| [ directory ] |
|
12.7 Sample Code: A Simple GameThis example illustrates how the APIs discussed in this chapter can be used to form a simple game. The user controls a car that is always moving forward at a constant speed and can be turned 90 degrees clockwise or counterclockwise. The object of the game is to drive around the track and collect as many coins as possible without hitting any of the walls. (See Figure 12.16 on the next page.) Figure 12.16. A screen shot from the simple game
The car is implemented using a Sprite that can be rotated in 90-degree increments using the appropriate transform. Special frame sequences are used to show just the first frame or to animate through the explosion frames. The track and the coins are implemented using TiledLayers. Most of the cells in the tiled layers are left empty so that the dark gray background is seen. A static tile is used to form the walls of the track, and an animated tile is used to display the spinning coins. Two separate TiledLayers are used to simplify the collision detection code. Collision detection provides a simple way to determine whether the car has collided with a non-empty cell in either of the TiledLayers. If the collision was with the coins, some simple code determines which cells containing the coins can be removed and the score can be accurately updated. Note that this code example is simplified to demonstrate the use of the game API; a real application would require additional code to appropriately handle application starting and pausing, game restarts, displaying the score, multiple levels, and so on.
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import java.io.*;
/**
* Simple car game that demonstrates
* the MIDP 2.0 Game API
**/
public class SimpleGame extends MIDlet {
public SimpleGame() {
}
protected void startApp() throws MIDletStateChangeException {
try {
Display.getDisplay(this).setCurrent(
new SimpleGameCanvas(this));
} catch (IOException e) {
// Cannot load game
}
}
protected void pauseApp() {
}
protected void destroyApp(boolean unconditional)
throws MIDletStateChangeException {
}
}
/**
* GameCanvas subclass for the game
*/
public class SimpleGameCanvas extends GameCanvas
implements Runnable {
// Car directions
static final int DIR_UP = 0;
static final int DIR_RIGHT = 1;
static final int DIR_DOWN = 2;
static final int DIR_LEFT = 3;
// Transform to be used for each car direction
static final int[] carTrans = { Sprite.TRANS_NONE,
Sprite.TRANS_ROT90,
Sprite.TRANS_ROT180,
Sprite.TRANS_ROT270 };
MIDlet parent;
Sprite car;
TiledLayer track;
TiledLayer coins;
int[] normalSequence = {0};
int[] explosionSequence = { 1, 1, 2, 2, 3, 3, 4, 4, 4,
5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7 };
public SimpleGameCanvas(MIDlet parentMIDlet)
throws IOException {
super(true);
parent = parentMIDlet;
// Create the car, define its reference pixel, and set
// the frame sequence that shows just the first frame
Image carFrames = Image.createImage("/carframes.png");
car = new Sprite(carFrames, 16, 23);
car.defineReferencePixel(8, 5);
car.setFrameSequence(normalSequence);
car.setPosition(30, 240);
// Create the track and set the cell values
Image tiles = Image.createImage("/tiles.png");
track = new TiledLayer(30, 30, tiles, 16, 16);
track.fillCells(0, 0, 30, 1, 1);
track.fillCells(0, 29, 30, 1, 1);
track.fillCells(0, 1, 1, 28, 1);
track.fillCells(29, 1, 1, 28, 1);
track.fillCells(4, 15, 22, 1, 1);
coins = new TiledLayer(30, 30, tiles, 16, 16);
coins.createAnimatedTile(2);
coins.setCell(3, 3, -1);
coins.setCell(6, 20, -1);
coins.setCell(10, 24, -1);
coins.setCell(16, 18, -1);
coins.setCell(23, 3, -1);
coins.setCell(3, 16, -1);
coins.setCell(16, 25, -1);
}
public void showNotify() {
// Start a thread to run the game
new Thread(this).start();
}
public void run() {
// Get graphics for rendering to the screen buffer
Graphics g = getGraphics();
// Create a layer manager to render the layers and
// add the layers in the appropriate order
LayerManager mgr = new LayerManager();
mgr.append(car);
mgr.append(track);
mgr.append(coins);
// Determine the view window size and its vertical
// location on the screen
int viewOffset = g.getFont().getHeight();
int viewWidth = getWidth();
int viewHeight = getHeight() - viewOffset;
// Game state information
boolean exploding = false;
int lastKeys = 0;
int dir =0;
int vx = 0;
int vy = 0;
int coinsLeft = 7;
// Counter used to animate the coins
int coinTile = 0;
int score = 1;
while (true) {
// Update current car direction based on key input
int keys = getKeyStates();
if (keys != lastKeys) {
if ((keys & LEFT_PRESSED) != 0) {
dir--;
}
else if ((keys & RIGHT_PRESSED) != 0) {
dir++;
}
dir = (dir + 4) & 0x03;
car.setTransform(carTrans[dir]);
lastKeys = keys;
}
// Check whether the car is exploding
if (exploding) {
// Check whether the end of the explosion
// sequence has been reached
if (car.getFrame() == explosionSequence.length-1) {
return;
}
// Show the next frame in the explosion sequence
car.nextFrame();
} else {
// Update the car's velocities based on
// the current direction
switch (dir) {
case DIR_UP:
if (vy > -32) vy--;
if (vx > 0) vx--;
if (vx < 0) vx++;
break;
case DIR_RIGHT:
if (vx < 32) vx++;
if (vy > 0) vy--;
if (vy < 0) vy++;
break;
case DIR_DOWN:
if (vy < 32) vy++;
if (vx > 0) vx--;
if (vx < 0) vx++;
break;
case DIR_LEFT:
if (vx > -32) vx--;
if (vy > 0) vy--;
if (vy < 0) vy++;
break;
}
// Move the car based on its velocities
car.move(vx >> 4, vy >> 4);
// check whether we hit the track wall
if (car.collidesWith(track, true)) {
// Start the explosion sequence
car.setFrameSequence(explosionSequence);
exploding = true;
}
// check whether the car hit a coin
if (car.collidesWith(coins, true)) {
// Determine which cells intersect with car
// Get the overall bounds of the car
int xmin = car.getX();
int xmax = xmin + car.getWidth();
int ymin = car.getY();
int ymax = ymin + car.getHeight();
// Convert car bounds to grid coordinates
// (divide by 16)
xmin >>= 4;
xmax >>= 4;
ymin >>= 4;
ymax >>= 4;
// Check each cell that intersects the car's bounds
for (int i = xmin; i <= xmax; i++) {
for (int j = ymin; j <= ymax; j++) {
// See if the cell is not empty
if (coins.getCell(i, j) != 0) {
// Remove the cell's coin
coins.setCell(i, j, 0);
coinsLeft--;
// Increment the score
score++;
}
}
}
if (coinsLeft == 0) {
// Game over, player won
}
}
}
// Animate the coins by updating the static tile
// that is linked to the animated tile
coins.setAnimatedTile(-1, 2 + ((coinTile++ >> 2)
& 0x03));
// Adjust the view window so that the car is always
// in the center of the screen
mgr.setViewWindow(car.getRefPixelX()-(viewWidth/2),
car.getRefPixelY()-(viewHeight/2),
viewWidth, viewHeight);
// Fill the background with dark gray
g.setGrayScale(45);
g.fillRect(0,viewOffset, viewWidth, viewHeight);
// Render the layers (coins, track, and car) at the
// appropriate location on the screen
mgr.paint(g, 0, viewOffset);
// Render the score
g.setColor(0xFFFFFF);
g.fillRect(0,0, viewWidth, viewOffset);
g.setColor(0x000000);
// Flush the screen buffer to the display
flushGraphics();
}
}
}
|
| [ directory ] |
|