Пост от 10.12.2025, 02:54:00
Отредактирован 30.01.2026, 22:34:02
Время чтения: 5мин.
Привет всем!
Думаю все достаточно старые здесь, или просто увлекающиеся ретро люди, знают какие телефоны использовались в 2000-е.
И в начале 9 класса(конец 2022 года), я разработал маленькое приложение на J2ME как раз для такого аппарата.

Затем я сделал его ремейк в 2024, потому что потерял оригинальный исходный код, но не смотря на невзгоды, мы всё равно пойдём последовательности.
Для разработки под устройство, первым делом нужны инструменты разработки, как бы это иронично не звучало. Полез в гугл я с вопросом Symbian SDK, и почти все инструменты не те, но это спойляр.
Большинство SDK на этих сайтах ведут на SDK для более продвинутых моделей, и используют C++. И всё это мимо, и да, я это всё тестировал и скачивал, и нет, я не сумасшедший.
И наконец, я понял что у меня модель 40 серии, а значит нужно скачать SDK на эту серию. Я наткнулся на эту ссылку с архивной версией Java благодаря ныне закрытому и удалённому из StackOverflow…

Далее, я начал изучать примеры, я взял для игры макет приложения для проверки 3d звука, а значит и скачал Apache Ant, потому что он используется для сборки, но его версия может любой, версия Java 6 нужна только работе утилит.

Приложение проверки 3d звука, потому что оно крайне простое, далее настроил всё под себя и сделал маленькую игрушку. Из наблюдений, эмулятор имеет срок использования без регистрации программы, далее требуя регистрации, что лично у меня под Wine не особо заработало. А утилита preverify написана такое чувство крайне кустарна, не понятно вообще что она делает.
Из своего кода, я актуализировал хоть как-то ant сборку, чтобы она брала переменные из окружения, что не имеет смысла пояснять здесь, это видно и в репозитории, просто поставил переменные на ранее забитые гвоздями значения.
<project name="MathThemRight" default="build">
<property environment="env"/>
<property name="build" value="build" /> <property name="classes" value="${build}/classes" /> <property name="src" value="src" /> <property name="rsrc" value="rsrc" /> <property name="midp_rsrc" value="${rsrc}/midp" /> <property name="bundle" value="${build}/bundle" /> <property name="preverified" value="${build}/preverified" /> <property name="bin" value="bin" /> <property name="midp_bin" value="${midp}/bin" /> <property name="targets" value="targets" /> <property name="javadoc" value="doc/javadoc" /> <property name="javadoc_rsrc" value="${rsrc}/javadoc" />
<property name="midp" value="." />
<property name="java_cmd" value="${env.JAVA_6_CMD}" /> <property name="sdk_location" value="${env.NOKIA_SERIES40_SDK}" />
<property name="preverify" value="${env.NOKIA_SERIES40_SDK_PREVERIFY}" />
<description> Math Them Right MIDlet java build project file </description>
<target name="clean"> <delete dir="${bin}" /> </target>
<target name="cleanSrc" description="deletes all class files from src folder"> <delete> <fileset dir="${src}" includes="**/*.class"/> </delete> </target>
<target name="build" description="clean, compile and build"> <antcall target="clean" /> <antcall target="compile" /> <antcall target="preverify" /> <antcall target="package" /> </target>
<target name="compile">
<mkdir dir="${classes}" /> <javac destDir="${classes}" srcDir="${src}" source="1.4" target="1.4" classpathref="project.class.path" includeAntRuntime="no" includeJavaRuntime="no" fork="yes" executable="${java_cmd}"> <bootclasspath> <fileset dir="${sdk_location}/lib"> <include name="**/*.jar"/> <include name="**/*.zip"/> </fileset> </bootclasspath>
</javac> <copy todir="${classes}"> <fileset dir="${src}" excludes="**/*.java"/> </copy> </target>
<path id="project.class.path"> <fileset dir="${sdk_location}/lib"> <include name="**/*.jar"/> <include name="**/*.zip"/> </fileset> </path>
<property name="myclasspath" refid="project.class.path"/>
<target name="preverify">
<mkdir dir="${preverified}"/> <exec executable="${preverify}" failonerror="true">
<arg line="-classpath ${myclasspath}"/> <arg line="-d ${preverified}"/> <arg line="${classes}"/> </exec> <copy todir="${preverified}" failonerror="false"> <fileset dir="${src}" excludes="**/*.java"/> </copy> </target>
<target name="package"> <mkdir dir="${bin}" /> <jar basedir="${preverified}" jarfile="${bin}/${ant.project.name}.jar" manifest="${midp_rsrc}/MANIFEST.MF" compress="true"> </jar>
<length file="${bin}/${ant.project.name}.jar" property="length.jarfile" /> <copy file="${midp_rsrc}/${ant.project.name}.jad" toDir="${bin}" /> <replace file="${bin}/${ant.project.name}.jad" token="@@@" value="${length.jarfile}"/>
</target>
</project>Затем сделал оставшуюся часть игры с музыкой по документации от Sun(да, не Oracle!), по MIDP.
package com.foxelyss.maththemright;
import java.io.InputStream;import java.util.Random;
import javax.microedition.lcdui.*;import javax.microedition.media.Manager;import javax.microedition.media.Player;import javax.microedition.midlet.MIDlet;import javax.microedition.midlet.MIDletStateChangeException;
public class Game extends MIDlet implements CommandListener {
private static final String START_FORM_TITLE = "Math Them Right";
private static final String START_MESSAGE = "Пожалуйста нажмите Далее";
private static final String CONTENT_TYPE = "audio/x-wav";
private static final String WIN_SOUND = "/com/foxelyss/maththemright/res/win.wav"; private static final String LOSE_SOUND = "/com/foxelyss/maththemright/res/lose.wav";
Display display;
ChoiceGroup answers;
Command startCommand = new Command("Далее", Command.OK, 1); Command exitCommand = new Command("Выход", Command.EXIT, 2);
Player win_player; Player lose_player;
InputStream win_sound_stream; InputStream lose_sound_stream;
Form startForm;
int win_strike = 0; int right_answer_index = -3;
public Game() { display = Display.getDisplay(this); }
public void startApp() throws MIDletStateChangeException { initAudio(); startForm = new Form(START_FORM_TITLE); startForm.append(START_MESSAGE); startForm.addCommand(startCommand); startForm.addCommand(exitCommand); startForm.setCommandListener(this);
answers = new ChoiceGroup("Ответы", Choice.EXCLUSIVE); startForm.append(answers); display.setCurrent(startForm); }
public void pauseApp() { }
public void destroyApp(boolean unconditional) { try { win_player.stop(); lose_player.stop(); win_player = null; lose_player = null; } catch (Exception e) { e.printStackTrace(); } }
void initAudio() { try { win_sound_stream = getClass().getResourceAsStream(WIN_SOUND); lose_sound_stream = getClass().getResourceAsStream(LOSE_SOUND);
win_player = Manager.createPlayer(win_sound_stream, CONTENT_TYPE);
win_player.realize(); win_player.prefetch();
lose_player = Manager.createPlayer(lose_sound_stream, CONTENT_TYPE);
lose_player.realize(); lose_player.prefetch();
} catch (Exception e) { e.printStackTrace(); } }
public void commandAction(Command c, Displayable d) { if (c == startCommand) { if (checkAnswer()) { win_strike++; try { win_player.start(); } catch (Exception e) { } } else { win_strike = 0; try { lose_player.start(); } catch (Exception e) { } }
generateExercise(); } else if (c == exitCommand) { destroyApp(true); notifyDestroyed(); } }
public boolean checkAnswer() { return right_answer_index == answers.getSelectedIndex(); }
public void generateExercise() { Random random = new Random();
int a = random.nextInt(200); int b = random.nextInt(200);
int operation = random.nextInt(4);
int right_result = a / b;
char operand = '/'; switch (operation) { case 0: operand = '+'; right_result = a + b; break; case 1: operand = '-'; right_result = a - b; break; case 2: operand = '*'; right_result = a * b; break; }
String question = a + " " + operand + " " + b + "\t="; ((StringItem) startForm.get(0)).setText(question + "\n" + "Серия побед:\t" + win_strike);
right_answer_index = random.nextInt(4);
answers.deleteAll(); for (int i = 0; i < 4; i++) { int offset = random.nextInt(24); String answer = "" + right_result; if (i != right_answer_index) { answer = (right_result + (offset < 12 ? -1 * (1 + offset) : offset)) + ""; }
answers.append(answer, null); } }
}Итоговая игра доступна в релизах. Вот и всё, как-то так!