Black Art of Java Game Programming:Building the JAVAroids Game// handle keyDown events by setting the appropriate // field in the key buffer // field in the key buffer... Black Art of Ja
Trang 1Black Art of Java Game Programming:Building the JAVAroids Game
// key bindings
static final int LEFTINDEX = 0;
static final int LEFT = 'q'; // rotate left
static final int RIGHTINDEX = 1;
static final int RIGHT = 'w'; // rotate right
static final int THRUSTINDEX = 2;
static final int THRUST = 'o'; // thrust
static final int FIREINDEX = 3;
static final int FIRE = 'p'; // fire
static final int SHIELDINDEX = 4;
static final int SHIELD = ' '; // shield
/////////////////////////////////////////////////////////////////// update Ship and Fire sprites based on key buffer
///////////////////////////////////////////////////////////////// public void update() {
// update fire sprites
for ( int i=0 ; i<MAX_SHOTS; i++) {
Trang 2// otherwise, the ship's not alive!
else {
// if the waiting period's over,
// initialize a new Ship sprite
if (!gameOver && (waitPeriod <= 0)) {
Trang 3Black Art of Java Game Programming:Building the JAVAroids Game
// handle keyDown events by setting the appropriate
// field in the key buffer
// field in the key buffer
Trang 4private void updateShield() {
///////////////////////////////////////////////////////////////// private void handleFire() {
for (int i=0; i<MAX_SHOTS; i++) {
Trang 5Black Art of Java Game Programming:Building the JAVAroids Game
Black Art of Java Game Programming
by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
The Enemy Manager
By now, you should be getting a better idea of how these managers are organized! The
EnemyManager class is responsible for the Enemy sprites and their Fire sprites, which it initializes in its constructor The update() method checks for collisions between the enemy objects and the ship (and this code is really similar to the AstManager’s update()) In addition, update() starts new enemy ships, using the method NewEnemy(), and initiates enemy firing at random intervals Finally, the paint() method cycles through all enemy ship sprites and enemy fire sprites, and tells each one to paint itself
Listing 13-16 shows the EnemyManager class
Listing 13-16 EnemyManager class
///////////////////////////////////////////////////////////////////
// EnemyManager responsible for controlling the
// Enemy alien sprites, and Enemy Fire
//
/////////////////////////////////////////////////////////////////public class EnemyManager extends Object {
// constants to define two sizes of enemy ships
static final int LARGE = 0;
static final int SMALL = 1;
static final int SRATX = 3; // x-ratio of large to small
static final int SRATY = 2; // y-ratio of large to small
// the enemy ship templates
Trang 6static final int tpy[][] = {
{0,3,6,6,3,0,-4,-4,0,0},
{0/SRATY,3/SRATY,6/SRATY,6/SRATY,3/SRATY,0/SRATY,-4/SRATY, -4/SRATY,0/SRATY,0/SRATY} } ;
// screen boundaries
static int width,height;
// constants parameters for enemy ships
static final int MAX_ENEMIES = 3;
static final int MAX_SHOTS_PER_ENEMY = 2;
static final int MAX_SHOTS = MAX_ENEMIES*MAX_SHOTS_PER_ENEMY;
// arrays for color, length, and value of various enemy ships static final Color ENEMY_COLOR[] =
{Color.green,Color.red,Color.orange};
static final int ENEMY_LENGTH[] = {14,14,5};
static final int VALUE[] = {500,750,1000};
// maximum speed
static final int MAX_VX = 9, MAX_VY = 9;
// how often enemies appear, and how often they fire
static double enemy_freq = 0.995 ;
static double fire_freq = 0.995;
// array of Enemy sprites
private Enemy e[] = new Enemy[MAX_ENEMIES];
// array of Fire sprites
private Fire f[] = new Fire[MAX_SHOTS_PER_ENEMY*MAX_ENEMIES];
// references to other game objects
Trang 7Black Art of Java Game Programming:Building the JAVAroids Game
GameManager g) {
ship = sm.getShip(); // get ship needed for // collision detection
shipfire = sm.getFire(); // get ship's fire for
this.sm = sm; // collision detection
this.efm = efm;
game = g;
// initialize the three enemy sprites
e[0] = new Enemy(tpx[0],tpy[0],tpx[0].length, // template
0,0, // initial loc ENEMY_COLOR[0], // color
width,height, // screen bounds ENEMY_LENGTH[0],VALUE[0]); // length,value
e[1] = new Enemy(tpx[0],tpy[0],tpx[0].length,
// suspend the three enemy sprites
for (int i=0; i<MAX_ENEMIES; i++) {
e[i].suspend();
}
// create and suspend the Fire sprites
for ( int i=0 ; i<MAX_SHOTS; i++) {
f[i] = new Fire(ENEMY_COLOR[i/MAX_SHOTS_PER_ENEMY],
///////////////////////////////////////////////////////////////// public void newGame() {
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch13/570-575.html (3 von 7) [13.03.2002 13:19:19]
Trang 8}
for (int i=0 ; i<MAX_SHOTS; i++) {
f[i] = new Fire(ENEMY_COLOR[i/MAX_SHOTS_PER_ENEMY],
// CHECK FOR COLLISIONS WITH SHIP OR SHIP FIRE
///////////////////////////////////////////////////////////////// public void update() {
// check if any of the fire sprites hit the Player's ship // If so, tell the ShipManager to destroy the ship
for ( int i=0 ; i<MAX_SHOTS; i++) {
for ( int i=0 ; i<MAX_ENEMIES; i++) {
// place a new enemy on the screen at random intervals
Trang 9Black Art of Java Game Programming:Building the JAVAroids Game
// tell sm to destroy ship
// check if enemy intersect's ship's fire
for (int j=0; j<shipfire.length; j++) {
if (e[i].intersect(shipfire[j])) {
sm.stopFire(j); // stop fire sprite
e[i].suspend(); // stop enemy sprite
Trang 10private void NewEnemy(int i) {
// set the enemy speed
e[i].setVelocity(GameMath.getRand(2*MAX_VX)-MAX_VX,
GameMath.getRand(2*MAX_VY)-MAX_VY);
// set the enemy position
int px = (Math.random() > 0.5) ? 0 : width;
/////////////////////////////////////////////////////////////////
private void Fire(int i) {
for (int j = i*MAX_SHOTS_PER_ENEMY;
j < (i+1)*MAX_SHOTS_PER_ENEMY;
j++) {
// if there's a slot in enemy fire array,
// initialize and restore the fire sprite
///////////////////////////////////////////////////////////////// public void paint(Graphics g) {
for ( int i=0 ; i<MAX_ENEMIES; i++) {
Trang 11Black Art of Java Game Programming:Building the JAVAroids Game
}
}
Previous Table of Contents Next
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch13/570-575.html (7 von 7) [13.03.2002 13:19:19]
Trang 12by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
The Effect Manager
For the effect manager, we’re going to depart from our policy of avoiding object instantiations during game play This is because the number of explosions is tricky to judge beforehand, so it’s easier to keep a Vector of explosions, and insert new explosions when the other manager classes detect
collisions Thus, EffManager provides the public methods addShipExplosion(),
addEnemyExplosion(), and addAstExplosion(), which the other managers can invoke These methods create new Explosion objects that are added to the explosions Vector
Listing 13-17 contains the complete effect manager class
Listing 13-17 EffManager class
///////////////////////////////////////////////////////////////////
// EffManager: handles effects, such as explosions and sound
//
/////////////////////////////////////////////////////////////////public class EffManager extends Object {
Vector explosions;
AudioClip expsound;
/////////////////////////////////////////////////////////////////// EffManager constructor
/////////////////////////////////////////////////////////////////
public EffManager(AudioClip expsound) {
explosions = new Vector();
this.expsound = expsound;
}
/////////////////////////////////////////////////////////////////// make a ship explosion at x,y
/////////////////////////////////////////////////////////////////file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch13/575-577.html (1 von 3) [13.03.2002 13:19:20]
Trang 13Black Art of Java Game Programming:Building the JAVAroids Game
public void addShipExplosion(int x,int y) {
Explosion exp = new Explosion(Color.red,x,y,20);
Explosion exp1 = new Explosion(Color.yellow,x+2,y+2,25);
///////////////////////////////////////////////////////////////// public void addAstExplosion(int x,int y) {
Explosion exp = new Explosion(Color.white,x,y,15);
///////////////////////////////////////////////////////////////// public void addEnemyExplosion(int x,int y) {
Explosion exp = new Explosion(Color.orange,x,y,15);
///////////////////////////////////////////////////////////////// public void addExplosion(Color c,int x, int y, int u) {
Explosion exp = new Explosion(c,x,y,u);
// explosions Vector
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch13/575-577.html (2 von 3) [13.03.2002 13:19:20]
Trang 14// explosions Vector
///////////////////////////////////////////////////////////////// public void update() {
Trang 15Black Art of Java Game Programming:Building the JAVAroids Game
Black Art of Java Game Programming
by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
The Game Manager
The GameManager class contains the top-level structure of JAVAroids The game opens with an introductory screen, which lists the point values of the objects in the game After this, the player can test drive his ship, and learn the controls Then, the player can start the game The transition between these screens is triggered by a mouseUp event
GameManager implements the Runnable interface by defining a method called run() The heart of the run() method is the Video Game Loop, which we covered back in Chapter 5, Building a Video Game This loop coordinates the sequence of actions that take place in Figure 13-17 GameManager also defines handlers for key events, which it passes along to the ShipManager
Finally, the GameManager source is presented in Listing 13-18 JAVAroids is finished!
Listing 13-18 GameManager class
///////////////////////////////////////////////////////////////////
// GameManager:
// responsible for tracking status of game and keeping score
//
/////////////////////////////////////////////////////////////////public class GameManager extends Applet implements Runnable {
// variables for double buffering and animation
Thread animation;
Graphics gbuf;
Image im;
static final int REFRESH_RATE = 72; // in ms
// size of the game applet: change as needed
static final int MAX_HEIGHT = 400;
static final int MAX_WIDTH = 400;
// game parameters
file:///D|/Downloads/Books/Computer/Java/Bla 0Java%20Game%20Programming/ch13/578-588.html (1 von 12) [13.03.2002 13:19:21]
Trang 16private boolean gameOver; // is game over
private int intro_screen; // which screen
static final int EXTRA_SHIP = 10000; // #pts for extra ship private int current_extra = 0; // counts extras
// constants for the introduction part of the game
static final int INSTRUCTIONS = 1;
static final int TEST_DRIVE = 2;
static final int INTRO_OVER = 3;
// references to manager classes
AstManager am; // asteroids
ShipManager sm; // ship
EnemyManager em; // enemy ships
EffManager efm; // effects
// sound
URL codebase;
AudioClip expsound = null;
// variables to monitor performance during game
Date time;
long t1,t2,dt;
// fonts
static Font bigfont = new Font("TimesRoman", Font.BOLD,24);
static Font medfont = new Font("TimesRoman", Font.PLAIN,18); static Font smallfont = new Font("TimesRoman", Font.PLAIN,12);
/////////////////////////////////////////////////////////////////// initialize applet
///////////////////////////////////////////////////////////////// public void init() {
Trang 17Black Art of Java Game Programming:Building the JAVAroids Game
///////////////////////////////////////////////////////////////// public void start() {
// load sound
try {
expsound = getAudioClip(getCodeBase(),"Explosion.au");
}
catch (Exception exc) {
System.out.println("Sound not loaded");
};
// initialize manager classes
efm = new EffManager(expsound);
/////////////////////////////////////////////////////////////////
file:///D|/Downloads/Books/Computer/Java/Bla 0Java%20Game%20Programming/ch13/578-588.html (3 von 12) [13.03.2002 13:19:21]
Trang 18///////////////////////////////////////////////////////////////// public void setGameOver() {
gameOver = true;
}
/////////////////////////////////////////////////////////////////// start a new game
///////////////////////////////////////////////////////////////// private void newGame() {
// tell managers to start a new game
Trang 19Black Art of Java Game Programming:Building the JAVAroids Game
sm.getShip().restore();
}
// else restart the game
else if (intro_screen == TEST_DRIVE) {
// pass key events to the ShipManager
public boolean keyDown(Event e, int k) {
sm.keyDown(e,k);
return true;
}
// pass key events to the ShipManager
public boolean keyUp(Event e, int k) {
sm.keyUp(e,k);
return true;
}
/////////////////////////////////////////////////////////////////// the game driver
///////////////////////////////////////////////////////////////// public void run() {
em.update(); // update enemies
am.update(); // update asteroids
efm.update(); // update effects
Trang 20Thread.sleep (REFRESH_RATE);// sleep
} catch (Exception exc) { };
}
}
}
/////////////////////////////////////////////////////////////////// initialize the AstManager and EnemyManager for the
// INSTRUCTIONS screen
///////////////////////////////////////////////////////////////// private void startInstructions() {
Asteroid a[] = am.getAsts();
Trang 21Black Art of Java Game Programming:Building the JAVAroids Game
// set enemies for intro screen
Enemy e[] = em.getEnemy();
///////////////////////////////////////////////////////////////// private void updateOpening() {
// (every EXTRA_SHIP points) give an extra ship!
///////////////////////////////////////////////////////////////// public void updateScore(int val) {
score += val;
if ((score / EXTRA_SHIP) > current_extra) {
sm.extraShip(); // give extra ship
current_extra = score/EXTRA_SHIP;
}
}
/////////////////////////////////////////////////////////////////// override update() to eliminate flicker
/////////////////////////////////////////////////////////////////file:///D|/Downloads/Books/Computer/Java/Bla 0Java%20Game%20Programming/ch13/578-588.html (7 von 12) [13.03.2002 13:19:21]
Trang 22}
/////////////////////////////////////////////////////////////////// return a string of n that is 0-padded with the given length///////////////////////////////////////////////////////////////// public String PadNumber(int n,int len) {
///////////////////////////////////////////////////////////////// // Strings used in INSTRUCTIONS screen
String javaroidsString = new String("JAVAroids!");
String galleryString = new String("The Lineup ");
new String("extra shield strength:");
// Strings used in the TEST_DRIVE screen
String shipControlString =
new String("Test Drive your ship NOW -> ");
String rotLeftString = new String("Press 'q' to Rotate Left"); String rotRightString =
file:///D|/Downloads/Books/Computer/Java/Bla 0Java%20Game%20Programming/ch13/578-588.html (8 von 12) [13.03.2002 13:19:21]
Trang 23Black Art of Java Game Programming:Building the JAVAroids Game
new String("Press 'w' to Rotate Right");
String thrustString = new String("Press 'o' to Thrust");
String fireString = new String("Press 'p' to Fire");
new String("Click mouse to begin!");
String byMeString = new String("by Joel Fan");
String gameOverString = new String("GAME OVER");
String clickMouseString2 =
new String("Click mouse to play again!");
/////////////////////////////////////////////////////////////////// paint to the screen, depending on mode of game
///////////////////////////////////////////////////////////////// public void paint(Graphics g) {
// clear offscreen buffer
Trang 24// tell other manager classes to paint themselves
em.paint(gbuf); // paint enemies
am.paint(gbuf); // paint asteroids
efm.paint(gbuf); // paint effects
// draw the score
// coordinates are hardcoded for simplicity
///////////////////////////////////////////////////////////////// public void paintInstructions(Graphics g) {
Trang 25Black Art of Java Game Programming:Building the JAVAroids Game
// coordinates are hardcoded for simplicity
///////////////////////////////////////////////////////////////// public void paintTestDrive(Graphics g) {
Trang 26Recommended Applet Tag to Run JAVAroids
<applet code=“GameManager.class” width=400 height=400>
Previous Table of Contents Next
file:///D|/Downloads/Books/Computer/Java/Bl Java%20Game%20Programming/ch13/578-588.html (12 von 12) [13.03.2002 13:19:21]
Trang 27Black Art of Java Game Programming:Building the JAVAroids Game
Black Art of Java Game Programming
by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
Suggestion Box
This game’s only a starting point Here are a few ideas for further extensions and improvements to the game:
• Make the enemy ships more intelligent For example, they could follow the player’s ship, or
exhibit different behaviors You can use a state machine to implement multiple behaviors, as you’ve seen in Chapter 5, Building a Video Game
• Change the way the game objects move One change you can implement almost immediately
is to bounce the sprites off the edges of the screen, instead of wrapping them around to the other side Just modify the updatePosition() method of MoveablePolygon, and you can alter the dynamic of the game dramatically!
• Another way of handling explosions and sound effects is by incorporating this functionality
in the Sprite subclasses themselves Thus, the sprites would be responsible for the sounds that occur when they collide, and the way that they explode In this scenario, the effect manager might tell the individual sprites when to make sounds or explode, but the actual sound or
explosion is the responsibility of the sprite itself Think about the benefits of encapsulating explosion and sound effects in the Sprite subclasses, and implement it
• Optimize the game Here are some ways of doing this First, precompute the coordinates of
the rotated polygons, and store them in a lookup table This way, you can avoid the point multiplications while the game is playing Secondly, use final methods whenever
floating-possible (such as accessor methods) to eliminate the overhead from dynamic method binding
A third optimization is to flatten the inheritance hierarchy, and reduce unnecessary method calls by inlining functions as much as possible
• Allow multiple players to compete, either in alternation or at the same time (You’ll need a
big keyboard!)
Summary
You’ve constructed a fairly intricate video game in this chapter However, you’ve built the game, and managed its complexity, by making use of inheritance- and responsibility-driven design These are concepts you can take with you in designing any object-oriented application, whether it’s a game or not!
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch13/588-590.html (1 von 2) [13.03.2002 13:19:21]
Trang 28Previous Table of Contents Next
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch13/588-590.html (2 von 2) [13.03.2002 13:19:21]
Trang 29Black Art of Java Game Programming:Daleks!
Black Art of Java Game Programming
by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
In developing this applet, I paid a lot of attention to the issues of bandwidth and processor speed The sounds, graphics, and animations used are simple but effective The result is a program that loads and runs quickly—features that are easy to overlook with Java In addition, many game parameters are customizable from HTML, meaning the game board, images, and intro screen can be modified to incorporate different themes and challenges
Playing the Game
When the applet first runs, the player is greeted with an animated intro screen and a bar showing the progress of loading images When the images are done loading, the player can press any key to begin the game Figure 14-1 shows a typical board setup on level 1 The player’s character always begins in the center of the screen The Daleks are scattered randomly around the board and move one square in the direction of the player every turn The numeric keypad is used to control movement (diagonal movement is allowed) The player may press “S” to activate a sonic screwdriver to destroy adjacent Daleks The number of remaining screwdrivers is displayed in the info bar at the bottom of the screen The player may teleport at any time by pressing “T” This will move the player to a random space on the board, which may be adjacent to one of the Daleks, resulting in the player’s capture and the end of the game Finally, the player can press “L” to make a “last stand,” allowing the Daleks to move
continuously until the player or all the Daleks are destroyed
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/591-596.html (1 von 4) [13.03.2002 13:19:22]
Trang 30Figure 14-1 The Daleks! board
Setting Up the Game
The applet is contained in two classes, daleks14 and animatedIntroClass A daleks14 object contains all the game routines and directs the traffic throughout the game An animatedIntroClass object contains the methods necessary to create the title screen shown between games Listing 14-1 shows the init() method of the daleks14 class, which is automatically called when the applet is loaded
Listing 14-1 The daleks14.init() method
public void init() {
// get parameters from the calling HTML file
getHTMLParameters();
// initialize dalek arrays
dalX = new int[maxEnemies];
dalY = new int[maxEnemies];
dalF = new int[maxEnemies];
Trang 31Black Art of Java Game Programming:Daleks!
to resize(int, int) ensures that the game graphics will fit in the applet window The method then
assigns each graphic image to the appropriate Image object The various Images contained in the
doctorPic array are needed because the player’s appearance changes at certain levels (mimicking Dr
Who’s ability to regenerate on the TV show) Each player and Dalek has a right- and left-facing
Image All the Image objects are given to a newly created MediaTracker object tracker, which
handles loading the graphics and reports on their progress The nextScreen variable is basically a
worksheet Image where we build each successive game screen, which can be accessed by using
offScreenGC, its graphics context The call to prepareScreen() draws the current game status on the
offscreen Image Finally, the animatedIntroClass object is initialized and run
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/591-596.html (3 von 4) [13.03.2002 13:19:22]
Trang 32Java addresses some of the complexity of C++ by eliminating the ability to dynamically allocate memory After an array is initialized, it cannot be extended, which can greatly reduce the flexibility
of Java applets Daleks! avoids this problem by waiting to initialize the Dalek arrays until the
maximum number of Daleks allowed is determined (this can be set through an HTML <param> tag)
Previous Table of Contents Next
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/591-596.html (4 von 4) [13.03.2002 13:19:22]
Trang 33Black Art of Java Game Programming:Daleks!
Black Art of Java Game Programming
by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
Animating the Title Screen
The animated intro screen displays a cloud of question marks flying from the middle to the edges of the screen, as shown in Figure 14-2 It displays the applet title, version number, author, and an info bar on the bottom of the screen If the animatedIntroClass object is running for the first time, it will display a progress bar that grows as the Image variables are loaded When loading is complete, the progress bar is replaced with the standard info bar showing the player status (i.e., last score, screwdrivers, level number, and so on)
Figure 14-2 The animated intro screen
Before the title screen is run, however, a new Thread must be created This allows the daleks14 object to monitor the keyboard while another Thread loops continuously to create the animation effect of the title screen
Preparing to Animate
The title screen features a number of customizable items, and so we cannot assume anything about the applet title, screen size, and flying widgets (question marks by default) We need to have a procedure to ensure that when displayed, the graphics and text on the intro screen will be properly aligned and displayed To do this, the setInfo(…) method examines the dimensions of the String objects to be displayed and determines their horizontal and vertical positions Listing 14-2 shows a portion of the setInfo(…) method, which determines how to center the game title on the screen
Listing 14-2 The animatedIntroClass.setInfo(…) method
// handle Font creation and sizing
int halfWayX = maxX * imgW / 2;
int totalHeight = maxY * imgH;
titleFont = new Font("Helvetica", Font.PLAIN, 36);
offScreenGC.setFont(titleFont);
titleX = halfWayX - offScreenGC.getFontMetrics().stringWidth(gameTitle) ⇐
/ 2;
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/596-599.html (1 von 3) [13.03.2002 13:19:23]
Trang 34The value of halfWayX is the horizontal center of the applet window in pixels (number of horizontal board squares * horizontal width of game pieces / 2) The totalHeight variable is the height of the game board in pixels The code creates a new Font object titleFont, which defines the display characteristics of the String object gameTitle To calculate dimensions, the procedure must make titleFont the current font, which is done
by setting it on the offscreen graphics context offScreenGC The variable titleX is then given the value for center of the screen minus half the width (in pixels) of the gameTitle String The procedure also calculates a
new vertical position for the text, 30 percent of the way down from the top of the applet window (remember both the height and width of the intro screen are customizable!).
Another preparation involves initializing the arrays for the flying String objects on the title screen The
trajectory and speed of each question mark is predetermined Listing 14-3 shows a portion of code that may seem a rather roundabout way of animating a number of randomly moving objects This code was chosen because it minimizes the number of calculations done in the animation loop itself, and therefore increases the speed at which the animation runs.
Listing 14-3 The animatedIntroClass.start() method
public void start() {
// determine question mark trajectory, velocity, and color
// *before* they are ever drawn
for (int j=0; j<numQmarks; j++) {
int angle = (int)(Math.random()*360);
int numSteps = (int)(Math.random()*30) + 20;
qMarkSteps[j] = numSteps;
int bright = 255 - numSteps * 3;
qMarkColor[j] = new Color(85, bright, 85);
qMarkXinc[j] = (int)(Math.cos(angle) * radius / numSteps); qMarkYinc[j] = (int)(Math.sin(angle) * radius / numSteps); qMarkCnt[j] = 0 - (int)(j/2);
qMarkX[j] = maxX * 8 + 2 + qMarkXinc[j];
qMarkY[j] = maxY * 8 + 2 + qMarkXinc[j];
}
}
As will be seen later, the number of question marks on the title screen is variable, and can be changed within
the source code or from HTML The for loop determines a trajectory, velocity, and Color object for each
question mark (later referred to as “flying widgets,” because they can be any valid String object) The total number of steps needed for each question mark to go from the center of the screen to the screen’s edge is
placed in qMarkSteps[x] (this is technically a measure of velocity) The fewer the steps needed to reach the
edge, the faster the question mark will move Based on this velocity, faster question marks are displayed using
brighter Color objects The arrays qMarkXinc[x] and qMarkYinc[x] are determined based on velocity and a
randomly determined trajectory (angle) calculated for each question mark These values represent the amount the question mark will be moved horizontally and vertically from its last position.
What is the end result? The question marks can be drawn and moved with a minimum of logical steps The
qMarkCnt[x] array tracks how many steps each question mark has taken When this becomes larger than the
value of qMarkSteps[x], the question mark is simply returned to the middle of the screen and sent right back
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/596-599.html (2 von 3) [13.03.2002 13:19:23]
Trang 35Black Art of Java Game Programming:Daleks!
along the same path Because of the large number of question marks being displayed, the animation still retains a random feel, even though it really just continually shows the same thing.
Creating a New Thread
Because the daleks14 class is implemented as Runnable, a method called start() is called when the applet is run, as shown in Listing 14-4 This method handles the creation of the new Thread for animation
Listing 14-4 The daleks14.start() method
public void start() {
The kicker Thread can be controlled using its start() and stop() methods The Thread object also contains
methods for adjusting its priority, or its share of CPU resources This allows applet programmers to adjust performance and distribute processing power to the methods or objects that need it most.
Previous Table of Contents Next
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/596-599.html (3 von 3) [13.03.2002 13:19:23]
Trang 36Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
The Animation Loop
Now that two Thread objects are active, one can be concentrated on the animation loop while the other waits for keyboard input (a keypress indicates it is time for the game to begin) Nothing fancy is required
here The update() procedure will call the animatedIntro object whenever animIntro (a boolean variable) is set to true Therefore, the animation loop will start whenever repaint() is called and animIntro is true, as
demonstrated in Listing 14-5.
Listing 14-5 The daleks14.update(…) method
public synchronized void update(Graphics g) {
// draw between-move animations and repaint the game board, or // call the intro screen’s drawing routine
This is the portion of the update() procedure that comprises the animation loop Notice that the loop will
only continue so long as animIntro remains true When a key is pressed and image loading is complete, the keyDown() method sets animIntro to false and stops the second Thread object, effectively ending the
animation loop.
Notice that the actual drawing routine is handled by the animateIntro object Its drawIntroScreen() method
is called with arguments for the current graphics context (telling it where to draw!), Image loading status,
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/599-602.html (1 von 3) [13.03.2002 13:19:23]
Trang 37Black Art of Java Game Programming:Daleks!
and the number of the picture currently being loaded.
The last important point of the animation loop is the use of the MediaTracker object tracker As a picture is loaded, the value for currentPic is incremented The value of currentPic is passed to the animateIntro()
method and is used to determine the length of the progress bar on the bottom of the screen, as shown in
Figure 14-3 When the last Image file is loaded, doneLoading becomes true, and the progress bar is
replaced by the normal status bar.
Figure 14-3 The progress bar while an image is loading
The Game Begins
Once the game begins, nothing happens in the Daleks! applet until the player presses a key In a real-time game this would be unacceptable, but it is perfect for turn-based games A large number of boolean
variables are used in the daleks14 object to help direct traffic, but we will only examine the important ones
to get a feel for the structure of the game itself
Starting a Turn
A new turn begins when the player presses a key, which automatically calls the keyDown() method, shown
in Listing 14-6
Listing 14-6 The daleks14.keyDown(…) method
public synchronized boolean keyDown(Event evt, int x) {
if (doneLoading)
handleKeyPress(x);
return false;
}
Notice that nothing will happen unless doneLoading is true This variable will not become true until the
tracker object is done loading all the Image files necessary to play the game Ideally, the audio files would
also be tracked, but Java’s beta API does not currently implement this function As a result, the game will pause to load audio files the first time they are played.
Directing Traffic
Now that a new turn has started, what should be done? The game can be in many states–we could be
waiting to start a new level (if all the Daleks have been destroyed), in the middle of a level, or waiting to reanimate the title screen (if the player has been captured) Each of these possibilities requires an additional boolean variable to help the handleKeyPress(int) method decide what to do Listing 14-7 gives the skeleton
of this procedure
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/599-602.html (2 von 3) [13.03.2002 13:19:23]
Trang 38public void handleKeyPress(int whichKey)
The if statement checks the current status of the game and calls the appropriate methods Let’s examine
what happens if we are in the middle of a level and the player has pressed a key In this case, the boolean
variables animIntro, levelComplete, and playerDead are false, and the code in the final else clause will be
executed.
Previous Table of Contents Next
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/599-602.html (3 von 3) [13.03.2002 13:19:23]
Trang 39Black Art of Java Game Programming:Daleks!
Black Art of Java Game Programming
by Joel Fan
Sams, Macmillan Computer Publishing
ISBN: 1571690433 Pub Date: 11/01/96
Previous Table of Contents Next
Making the Right Moves
We can only hope for the player’s sake that he or she has made a wise move Fortunately, the applet’s only job is to analyze the player’s input and update the game board according to the rules of the game The final
else clause (with the comment “analyze keypress and execute the next turn”) is where the entire turn
unfolds, shown in Listing 14-8.
Listing 14-8 Executing player’s move in handleKeyPress(int whichKey); executing next turn in
// analyze keypress and execute the next turn
char ASCIImove = (char)whichKey;
boolean validMove = movePlayer(ASCIImove);
Trang 40First, the player’s move is converted from an integer to an ASCII character for simplification Then the
movePlayer(char) method is called This method returns a boolean value—true if the player’s move was valid and false otherwise If the player’s move checks out, several things can happen If the player has
chosen to make a last stand (by pressing “L”), the repaint() procedure is called This will be examined in a later section.
Analyzing Input
The movePlayer(char) method shown in Listing 14-9 takes care of the gritty details of keyboard processing The end result of this method is a boolean value indicating whether or not the player’s move is a valid one
Listing 14-9 The daleks14.movePlayer(…) method
public boolean movePlayer(char input) {
int newX = drX;
int newY = drY;
int newF = drF;
boolean pass = false;
// player may elect to not move (hit '5')
boolean teleport = false;
// player may teleport (hit 'T' or 't')
boolean validMove = true;
switch (input) {
// numeric keypad movement options
case '1': newX ; newY++; newF = faceLeft; break; case '2': newY++; break; case '3': newX++; newY++; newF = faceRight; break; case '4': newX ; newF = faceLeft; break; case '5': pass = true; break; case '6': newX++; newF = faceRight; break; case '7': newX ; newY ; newF = faceLeft; break; case '8': newY ; break; case '9': newX++; newY ; newF = faceRight; break;
file:///D|/Downloads/Books/Computer/Java/Blac 20Java%20Game%20Programming/ch14/602-605.html (2 von 4) [13.03.2002 13:19:24]