This commit is contained in:
Donovan Preston 2014-08-04 14:19:00 -04:00
Родитель 9c4d4e1f9b 08567054bc
Коммит 1dbece6ca6
12 изменённых файлов: 2230 добавлений и 1 удалений

Просмотреть файл

@ -760,7 +760,7 @@ Native["com/sun/midp/rms/RecordStoreSharedDBHeader.getHeaderRefCount0.(I)I"] = f
MIDP.nativeEventQueue = [];
MIDP.copyEvent = function(obj) {
var e = MIDP.nativeEventQueue.pop();
var e = MIDP.nativeEventQueue.shift();
obj.class.getField("type", "I").set(obj, e.type);
obj.class.fields.forEach(function(field) {
field.set(obj, e[field.name]);

Просмотреть файл

@ -0,0 +1,337 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.lcdui.*;
import java.util.*;
/**
* Class to implement an asteroid. Asteroids come in three sizes.
* @author Jean-Francois Doue
* @version 1.2, 2001/10/24
*/
public class Asteroid extends Mobile {
/**
* A size constant for small asteroids.
*/
public static final byte SIZE_SMALL = 0;
/**
* A size constant for medium asteroids.
*/
public static final byte SIZE_MEDIUM = 1;
/**
* A size constant for large asteroids.
*/
public static final byte SIZE_LARGE = 2;
/**
* The x coordinates of the asteroid's vertices
*/
public static byte[][] xcoords;
/**
* The y coordinates of the asteroid's vertices
*/
public static byte[][] ycoords;
/**
* The radius of the asteroid.
*/
public static byte[] radii;
/**
* The diameter of the asteroid.
*/
public static int[] diameters;
/**
* Scan converted asteroids used for collision detection.
*/
public static boolean[][][] masks;
/**
* The asteroids currently existing in the game.
*/
public static Pool asteroids;
private byte _angle; // Orientation of the asteroid.
private byte _size; // Small, medium or large.
private static byte[] _value = {5, 2, 1}; // Points earned when shot.
private static final byte _FIELD_TOP = 0;
private static final byte _FIELD_BOTTOM = 1;
private static final byte _FIELD_LEFT = 2;
private static final byte _FIELD_RIGHT = 3;
static {
// Create and populate the asteroid pool.
Asteroid[] array = new Asteroid[20];
for (int i = array.length - 1; i >= 0; i--) {
array[i] = new Asteroid();
}
asteroids = new Pool(array);
final int[] allRadii = {3, 5, 8};
final byte[][] allAngles = {
{3, 11, 19, 25, 3}, // small
{2, 7, 17, 19, 26, 2}, // medium
{1, 4, 9, 15, 21, 23, 29, 1} // large
};
radii = new byte[3];
diameters = new int[3];
xcoords = new byte[3][];
ycoords = new byte[3][];
masks = new boolean[3][][];
for (int i = SIZE_SMALL; i <= SIZE_LARGE; i++) {
// Precompute the asteroid vertices.
radii[i] = (byte)(allRadii[i] * ratioNum / ratioDenom);
byte[] angles = allAngles[i];
byte[] pointx = new byte[angles.length];
xcoords[i] = pointx;
byte[] pointy = new byte[angles.length];
ycoords[i] = pointy;
for (int j = angles.length - 1; j >= 0; j--) {
pointx[j] = (byte)((radii[i] * Mobile.cos[angles[j]]) >> 6);
pointy[j] = (byte)((radii[i] * Mobile.sin[angles[j]]) >> 6);
}
// Scan convert the asteroid polygon.
diameters[i] = radii[i] << 1;
masks[i] = new boolean[diameters[i]][];
for (int j = 0; j < diameters[i]; j++) {
masks[i][j] = new boolean[diameters[i]];
}
Geometry.scanConvertPolygon(masks[i], pointx, pointy);
}
}
/**
* Initializes an Asteroid instance to make it large, positionned
* on a screen boundary and going in the direction of opposite boundary.
*/
public static void randomInit(Asteroid asteroid) {
int x = 0, y = 0;
byte angle = 0;
switch(Math.abs(Game.random.nextInt()) % 4) {
case _FIELD_TOP:
y = 1;
x = Math.abs(Game.random.nextInt()) % width;
angle = (byte)(15 + Math.abs(Game.random.nextInt()) % 15);
break;
case _FIELD_LEFT:
x = 1;
y = Math.abs(Game.random.nextInt()) % height;
angle = (byte)((23 + Math.abs(Game.random.nextInt()) % 15) % 32);
break;
case _FIELD_RIGHT:
x = width - 1;
y = Math.abs(Game.random.nextInt()) % height;
angle = (byte)(7 + Math.abs(Game.random.nextInt()) % 15);
break;
case _FIELD_BOTTOM:
y = height - 1;
x = Math.abs(Game.random.nextInt()) % width;
angle = (byte)(Math.abs(Game.random.nextInt()) % 15);
break;
}
asteroid.init(x, y, angle, SIZE_LARGE);
}
/**
* Initializes a Asteroid instance by setting its position, angle
* and size.
*/
public final void init(int x, int y, byte angle, byte size) {
_angle = angle;
_size = size;
moveTo(x, y);
setVelocity(cos[angle] << 2, sin[angle] << 2);
}
public Asteroid() {
}
/**
* Move the asteroid to its next position.
*/
public static final void move() {
for (int i = 0; i < asteroids.count; i++) {
Asteroid a = (Asteroid)asteroids.pool[i];
a._x += a.vx;
a._y += a.vy;
a.x = a._x >> 8;
a.y = a._y >> 8;
// If a border has been hit, wrap the trajectory around
// the screen. The new origin is the projection of the
// intersection point on the opposite border.
if (a.x <= 0) {
a.moveTo(width - 2, a.y);
} else if (a.x >= width - 1) {
a.moveTo(1, a.y);
} else if (a.y <= 0) {
a.moveTo(a.x, height - 2);
} else if (a.y >= height - 1) {
a.moveTo(a.x, 1);
}
}
}
/**
* Compute collisions between the asteroids and
* the ship and the rockets.
*/
public static final void collisionDetection() {
Ship ship = Ship.ship;
Field field = Game.field;
// Collision detection makes sense only while the game is
// being played and the ship is alive.
if ((field != null) && (field.getState() == Field.GAME_STATE) && (ship.isAlive)) {
int score = field.getScore();
int newScore = score;
Pool rockets = Rocket.rockets;
Pool explosions = Explosion.explosions;
for (asteroids.current = asteroids.count - 1; asteroids.current >= 0;) {
Asteroid a = (Asteroid)asteroids.pool[asteroids.current--];
// Detect ship - asteroid collisions.
int offset = ship.angle << 2;
for (int i = 0; i < 4; i++) {
int sx = ship.x + Ship.xcoords[offset + i] - a.x + radii[a._size];
if ((sx >= 0) && (sx < diameters[a._size])) {
int sy = ship.y + Ship.ycoords[offset + i] - a.y + radii[a._size];
if ((sy >= 0) && (sy < diameters[a._size])) {
// Use the mask for collision detection
if (masks[a._size][sx][sy]) {
int lives = field.getLives();
if ((lives > 0) && (ship.isAlive)) {
ship.explode();
field.setLives(lives - 1);
}
}
}
}
}
// Detect asteroid - rocket collisions.
for (rockets.current = rockets.count - 1; rockets.current >= 0;) {
Rocket r = (Rocket)rockets.pool[rockets.current--];
// Transform the r into asteroid coordinates.
int rx = r.x - a.x + radii[a._size];
if ((rx >= 0) && (rx < diameters[a._size])) {
int ry = r.y - a.y + radii[a._size];
if ((ry >= 0) && (ry < diameters[a._size])) {
// Use the mask for collision detection
if (masks[a._size][rx][ry]) {
asteroids.removeCurrent();
rockets.removeCurrent();
newScore += _value[a._size];
a.split(r);
Explosion explosion = (Explosion)explosions.addNewObject();
if (explosion != null) {
explosion.init(r.x, r.y);
}
break;
}
}
}
}
}
if (newScore != score) {
field.setScore(newScore);
}
}
}
/**
* Draws an asteroid of the specified size and location
* in the specified graphic context.
*/
public static final void draw(byte size, int xpos, int ypos, Graphics g) {
byte[] xcoord = xcoords[size];
byte[] ycoord = ycoords[size];
for (int i = 0; i < xcoord.length - 1; i++) {
g.drawLine(xcoord[i] + xpos, ycoord[i] + ypos, xcoord[i + 1] + xpos, ycoord[i + 1] + ypos);
}
}
/**
* Draws all the asteroids of the supplied object pool using the
* specified graphic context.
*/
static public final void draw(Graphics g) {
for (int i = 0; i < asteroids.count; i++) {
Asteroid a = (Asteroid)asteroids.pool[i];
byte[] xcoord = xcoords[a._size];
byte[] ycoord = ycoords[a._size];
for (int j = 0; j < xcoord.length - 1; j++) {
g.drawLine(
xcoord[j] + a.x,
ycoord[j] + a.y,
xcoord[j + 1] + a.x,
ycoord[j + 1] + a.y);
}
}
}
/**
* Splits the asteroid in two smaller pieces and set their
* direction depending on the asteroid direction and the hitting
* rocket direction. The pieces are added to the supplied collection.
*/
public final void split(Rocket rocket) {
if (_size >= SIZE_MEDIUM) {
byte newSize = (byte)(_size - 1);
int angle = (cos[_angle] * sin[rocket.angle] - cos[rocket.angle] * sin[_angle]) >> 10;
byte angle1 = (byte)(_angle + angle + Math.abs(Game.random.nextInt()) % 5);
if (angle1 < 0) {
angle1 += 32;
}
if (angle1 >= 32) {
angle1 -= 32;
}
byte angle2 = (byte)(_angle + angle - Math.abs(Game.random.nextInt()) % 5);
if (angle2 < 0) {
angle2 += 32;
}
if (angle2 >= 32) {
angle2 -= 32;
}
Asteroid a = (Asteroid)asteroids.addNewObject();
if (a != null) {
a.init(x, y, angle1, newSize);
}
a = (Asteroid)asteroids.addNewObject();
if (a != null) {
a.init(x, y, angle2, newSize);
}
}
}
}

Просмотреть файл

@ -0,0 +1,101 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.lcdui.*;
import java.util.*;
/**
* Class to represent an explosion.
* @author Jean-Francois Doue
* @version 1.0, 2001/07/26
*/
public class Explosion extends Object {
public static byte[] xcoords;
public static byte[] ycoords;
private int _frame, _x, _y;
private static final int MAX_FRAME = 6;
public static Pool explosions;
static {
// Create and populate the explosion pool.
Explosion[] array = new Explosion[10];
for (int i = array.length - 1; i >= 0; i--) {
array[i] = new Explosion();
}
explosions = new Pool(array);
// Pre-compute the explosion images
int[] Xcoords = new int[8];
int[] Ycoords = new int[8];
for (int i = 0; i < 8; i++) {
Xcoords[i] = Mobile.cos[i << 2] * (Math.abs(Game.random.nextInt()) % 12);
Ycoords[i] = Mobile.sin[i << 2] * (Math.abs(Game.random.nextInt()) % 12);
}
xcoords = new byte[48];
ycoords = new byte[48];
for (int i = 0; i < Explosion.MAX_FRAME; i++) {
int offset = i << 3;
for (int j = 0; j < 8; j++) {
xcoords[offset + j] = (byte)(Xcoords[j] >> 8);
ycoords[offset + j] = (byte)(Ycoords[j] >> 8);
Xcoords[j] += Mobile.cos[j << 2] << 2;
Ycoords[j] += Mobile.sin[j << 2] << 2;
}
}
}
public Explosion() {
}
public final void init(int x, int y) {
_x = x;
_y = y;
_frame = 0;
}
/**
* Animate the explosion and remove those which are done.
*/
public static final void explode() {
for (explosions.current = explosions.count - 1; explosions.current >= 0;) {
Explosion e = (Explosion)explosions.pool[explosions.current--];
e._frame++;
if (e._frame >= Explosion.MAX_FRAME) {
explosions.removeCurrent();
}
}
}
/**
* Draw all the explosions using the supplied context.
*/
public static final void draw(Graphics g) {
for (int i = 0; i < explosions.count; i++) {
Explosion e = (Explosion)explosions.pool[i];
int offset = e._frame << 3;
for (int j = 0; j < 8; j++) {
g.drawLine(
e._x + xcoords[j + offset],
e._y + ycoords[j + offset],
e._x + xcoords[j + offset],
e._y + ycoords[j + offset]);
}
}
}
}

469
tests/asteroids/Field.java Normal file
Просмотреть файл

@ -0,0 +1,469 @@
/**
* Copyright 2001-2002 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;
/**
* The game main screen. The class also implements the game's main loop.
* @author Jean-Francois Doue
* @author Pavel Machek
* @version 1.4, 2002/10/14
*/
public class Field extends Canvas implements Runnable {
/**
* The 'title' game state. Displays the game name and author.
*/
public static final byte TITLE_STATE = 0;
/**
* The 'control' game state. Displays the mapping between keys and game commands.
*/
public static final byte CONTROL_STATE = 1;
/**
* The 'points' game state. Displays the value of each screen items.
*/
public static final byte POINTS_STATE = 2;
/**
* The 'high score' game state. Displays the high score table.
*/
public static final byte HISCORE_STATE = 3;
/**
* The 'game over' game state. Displays the 'game over' message.
*/
public static final byte GAMEOVER_STATE = 4;
/**
* The 'new high score' game state. Lets players enter their name.
*/
public static final byte NEWHIGHSCORE_STATE = 5;
/**
* The 'game' game state. The player is actively playing the game.
*/
public static final byte GAME_STATE = 6;
/**
* When not in game mode, the game switches its state every TIMEOUT ms
*/
public static final long TIMEOUT = 8000L;
public static Font smallFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL);
public static Font bigFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
/**
* Time spent moving objects and computing collisions.
*/
//public static long computeavg;
/**
* Time spent painting screens.
*/
//public static long paintavg;
/**
* Number of game frames since beginning.
*/
//public static long frames;
private byte _state; // The current game state
private Slideshow _nextSlide; // A TimeTask used to trigger the transition to the next state.
private int _lives; // Number of lives left.
private int _nextBonusLife; // Score above which next extra life will be awarded.
private int _score; // Current score.
private byte _level; // Current level.
private boolean _paused; // Set the true by the Game if it wants to enter its paused state
// This causes the main game thread to exit.
private boolean _frozen; // Set when another Displayable is being displayed by the game
// (nothing happens in the game in between, but the game
// must be able to resume).
private Image _buffer; // To implement double-buffering on platforms which do not have it.
private char[] _scoreString;
private char _liveString;
private char[] _levelString // The current level indicator
= {'L', 'e', 'v', 'e', 'l', ' ', '0'};
private byte _levelStringTimer; // The number of frames during which the level indicator is displayed
private int _liveStringWidth; // In pixels.
private int _lastKeyPressed; // The last key pressed by the player.
private boolean _isRepeatedKey; // True if _lastKeyPressed was obtained through keyRepeated().
public Field() {
//computeavg = 0;
//paintavg = 0;
//frames = 0;
// Determine the dimensions of the Canvas.
// The game has been developed using the j2mewtk's
// DefaultColorPhone, using a resolution of 100x96.
// Object are sized proportionaly on other platforms
// ratioDenom.
Mobile.width = getWidth();
Mobile.height = getHeight();
Mobile.ratioNum = Math.min(Mobile.width, Mobile.height);
// The score is stored as a char array for greater
// efficiency.
_scoreString = new char[4];
// For device which do not support double buffering,
// create an offscreen image for double buffering.
if (!isDoubleBuffered()) {
_buffer = Image.createImage(Mobile.width, Mobile.height);
}
}
/**
* Starts a new game.
*/
public final void newGame() {
_level = 0;
setLives(4);
_nextBonusLife = 500;
setScore(0);
Asteroid.asteroids.removeAll();
_lastKeyPressed = 0;
_isRepeatedKey = false;
Ship.ship.reset();
}
/**
* Returns the number of remaining ships
*/
public final int getLives() {
return _lives;
}
/**
* Sets the number of remaining ships
*/
public final void setLives(int lives) {
if (lives < 0) {
lives = 0;
}
_lives = lives;
_liveString = (char)('0' + _lives);
_liveStringWidth = smallFont.charWidth(_liveString);
}
/**
* Returns the current score.
*/
public final int getScore() {
return _score;
}
/**
* Updates the score.
*/
public final void setScore(int score) {
_score = score;
// Convert the score to an array of chars
// of the form: 0000
Scores.toCharArray(_score, _scoreString);
// Extra lives are awarded every 500 points.
if (_score >= _nextBonusLife) {
_nextBonusLife += 500;
setLives(_lives + 1);
}
}
/**
* Initializes a new level.
*/
private final void _nextLevel() {
// At most 7 large asteroids per screen.
if (_level < 5) {
_level++;
}
// Populate the game level with large asteroids.
for (byte i = 0; i < 3 + _level; i++) {
Asteroid asteroid = (Asteroid)Asteroid.asteroids.addNewObject();
if (asteroid != null) {
Asteroid.randomInit(asteroid);
}
}
// Clear all the existing rockets or explosions and reset
// the ship.
Rocket.rockets.removeAll();
Explosion.explosions.removeAll();
if (_level >= 1) {
_levelString[6] = (char)('0' + _level);
_levelStringTimer = 20;
}
}
/**
* Overriden from Canvas.
*/
protected void paint(Graphics g) {
Graphics gr = (_buffer != null) ? _buffer.getGraphics() : g;
gr.setColor(0x00FFFFFF);;
gr.fillRect(0, 0, getWidth() - 1, getHeight() - 1);
gr.setColor(0x00000000);
gr.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
// Draw the asteroids
gr.setColor(0x000000FF);
Asteroid.draw(gr);
// Draw the explosions
gr.setColor(0x00FF00FF);
Explosion.draw(gr);
// Draw the rockets
gr.setColor(0x00FF0000);
Rocket.draw(gr);
switch(_state) {
case TITLE_STATE:
Slideshow.drawTitleScreen(gr);
break;
case CONTROL_STATE:
Slideshow.drawControlScreen(gr);
break;
case POINTS_STATE:
Slideshow.drawPointsScreen(gr);
break;
case HISCORE_STATE:
Slideshow.drawHighScoresScreen(gr);
break;
case GAME_STATE:
gr.setColor(0x00000000);
//gr.drawRect(10, 10, 16, 16);
gr.setFont(smallFont);
gr.drawChars(_scoreString, 0, 4, 2, getHeight() - 1, Graphics.BOTTOM|Graphics.LEFT);
gr.drawChar(_liveString, Mobile.width - _liveStringWidth - 1, Mobile.height, Graphics.BOTTOM|Graphics.LEFT);
Ship.draw(0, Mobile.width - Ship.radius - 2 - _liveStringWidth, Mobile.height - Ship.radius - 1, gr);
// Display the level indicator (only during the first few frames of the level)
if (_levelStringTimer > 0) {
_levelStringTimer--;
int x = (Mobile.width - Field.smallFont.charsWidth(_levelString, 0, _levelString.length)) >> 1;
int y = ((Mobile.height) >> 1) + Field.smallFont.getHeight();
gr.drawChars(_levelString, 0, _levelString.length, x, y, Graphics.BOTTOM|Graphics.LEFT);
}
Ship.ship.draw(gr);
break;
case GAMEOVER_STATE:
Slideshow.drawGameOverScreen(gr);
break;
}
if (_buffer != null) {
g.drawImage(_buffer, 0, 0, Graphics.TOP|Graphics.LEFT);
}
}
/**
* Overriden from Canvas.
*/
protected void keyPressed(int keyCode) {
_lastKeyPressed = keyCode;
}
protected void keyRepeated(int keyCode) {
_lastKeyPressed = keyCode;
_isRepeatedKey = true;
}
/**
* Returns the current state.
*/
public final byte getState() {
return _state;
}
/**
* Triggers a transition from one state of the game automaton
* to the other.
*/
public final void setState(byte newState) {
switch (newState) {
case TITLE_STATE:
_nextSlide = new Slideshow(CONTROL_STATE);
Game.timer.schedule(_nextSlide, TIMEOUT);
break;
case CONTROL_STATE:
_nextSlide = new Slideshow(POINTS_STATE);
Game.timer.schedule(_nextSlide, TIMEOUT);
break;
case POINTS_STATE:
_nextSlide = new Slideshow(HISCORE_STATE);
Game.timer.schedule(_nextSlide, TIMEOUT);
break;
case HISCORE_STATE:
_nextSlide = new Slideshow(TITLE_STATE);
Game.timer.schedule(_nextSlide, TIMEOUT);
break;
case GAMEOVER_STATE:
if (Game.scores.isHighScore(_score)) {
_nextSlide = new Slideshow(NEWHIGHSCORE_STATE);
Game.timer.schedule(_nextSlide, TIMEOUT / 2);
} else {
_nextSlide = new Slideshow(HISCORE_STATE);
Game.timer.schedule(_nextSlide, TIMEOUT);
}
break;
case NEWHIGHSCORE_STATE:
setFrozen(true);
if (Game.display.getCurrent() != Game.scoreForm) {
Game.enterHighScore();
}
break;
case GAME_STATE:
if (_nextSlide != null) {
_nextSlide.cancel();
_nextSlide = null;
}
break;
}
_state = newState;
}
/**
* Asks the game's main thread to exit.
*/
public final void pause() {
_paused = true;
}
/**
*
*/
public final void setFrozen(boolean frozen) {
_frozen = frozen;
if (_frozen) {
if (_nextSlide != null) {
_nextSlide.cancel();
_nextSlide = null;
}
}
}
/**
* Executes the game's main loop.
*/
public void run() {
try {
while (!_paused) {
long time1 = System.currentTimeMillis();
//long time2;
long time3;
long ellapsed = 0;
if (!_frozen) {
// If the field has been cleared, change the level.
if (Asteroid.asteroids.size() == 0) {
_nextLevel();
}
// Animate the explosion and remove those which are done.
Explosion.explode();
// Move the asteroids.
Asteroid.move();
// Move the rockets and remove those which have expired.
Rocket.move();
// Handle user events
// Move the ship (only while the game is actually proceeding)
if (_state == GAME_STATE) {
if (_lastKeyPressed != 0) {
int gameAction = getGameAction(_lastKeyPressed);
if (gameAction != 0) {
switch(gameAction) {
case LEFT:
Ship.ship.rotate(-2);
break;
case RIGHT:
Ship.ship.rotate(2);
break;
case FIRE:
Ship.ship.shoot(Rocket.rockets);
break;
case GAME_A:
case UP:
Ship.ship.burn();
break;
case GAME_B:
if (!_isRepeatedKey) {
Ship.ship.teleport();
}
break;
}
}
_lastKeyPressed = 0;
_isRepeatedKey = false;
}
Ship.ship.move();
}
// Compute collisions between the asteroids and
// the ship and the rockets.
Asteroid.collisionDetection();
// Detect game over
if ((_state == GAME_STATE) && (_lives <= 0) && (Ship.ship.isAlive)) {
setState(GAMEOVER_STATE);
}
// Determine the time spent to compute the frame.
//time2 = System.currentTimeMillis();
//computeavg += (time2 - time1);
// Force a screen refresh.
repaint();
serviceRepaints();
// Determine the time spent to draw the frame.
time3 = System.currentTimeMillis();
//paintavg += (time3 - time2);
//frames++;
// Determine the total time for the frame.
ellapsed = time3 - time1;
}
// Sleep for a while (at least 20ms)
try {
Thread.currentThread().sleep(Math.max(50 - ellapsed, 20));
} catch(java.lang.InterruptedException e) {
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

224
tests/asteroids/Game.java Normal file
Просмотреть файл

@ -0,0 +1,224 @@
/**
* Copyright 2001-2002 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;
/**
* The MIDlet's main class. Handles the game lifecycle and owns
* the various game screens and commands.
* @author Jean-Francois Doue
* @version 1.4, 2002/10/14
*/
public class Game extends MIDlet implements CommandListener {
/**
* The random number generator used throughout the
* game
*/
public static Random random = new Random();
/**
* A timer used to schedule the transitions between
* the various game screens.
*/
public static Timer timer;
/**
* The game's main screen, where all the drawing occurs.
*/
public static Field field;
/**
* A form used to get the player's initials for high scores.
*/
public static Form scoreForm;
/**
* A form used to display license info.
*/
public static Form licenseForm;
/**
* The high score database.
*/
public static Scores scores;
/**
* The MIDlet display.
*/
public static Display display;
private static Command _exitCommand;
private static Command _startCommand;
private static Command _licenseCommand;
private static Command _scoreOkCommand;
private static Command _licenseOkCommand;
private static TextField _scoreField;
private static Displayable _currentDisplayable;
/**
* Constructor invoked by the application management software.
* Do not obfuscate.
*/
public Game() {
// Retrieve the display.
display = Display.getDisplay(this);
// Create a form which will be used to display
// licensing info.
licenseForm = new Form("License");
licenseForm.append("This game is free software licensed under the GNU General Public License. For details, see http://jfdoue.free.fr");
_licenseOkCommand = new Command("Ok", Command.SCREEN, 1);
licenseForm.addCommand(_licenseOkCommand);
licenseForm.setCommandListener(this);
// Instantiate the main game canvas.
// Add two commands to the canvas, one to start the game
// and one to exit the MIDlet
field = new Field();
_exitCommand = new Command("Exit", Command.EXIT, 1);
_startCommand = new Command("Start", Command.SCREEN, 1);
_licenseCommand = new Command("License", Command.SCREEN, 3);
field.addCommand(_exitCommand);
field.addCommand(_startCommand);
field.addCommand(_licenseCommand);
field.setCommandListener(this);
_currentDisplayable = field;
// Create a form which will be used to enter the
// user name for high scores.
scoreForm = new Form("Congratulations");
_scoreField = new TextField("Your score is one of the 3 best. Enter your initials", "", 3, TextField.ANY);
scoreForm.append(_scoreField);
_scoreOkCommand = new Command("Done", Command.SCREEN, 1);
scoreForm.addCommand(_scoreOkCommand);
scoreForm.setCommandListener(this);
// Read the high scores from persistent storage.
scores = new Scores();
// Initialize the random number generator.
random = new Random();
}
/**
* Method used to switch screens.
*/
public static void setDisplayable(Displayable displayable) {
_currentDisplayable = displayable;
display.setCurrent(displayable);
}
/**
* Invoked by Field to ask the game to switch to
* the high score form.
*/
public static void enterHighScore() {
_scoreField.setString("");
setDisplayable(scoreForm);
}
// Methods overwritten from MIDlet. These methods are
// invoked by the application management software
// to ask to MIDlet to enter the desired state.
/**
* Overriden from MIDlet.
*/
protected void startApp() {
//System.out.println("startApp");
// The game has two application threads
// + One timer thread to trigger a switch between
// the different game screens while not in game mode.
// + A thread to run the main game loop.
timer = new Timer();
setDisplayable(_currentDisplayable);
Thread thread = new Thread(field);
thread.start();
field.setState(field.getState());
}
/**
* Overriden from MIDlet.
*/
protected void pauseApp() {
//System.out.println("pauseApp");
// Kill the two game threads.
field.pause();
if (timer != null) {
timer.cancel();
timer = null;
}
}
/**
* Overriden from MIDlet.
*/
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
field.pause();
timer.cancel();
timer = null;
random = null;
field = null;
scores = null;
display = null;
_exitCommand = null;
_startCommand = null;
_scoreOkCommand = null;
scoreForm = null;
licenseForm = null;
_scoreField = null;
_currentDisplayable = null;
//System.out.println("computeavg = " + (Field.computeavg / Field.frames));
//System.out.println("paintavg = " + (Field.paintavg / Field.frames));
}
// Implementation of the CommandListener interface
/**
* CommandListener interface implementation.
*/
public void commandAction(Command c, Displayable d) {
if (c == _exitCommand) {
try {
destroyApp(false);
} catch(MIDletStateChangeException e) {
}
notifyDestroyed();
} else if (c == _startCommand) {
field.setState(Field.GAME_STATE);
field.newGame();
} else if (c == _scoreOkCommand) {
scores.addHighScore(field.getScore(), _scoreField.getString());
field.setState(Field.HISCORE_STATE);
setDisplayable(field);
field.setFrozen(false);
} else if (c == _licenseCommand) {
field.setFrozen(true);
setDisplayable(licenseForm);
} else if (c == _licenseOkCommand) {
setDisplayable(field);
field.setState(field.getState());
field.setFrozen(false);
}
}
}

Просмотреть файл

@ -0,0 +1,190 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
/**
* Class to group various geometric functions.
* @author Jean-Francois Doue
* @version 1.4, 2002/10/14
*/
public class Geometry extends Object {
/**
* Scan converts a polygon.
* @param pixels
* The resulting scan-converted polygon as a 2D boolean array
* @param xcoords
* The X-coordinates of the polygon vertices. The vertex are ordered clockwise,
* and the last vertex equals the first vertex.
* @param ycoords
* The Y-coordinates of the polygon vertices. The vertex are ordered clockwise,
* and the last vertex equals the first vertex.
*/
public static void scanConvertPolygon(boolean[][] pixels, byte[] xcoords, byte[] ycoords) {
// Degenerate cases
if (pixels.length == 0) {
return;
}
if (pixels.length == 1) {
pixels[0][0] = true;
return;
}
// Index of the polygon segment being scan converted.
int top = 0, bottom = xcoords.length - 1;
// Parameters used to adapt the Bresenham algorithm.
// to the 8 possible octants. (top and bottom lines)
boolean isSteepT = false, isSteepB = false;
int incrYT = 0, incrYB = 0;
// Decision variable of the Bresenham algorithm.
// If d <= 0, then the next point ought to be E
// If d > 0, then the next point ought to be NE
int dT = 0, dB = 0;
// Incremental d of the Bresenham algorithm when E is chosen.
int incrET = 0, incrEB = 0;
// Incremental d of the Bresenham algorithm when NE is chosen.
int incrNET = 0, incrNEB = 0;
// The x coordinate of the current line point.
int x = xcoords[top];
// The y coordinate of the current line point (top and bottom lines).
int yT = 0, yB = 0;
// Translation
int tx = pixels.length >> 1;
// Scan convert the top and bottom border of the polygon.
// The scan conversion is done once the lines cross.
while (top <= bottom) {
// Another segment of the top border has been reached.
if (x == xcoords[top]) {
while (xcoords[top + 1] == xcoords[top] && top < xcoords.length) {
top++;
}
int dxT = xcoords[top + 1] - xcoords[top];
int dyT = ycoords[top + 1] - ycoords[top];
yT = ycoords[top];
top++;
incrYT = (dyT >= 0) ? 1 : -1;
int absDxT = Math.abs(dxT);
int absDyT = Math.abs(dyT);
isSteepT = (absDxT <= absDyT);
if (isSteepT) {
dT = (absDxT << 1) - absDyT;
incrET = absDxT << 1;
incrNET = (absDxT - absDyT ) << 1;
} else {
dT = (absDyT << 1) - absDxT;
incrET = absDyT << 1;
incrNET = (absDyT - absDxT ) << 1;
}
} else {
// Compute the Y coordinate of the next top border point.
if (isSteepT) {
if (dT <= 0) {
while (dT <= 0) {
yT += incrYT;
dT += incrET;
}
}
yT += incrYT;
dT += incrNET;
} else {
if (dT <= 0) {
dT += incrET;
} else {
yT += incrYT;
dT += incrNET;
}
}
}
// Another segment of the bottom border has been reached.
if (x == xcoords[bottom]) {
while (xcoords[bottom - 1] == xcoords[bottom] && bottom >= 0) {
bottom--;
}
int dxB = xcoords[bottom - 1] - xcoords[bottom];
int dyB = ycoords[bottom - 1] - ycoords[bottom];
yB = ycoords[bottom];
bottom--;
incrYB = (dyB >= 0) ? 1 : -1;
int absDxB = Math.abs(dxB);
int absDyB = Math.abs(dyB);
isSteepB = (absDxB <= absDyB);
if (isSteepB) {
dB = (absDxB << 1) - absDyB;
incrEB = absDxB << 1;
incrNEB = (absDxB - absDyB ) << 1;
} else {
dB = (absDyB << 1) - absDxB;
incrEB = absDyB << 1;
incrNEB = (absDyB - absDxB ) << 1;
}
} else {
// Compute the Y coordinate of the next bottom border point.
if (isSteepB) {
if (dB <= 0) {
while (dB <= 0) {
yB += incrYB;
dB += incrEB;
}
}
yB += incrYB;
dB += incrNEB;
} else {
if (dB <= 0) {
dB += incrEB;
} else {
yB += incrYB;
dB += incrNEB;
}
}
}
// Fill the line between the top and the bottom border points.
int min = (yB <= yT) ? yB : yT;
int max = (yB > yT) ? yB : yT;
for (int i = min; i <= max; i++) {
pixels[pixels.length - 1 - i - tx][x + tx] = true;
}
x--;
}
/*
for (int i = 0; i < pixels.length; i++) {
for (int j = pixels[i].length - 1; j >= 0; j--) {
if (pixels[i][j]) {
System.out.print("#");
} else {
System.out.print(".");
}
}
System.out.println();
}
*/
}
}

108
tests/asteroids/Mobile.java Normal file
Просмотреть файл

@ -0,0 +1,108 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
/**
* The base class for all moving objects on screen.
* Provides pseudo-floating point capabilities.
* @author Jean-Francois Doue
* @version 1.3, 2001/10/26
*/
public abstract class Mobile extends Object {
/**
* A cosine table.
*/
public static final int[] cos = { 64,
62, 59, 53, 45, 35, 24, 12, 0, -12,
-24, -35, -45, -53, -59, -62, -64,
-62, -59, -53, -45, -35, -24, -12,
0, 12, 24, 35, 45, 53, 59, 62 };
/**
* A sine table.
*/
public static final int[] sin = { 0,
12, 24, 35, 45, 53, 59, 62, 64, 62,
59, 53, 45, 35, 24, 12, 0, -12,
-24, -35, -45, -53, -59, -62, -64,
-62, -59, -53, -45, -35, -24, -12
};
/**
* Graphics are scaled to keep the same
* aspect as on the original development platform.
*/
public static int ratioNum;
/**
* The screen width of the original development platform.
*/
public static final int ratioDenom = 96;
/**
* Screen width
*/
public static int width;
/**
* Screen height
*/
public static int height;
/**
* The screen coordinates (in pixels) of the mobile.
*/
public int x, y;
/**
* The velocity of the mobile (in pseudo floating point units.)
*/
public int vx, vy;
/**
* The screen coordinates (in pseudo floating point units) of the mobile.
*/
protected int _x, _y;
/**
* The previous screen coordinates (in pixels) of the mobile.
*/
public int xold, yold;
public Mobile() {
}
/**
* Move the mobile to a specific screen location.
*/
public void moveTo(int x, int y) {
this.x = x;
this.y = y;
this._x = x << 8;
this._y = y << 8;
this.xold = x;
this.yold = y;
}
/**
* Alters the velocity of the mobile.
*/
public void setVelocity(int vx, int vy) {
this.vx = vx;
this.vy = vy;
}
}

105
tests/asteroids/Pool.java Normal file
Просмотреть файл

@ -0,0 +1,105 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
/**
* Class to implement efficient, pool based collections.
* The class supports an iterator method for collection traversal,
* and methods to add and remove elements. The collection size
* cannot grow beyond the size of the initial pool of objects
* provided for the collection.
* @author Jean-Francois Doue
* @version 1.1, 2001/10/02
*/
public class Pool extends Object {
/**
* An object array the pool where objects are actually stored.
*/
public Object[] pool;
/**
* The number of objects currently in the pool.
*/
public int count;
/**
* The index of the current object.
*/
public int current;
/**
* Initializes the collection with a pool of instances.
*/
public Pool(Object[] pool) {
this.pool = pool;
}
/**
* Resets the collection iterator.
*/
public final void reset() {
current = count - 1;
}
/**
* Returns the next object in the collection.
*/
public final Object next() {
if (current >= 0) {
return pool[current--];
}
return null;
}
/**
* Removes the current object from the collection.
*/
public final void removeCurrent() {
if (current + 1 < count - 1) {
Object tmp = pool[current + 1];
pool[current + 1] = pool[count - 1];
pool[count - 1] = tmp;
}
count--;
}
/**
* Adds a new object to the collection. The
* returned object must be initialized by the callee.
* Returns null if the collection capacity has been
* exceeded.
*/
public final Object addNewObject() {
if (count >= pool.length) {
return null;
}
return pool[count++];
}
/**
* Removes all the objects from the collection.
*/
public final void removeAll() {
count = 0;
}
/**
* Returns the size of the collection.
*/
public final int size() {
return count;
}
}

120
tests/asteroids/Rocket.java Normal file
Просмотреть файл

@ -0,0 +1,120 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.lcdui.*;
/**
* Class to implement a rocket shot by the player's spaceship.
* @author Jean-Francois Doue
* @version 1.4, 2002/10/14
*/
public class Rocket extends Mobile {
/**
* The orientation of the rocket.
*/
public byte angle;
/**
* The rockets currently existing in the game
*/
public static Pool rockets;
private int _rangex, _rangey; // The distance travelled by the rocket.
static {
// Create and populate the rocket pool.
Rocket[] array = new Rocket[10];
for (int i = array.length - 1; i >= 0; i--) {
array[i] = new Rocket();
}
rockets = new Pool(array);
}
public Rocket() {
}
/**
* Initializes a Rocket instance by setting its position
* and angle.
*/
public final void init(int x, int y, byte angle, int vx, int vy) {
moveTo(x, y);
setVelocity((cos[angle] << 4) + vx, (sin[angle] << 4) + vy);
this.angle = angle;
_rangex = 0;
_rangey = 0;
}
/**
* Move the rockets and remove those which have expired.
*/
public static final void move() {
for (rockets.current = rockets.count - 1; rockets.current >= 0;) {
Rocket r = (Rocket)rockets.pool[rockets.current--];
int rangex = r._rangex >> 8;
int rangey = r._rangey >> 8;
int maxRange = (((width <= height) ? width : height) * 8) / 10;
// Determines if the rocket has travelled its maximum distance
// (80% of the screens smallest dimension).
if ((rangex * rangex + rangey * rangey) > maxRange * maxRange) {
rockets.removeCurrent();
} else {
r.xold = r.x;
r.yold = r.y;
r._x += r.vx;
r._y += r.vy;
r.x = r._x >> 8;
r.y = r._y >> 8;
// If a border has been hit, wrap the trajectory around
// the screen. The new origin is the projection of the
// intersection point on the opposite border.
if (r.x <= 0) {
r.moveTo(width - 2, r.y);
} else if (r.x >= width - 1) {
r.moveTo(1, r.y);
} else if (r.y <= 0) {
r.moveTo(r.x, height - 2);
} else if (r.y >= height - 1) {
r.moveTo(r.x, 1);
}
// Upgrade the range travelled.
r._rangex += r.vx;
r._rangey += r.vy;
}
}
}
/**
* Draws all the rockets of the supplied object pool using the
* specified graphic context.
*/
public static final void draw(Graphics g) {
for (int i = 0; i < rockets.count; i++) {
Rocket r = (Rocket)rockets.pool[i];
g.drawLine(r.x, r.y, r.x, r.y);
}
}
}

153
tests/asteroids/Scores.java Normal file
Просмотреть файл

@ -0,0 +1,153 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.rms.*;
import java.io.*;
/**
* Class used for storing game scores.
* @author Jean-Francois Doue
* @version 1.0, 2001/07/26
*/
public class Scores {
/**
* An array of player names.
*/
public String[] names = {"LAU", "RAG", "NES"};
/**
* An array of player high scores.
*/
public int[] values = {980, 675, 172};
//public int[] values = {30, 20, 10};
/**
* Utility method to convert a integer score to a character
* array.
*/
public static void toCharArray(int score, char[] charArray) {
// Convert the score to an array of chars
// of the form: 0000
charArray[0] = (char)('0' + (score / 1000));
score = score % 1000;
charArray[1] = (char)('0' + (score / 100));
score = score % 100;
charArray[2] = (char)('0' + (score / 10));
score = score % 10;
charArray[3] = (char)('0' + score);
}
public Scores() {
// Initialize / read scores from persistent storage.
RecordStore recordStore = null;
try {
recordStore = RecordStore.openRecordStore("scores", true);
// If the record store exists and contains records,
// read the high scores.
if (recordStore.getNumRecords() > 0) {
for (int i = 0; i < names.length; i++) {
byte[] record = recordStore.getRecord(i + 1);
DataInputStream istream = new DataInputStream(new ByteArrayInputStream(record, 0, record.length));
values[i] = istream.readInt();
names[i] = istream.readUTF();
}
} else {
// Otherwise, create the records and initialize them
// with the default values. They will have record IDs
// 1, 2, 3
for (int i = 0; i < names.length; i++) {
ByteArrayOutputStream bstream = new ByteArrayOutputStream(12);
DataOutputStream ostream = new DataOutputStream(bstream);
ostream.writeInt(values[i]);
ostream.writeUTF(names[i]);
ostream.flush();
ostream.close();
byte[] record = bstream.toByteArray();
recordStore.addRecord(record, 0, record.length);
}
}
} catch(Exception e) {
} finally {
if (recordStore != null) {
try {
recordStore.closeRecordStore();
} catch(Exception e) {
}
}
}
}
/**
* Returns true if the score is among the high scores.
*/
public boolean isHighScore(int score) {
for (int i = 0; i < names.length; i++) {
if (score >= values[i]) {
return true;
}
}
return false;
}
/**
* Updates the high score database with the supplied name and score.
*/
public void addHighScore(int score, String name) {
for (int i = 0; i < names.length; i++) {
if (score >= values[i]) {
// Shift the score table.
for (int j = names.length - 1; j > i; j--) {
values[j] = values[j - 1];
names[j] = names[j - 1];
}
// Insert the new score.
values[i] = score;
names[i] = name;
// Overwrite the scores in persistent storage.
RecordStore recordStore = null;
try {
recordStore = RecordStore.openRecordStore("scores", true);
for (int j = 0; j < names.length; j++) {
ByteArrayOutputStream bstream = new ByteArrayOutputStream(12);
DataOutputStream ostream = new DataOutputStream(bstream);
ostream.writeInt(values[j]);
ostream.writeUTF(names[j]);
ostream.flush();
ostream.close();
byte[] record = bstream.toByteArray();
recordStore.setRecord(j + 1, record, 0, record.length);
}
} catch(Exception e) {
} finally {
if (recordStore != null) {
try {
recordStore.closeRecordStore();
} catch(Exception e) {
}
}
}
break;
}
}
}
}

235
tests/asteroids/Ship.java Normal file
Просмотреть файл

@ -0,0 +1,235 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import javax.microedition.lcdui.*;
import java.util.*;
/**
* Class to implement the player's spaceship. The spaceship
* can rotate, move, shoot and teleport itself.
* @author Jean-Francois Doue
* @version 1.4, 2002/10/14
*/
public class Ship extends Mobile {
/**
* False if the ship has been shot.
*/
public boolean isAlive;
/**
* The orientation of the ship.
*/
public byte angle;
/**
* The X coordinates of an array of points representing the ship
* at various orientations.
*/
public static byte[] xcoords;
/**
* The Y coordinates of an array of points representing the ship
* at various orientations.
*/
public static byte[] ycoords;
/**
* The size of the ship (in pixels).
*/
public static byte radius;
/**
* The ship singleton
*/
public static Ship ship;
private byte _explosionFrame;
private byte _latency; // To limit the ship's firing power
static {
// Instantiate the ship.
ship = new Ship();
final byte[] pointx = {5,-3, 0,-3};
final byte[] pointy = {0, 4, 0,-4};
radius = (byte)(5 * ratioNum / ratioDenom);
xcoords = new byte[128];
ycoords = new byte[128];
for (int i = 0; i < 32; i++) {
int offset = i << 2;
for (int j = 0; j < 4; j++) {
xcoords[offset + j] = (byte)(((pointx[j] * cos[i] - pointy[j] * sin[i]) * ratioNum / ratioDenom) >> 6);
ycoords[offset + j] = (byte)(((pointx[j] * sin[i] + pointy[j] * cos[i]) * ratioNum / ratioDenom) >> 6);
}
}
}
public Ship() {
}
/**
* Positions the ship at its original location, orientation
* and velocity.
*/
public final void reset() {
angle = 0;
moveTo(Mobile.width >> 1, Mobile.height >> 1);
vx = 0;
vy = 0;
isAlive = true;
rotate(0);
}
/**
* Called when the ship collides with an asteroid.
*/
public final void explode() {
isAlive = false;
_explosionFrame = 0;
}
/**
* Move the ship to its next position.
*/
public final void move() {
if (isAlive) {
xold = x;
yold = y;
_x += vx;
_y += vy;
x = _x >> 8;
y = _y >> 8;
// If a border has been hit, wrap the trajectory around
// the screen. The new origin is the projection of the
// intersection point on the opposite border.
if (x <= 0) {
moveTo(width - 2, y);
} else if (x >= width - 1) {
moveTo(1, y);
} else if (y <= 0) {
moveTo(x, height - 2);
} else if (y >= height - 1) {
moveTo(x, 1);
}
if (_latency > 0) {
_latency--;
}
} else {
_explosionFrame++;
if (_explosionFrame > 20) {
reset();
}
}
}
/**
* Changes the orientation of the ship.
*/
public final void rotate(int direction) {
if (isAlive) {
angle += direction;
if (angle > 31) {
angle -= 32;
} else if (angle < 0) {
angle += 32;
}
}
}
/**
* Adds velocity to the ship.
*/
public final void burn() {
if (isAlive) {
int newvx = vx + (cos[angle] << 1);
int newvy = vy + (sin[angle] << 1);
// clamp the ship velocity.
if (newvx * newvx + newvy * newvy < 262144) {
vx = newvx;
vy = newvy;
}
}
}
/**
* Shoots a rocket.
*/
public final Rocket shoot(Pool rockets) {
if (isAlive) {
if (_latency == 0) {
Rocket rocket = (Rocket)rockets.addNewObject();
if (rocket != null) {
int offset = angle << 2;
rocket.init(xcoords[offset] + x, ycoords[offset] + y, angle, vx, vy);
// Prevent the ship for shooting again for 3 frames
_latency = 3;
}
}
}
return null;
}
/**
* Teleports the ship to another lcoation.
*/
public final void teleport() {
if (isAlive) {
moveTo(Math.abs(Game.random.nextInt()) % width, Math.abs(Game.random.nextInt()) % height);
}
}
/**
* Draws the ship at the specified location and orientation.
*/
public static void draw(int orientation, int xpos, int ypos, Graphics g) {
int offset = orientation << 2;
g.drawLine(xcoords[offset] + xpos, ycoords[offset] + ypos,
xcoords[offset + 1] + xpos, ycoords[offset + 1] + ypos);
g.drawLine(xcoords[offset + 1] + xpos, ycoords[offset + 1] + ypos,
xcoords[offset + 2] + xpos, ycoords[offset + 2] + ypos);
g.drawLine(xcoords[offset + 2] + xpos, ycoords[offset + 2] + ypos,
xcoords[offset + 3] + xpos, ycoords[offset + 3] + ypos);
g.drawLine(xcoords[offset + 3] + xpos, ycoords[offset + 3] + ypos,
xcoords[offset + 0] + xpos, ycoords[offset + 0] + ypos);
}
/**
* Draws the ship in the specified graphic context.
*/
public final void draw(Graphics g) {
if (isAlive) {
draw(angle, x, y, g);
} else {
if (_explosionFrame < 6) {
g.setColor(255, 0, 0);
int radius = _explosionFrame;
g.drawArc(x - radius, y - radius, radius << 1, radius << 1, 0, 360);
radius = _explosionFrame + 2;
g.drawArc(x - radius, y - radius, radius << 1, radius << 1, 0, 360);
radius = _explosionFrame + 4;
g.drawArc(x - radius, y - radius, radius << 1, radius << 1, 0, 360);
}
}
}
}

Просмотреть файл

@ -0,0 +1,187 @@
/**
* Copyright 2001 Jean-Francois Doue
*
* This file is part of Asteroid Zone. Asteroid Zone is free software;
* you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any later version.
* Asteroid Zone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Asteroid Zone; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package asteroids;
import java.util.*;
import javax.microedition.lcdui.*;
/**
* Class to manage the game presentation screens.
* @author Jean-Francois Doue
* @version 1.2, 2001/10/24
*/
public class Slideshow extends TimerTask {
private byte _nextState;
private static int _smallFontHeight;
private static int _bigFontHeight;
private static final String _asteroid = "ASTEROID";
private static final String _field = "ZONE";
private static final String _byjfd = "by J.F. Doue";
private static final String _version = "v1.4 - 13 Oct 2002";
private static final String _gameControls = "Game Controls";
private static final String _points = "Points";
private static final String _hiScores = "High Scores";
private static final String _gameOver = "Game Over";
private static final String[] _commands = {"Rotate:", "Shoot:", "Thrust:", "Teleport:"};
private static final String[] _keys = {"Left/Right", "Fire", "Up or A", "B"};
static {
_smallFontHeight = Field.smallFont.getHeight();;
_bigFontHeight = Field.bigFont.getHeight();
}
public Slideshow(byte nextState) {
_nextState = nextState;
}
/**
* Overriden from TimerTask. Triggers the transition to the next
* game state.
*/
public void run() {
Game.field.setState(_nextState);
}
/**
* Draws the title screen.
*/
public static void drawTitleScreen(Graphics g) {
g.setColor(0x00000000);
g.setFont(Field.bigFont);
int x = (Mobile.width - Field.bigFont.stringWidth(_asteroid)) >> 1;
int y = ((Mobile.height - ((_bigFontHeight + _smallFontHeight) << 1)) >> 1) + _bigFontHeight;
g.drawString(_asteroid, x, y, Graphics.BOTTOM|Graphics.LEFT);
x = (Mobile.width - Field.bigFont.stringWidth(_field)) >> 1;
g.drawString(_field, x, y + _bigFontHeight, Graphics.BOTTOM|Graphics.LEFT);
g.setColor(0x008080FF);
x = ((Mobile.width - Field.bigFont.stringWidth(_asteroid)) >> 1) - 1;
y += 1;
g.drawString(_asteroid, x, y, Graphics.BOTTOM|Graphics.LEFT);
x = ((Mobile.width - Field.bigFont.stringWidth(_field)) >> 1) - 1;
y += _bigFontHeight;
g.drawString(_field, x, y, Graphics.BOTTOM|Graphics.LEFT);
y += _smallFontHeight;
g.setColor(0x00000000);
g.setFont(Field.smallFont);
x = (Mobile.width - Field.smallFont.stringWidth(_byjfd)) >> 1;
g.drawString(_byjfd, x, y, Graphics.BOTTOM|Graphics.LEFT);
y += _smallFontHeight;
x = (Mobile.width - Field.smallFont.stringWidth(_version)) >> 1;
g.drawString(_version, x, y, Graphics.BOTTOM|Graphics.LEFT);
}
/**
* Draws the control screen.
*/
public static void drawControlScreen(Graphics g) {
// Draw the "Game control" string
g.setFont(Field.smallFont);
g.setColor(0x00000000);
int x = (Mobile.width - Field.smallFont.stringWidth(_gameControls)) >> 1;
int y0 = ((Mobile.height - _smallFontHeight * 5) >> 1) + _smallFontHeight;
int y = y0;
g.drawString(_gameControls, x, y, Graphics.BOTTOM|Graphics.LEFT);
// Draw the command names
x = (Mobile.width >> 1) - 2;
for (int i = 0; i < 4; i++) {
y += _smallFontHeight;
g.drawString(_commands[i], x, y, Graphics.BOTTOM|Graphics.RIGHT);
}
// Draw the command keys
g.setColor(0x00FF0000);
y = y0;
x = (Mobile.width >> 1) + 2;
for (int i = 0; i < 4; i++) {
y += _smallFontHeight;
g.drawString(_keys[i], x, y, Graphics.BOTTOM|Graphics.LEFT);
}
}
/**
* Draws the points screen.
*/
public static void drawPointsScreen(Graphics g) {
g.setFont(Field.smallFont);
g.setColor(0x00000000);
int x = (Mobile.width - Field.smallFont.stringWidth(_points)) >> 1;
int y = ((Mobile.height - 6 * Asteroid.radii[Asteroid.SIZE_LARGE] - _smallFontHeight) >> 1) + _smallFontHeight;
g.drawString(_points, x, y, Graphics.BOTTOM|Graphics.LEFT);
x = Mobile.width >> 2;
y += Asteroid.radii[Asteroid.SIZE_LARGE];
Asteroid.draw(Asteroid.SIZE_SMALL, x, y, g);
int textx = Mobile.width >> 1;
int texty = y + (_smallFontHeight >> 1);
g.drawString("5 pts", textx, texty, Graphics.BOTTOM|Graphics.LEFT);
y += (Asteroid.radii[Asteroid.SIZE_LARGE] << 1);
Asteroid.draw(Asteroid.SIZE_MEDIUM, x, y, g);
texty = y + (_smallFontHeight >> 1);
g.drawString("2 pts", textx, texty, Graphics.BOTTOM|Graphics.LEFT);
y += (Asteroid.radii[Asteroid.SIZE_LARGE] << 1);
Asteroid.draw(Asteroid.SIZE_LARGE, x, y, g);
texty = y + (_smallFontHeight >> 1);
g.drawString("1 pt", textx, texty, Graphics.BOTTOM|Graphics.LEFT);
}
/**
* Draws the game over screen.
*/
public static void drawGameOverScreen(Graphics g) {
// Draw the "Game over" string
g.setFont(Field.smallFont);
g.setColor(0x00000000);
int x = (Mobile.width - Field.smallFont.stringWidth(_gameOver)) >> 1;
int y = (Mobile.height + _smallFontHeight) >> 1;
g.drawString(_gameOver, x, y, Graphics.BOTTOM|Graphics.LEFT);
}
/**
* Draws the high scores screen.
*/
public static void drawHighScoresScreen(Graphics g) {
// Draw the "High score" string
g.setFont(Field.smallFont);
g.setColor(0x00000000);
int x = (Mobile.width - Field.smallFont.stringWidth(_hiScores)) >> 1;
int y0 = ((Mobile.height - (_smallFontHeight << 2)) >> 1) + _smallFontHeight;
int y = y0;
g.drawString(_hiScores, x, y, Graphics.BOTTOM|Graphics.LEFT);
// Draw the best player names
x = (Mobile.width >> 1) - 2;
for (int i = 0; i < 3; i++) {
y += _smallFontHeight;
g.drawString(Game.scores.names[i], x, y, Graphics.BOTTOM|Graphics.RIGHT);
}
// Draw the best scores.
g.setColor(0x00FF0000);
y = y0;
x = (Mobile.width >> 1) + 2;
char[] scoreString = new char[4];
for (int i = 0; i < 3; i++) {
y += _smallFontHeight;
Scores.toCharArray(Game.scores.values[i], scoreString);
g.drawChars(scoreString, 0, 4, x, y, Graphics.BOTTOM|Graphics.LEFT);
}
}
}