зеркало из https://github.com/mozilla/pluotsorbet.git
Merge branch 'master' of https://github.com/andreasgal/j2me.js
This commit is contained in:
Коммит
1dbece6ca6
2
midp.js
2
midp.js
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче