この記事は実用的な目標を追求するものではありません。約15年前に、開発者がその時代の弱い電話向けに完全に機能するアプリケーションとゲームをどうやって作成したのか疑問に思いました。

- どちらかといえば、私はこのゲームとは何の関係もありません。
, floating-point , . "3" — fixed-point . , . , j2me Android.
, j2me — java (, 1.3), .jar PC. — . , - — API j2me .
.
, , , .
Nokia 5200, " " :
- 2006
- 128x160 1.8
- 262 . ( , 6 R, G, B ).
- - bluetooth .
- ( , 7 )
- microSd , , , 256 .
- - opera mini (, , )
- 640x480 .
- MIDP 2.0 (wiki)
- usb
- -
- , , — 100 , , floating-point . , - .
, — , 50-200 .
Write once, run everywhere
java . , . , platform- , .
, — . — . . , .jar j2me .class java. , Canvas, MIDlet javax.microedition.
, . Android : .class , .dex ( , .. dex 65 ), apk, ART.
, . , . , . , Vector synchronized. Vector , ArrayList ArrayList , .
— java . (int, boolean, ...) . Vector Object, .
, go , java 1.3. go - , java 2004 1.5 . 1.3.
j2me — .jar .class ( 1.3, 20 ), Gravity defied PC. "" java javax.microedition , . , : , java.awt.Image
javax.microedition.lcdui.Image
.
J2ME

javax.microedition
. , - , , - , , — . javax.microedition.lcdui.
MIDlet.
startApp()
.
— pauseApp()
startApp()
. destroyApp()
.
, notifyPaused()
notifyDestroyed()
— , .
, " " resumeRequest()
, notifyPaused()
, , .
, lifecycle .
, Runnable - :
Thread thread;
boolean isRunning;
boolean needToDestroy = false;
public void startApp() {
isRunning = true;
if (thread != null) {
thread = new Thread(this);
thread.start();
}
}
public void pauseApp() {
isRunning = false;
}
public void destroyApp(boolean unconditional) {
needToDestroy = true;
}
, .
void run(){
while(!needToDestroy) {
while (!isRunning) {
Thread.sleep(100);
}
}
notifyDestroyed();
}
, 100 — , . , pauseApp()
startApp()
Canvas
— Canvas. Canvas java.
repaint()
, , . UI- paint(Graphics g)
. , - , Canvas — . — repaint()
paint(...)
.
, :
hasPointerEvents(), hasPointerMotionEvents(), hasRepeatEvents()
, true. pointerDragged(int x, int y)
( ), pressed
( ) released
( ).
— , .
, — , . . , , . , 240360 . — — .
- , "" , . j2me - , , .., . , nokia 5800 , .
MIDlet Pascal
- , . java2me , , MIDlet pascal . j2me — , , java.
?
, , , Gravity Defied 64 .
-, .jar — zip , 122.1 kB
- META-INF MANIFEST.MF 3.8 kB, SHA-1 MD5 . .
- levels.mrg 5.1 kB 30 . 170 . .
- 11 . 10.8 kB.
- .class , 98.3 kB, 15 . — 127 , 24.3 kB. :
- , (4 ), 127 174 .
- — 470 .
- 9 — 1.6 6 kB.
- god-like :
. fernflower — , intelliJ IDEA. — , . .
IDEA — , .
: /gradlew jar
, build .jar
: mkdir decompiled && java -jar fernflower.jar -ren=1 GravityDefied_java decompiled
ren
, if
for
. , java . ren=1
field_42
method_135
— , .
2004 — , , :
- - , . .class .
else
, int
..- . "" Micro, .
- , fixed-point , . ,
(int)((long)a * b >> 16)
- , , .
— , . , , -. , .
- Netbeans, j2me SDK. , , ant. .
, Linux. gradle . — javax.microedition.*
. — PC- java. . , .
watch ./gradlew run
. ctrl+S
.
.
19 :
- 8 javax.microedition.rms.
- 10 .lcdui, , , Canvas ..).
- MIDlet — , .
, .
Micro, . - , startApp MIDlet .
:
protected void pauseApp() {
c = true;
if (!b) {
this.gameToMenu();
}
System.gc();
}
, c
isPaused
.
"" :
public void a() {
if (this.recordStore != null) {
try {
this.e.closeRecordStore();
return;
} catch (RecordStoreException var1) {
}
}
}
- closeMethodStore
.
, intelliJ IDEA - . — , , Image.loadImage(name)
:
this.p = Image.createImage("/splash.png");
, p splashImage.
- — , . , … Jetbrains — , — . , , .
- . — loadImage()… null . .
: , Image:
public class Image {
public final java.awt.Image image;
private Image(java.at.Image image) {
this.image = image;
}
public Graphics getGraphics() {
throw new RuntimeException();
}
public int getWidth() {
return image.getWidth(null);
}
public static Image createImage(int w, int h) {
return new Image(new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB));
}
...
}
, API , .
CanvasImpl, JPanel. Canvas.
, c :
public void paintComponent(Graphics g) {
if (upscale == 1) {
canvas.paint(new javax.microedition.lcdui.Graphics(g));
} else {
canvas.paint(new javax.microedition.lcdui.Graphics(screen.getGraphics()));
g.drawImage(screen, 0, 0, width * upscale, height * upscale, Color.WHITE, null);
}
}
javax.microedition.lcdui.Graphics(g)
— awt.Graphics, .
, . "" , .
, , , , — . PC. ? - 64 * 64
, , 1 * 1
, 240 * 320
. , , , , .
, . , , , , , .
, , j2me PC. — 2010 -, - . - - — .
!
, .
.jar . . , , . - Alert Canvas Displayable , Canvas. , .
gradle :
- emulator , , . , , .
- app-original, .jar
- app-from-sources - . .
, , . "" , , .
, .
Fixed-point physics
. , 16 — . , , -32768.0
32767.999984
c 1.0 / 65536
.
— .
int.
: int, , "". long. 64 32 . 16 16- int.
: . long, 16 . - , 32 — 16.
sin
, cos
atan2
.
— 64 — 0 90 . , — . . , .

, . Canvas.hasPointerEvents()
true
, , . — " ", " ", " " - "" . , , .
, — 170 . ? — .
, — / .., . . 0xff, int , , — dx , dy.
for (int i = 1; i < pointsCount; ++i) {
byte modeOrDx;
if ((modeOrDx = var1.readByte()) == -1) {
offsetY = 0;
offsetX = 0;
pointX = var1.readInt();
pointY = var1.readInt();
} else {
pointX = modeOrDx;
pointY = var1.readByte();
}
offsetX += pointX;
offsetY += pointY;
this.addPointSimple(offsetX, offsetY);
}
.
GPU full hd , (128*160
240*320
). 3 - , api . , — 90-180-270 .
, — .
, 32 16 . 48*48 1091 .
, , - API 3 3 - 3-. , - .
— 2 3.
. — 100 "23" "64".
if (time10MsToStringCache[time10MsPart] == null) {
String zeroPadding;
if (time10MsPart >= 10) {
zeroPadding = "";
} else {
zeroPadding = "0";
}
time10MsToStringCache[time10MsPart] = zeroPadding + time10Ms % 100L;
}
, , . , -.
No-MVP
MenuManager ( ) . - , — - , .
, - , . : Android:
- layout . .
- stings.txt.
- Activity, .
- LifecycleObserver, Adapter , Activity .
- Adapter DataSource.
- " ", Bundle DataSource .
- DataSouce SQLite .
: , ? , .
, TimerOrMotoPartOrMenuElem .
, , :
, , , — .
, , 64 . , - , "" .
, , , , . ", " — .
:
public void init() {
long timeToLoading = 3000L;
Thread.yield();
this.gameCanvas = new GameCanvas(this);
Display.getDisplay(this).setCurrent(this.gameCanvas);
this.gameCanvas.requestRepaint(1);
while (!this.gameCanvas.isShown()) {
this.goLoadingStep();
}
long deltaTimeMs;
while (timeToLoading > 0L) {
deltaTimeMs = this.goLoadingStep();
timeToLoading -= deltaTimeMs;
}
this.gameCanvas.requestRepaint(2);
for (timeToLoading = 3000L; timeToLoading > 0L; timeToLoading -= deltaTimeMs) {
deltaTimeMs = this.goLoadingStep();
}
while (gameLoadingStateStage < 10) {
this.goLoadingStep();
}
this.gameCanvas.requestRepaint(0);
this.isInited = true;
}
goLoadingStep()
. goLoadingStep()
. goLoadingStep
, .
goLoadingStep()
:
private long goLoadingStep() {
++gameLoadingStateStage;
this.gameCanvas.repaint();
long startTimeMillis = System.currentTimeMillis();
switch (gameLoadingStateStage) {
case 1:
this.levelLoader = new LevelLoader();
break;
case 2:
this.gamePhysics = new GamePhysics(this.levelLoader);
this.gameCanvas.init(this.gamePhysics);
break;
case 3:
this.menuManager = new MenuManager(this);
this.menuManager.initPart(1);
break;
....
case 9:
this.menuManager.initPart(7);
break;
case 10:
this.gameCanvas.setMenuManager(this.menuManager);
this.gameCanvas.setViewPosition(-50, 150);
this.setMode(1);
break;
default:
--gameLoadingStateStage;
try {
Thread.sleep(100L);
} catch (InterruptedException var3) {
}
}
return System.currentTimeMillis() - startTimeMillis;
}
MenuManager.initPart() switch case
.
, , . , .
2004 . Excitera Mobile Awards 2004 (EMA04) best-in-show. Codebrew Software :
- Tors Björn Henrik Johansson — system/game logic/interface, testing, levels design
- Set Elis Norman — graphics/physics/mathematics/system/tools programming, levels design
- Per David Jacobsson — physics programming, game graphics, levels design
さらに、私たちの同胞によって作られたアンドロイド用のこのゲームのポートがありますが、逆コンパイルされたコードを使用するだけです。
そのコードについて5年間不満はなかったので、元のアプリケーションを逆コンパイルして理解しようとしても害はないと思います。現在、このゲームは歴史的に興味深いものであり、小型スマートフォンの時代をより詳細に見ることができます。