Tuesday, January 19, 2010

The Player Sprite









The Player Sprite


PlayerSprite represents the player and is a subclass of TiledSprite. The statechart for PlayerSprite in Figure 13-14 shows that the sprite performs three concurrent activities.


The move( ) and tryPickup( ) transitions are triggered by the user from the keyboard. The hitByAlien( ) transition is initiated by the WorldDisplay object when an alien tells it that it has hit the player.


The transitions in Figure 13-14 are labeled with method names; this is a practice that I'll use when there's a direct mapping from a transition to a method call. This makes it easier to see the mapping from the statechart to the corresponding code.




Figure 13-14. PlayerSprite statechart




Moving (and Standing Still)


A PlayerSprite TRies to move when the user presses one of the quadrant keys (9, 3, 1, or 7):



public void move(int quad)
{
Point newPt = tryMove(quad);
if (newPt == null) { // move not possible
clipsLoader.play("slap", false);
standStill( );
}
else { // move is possible
setTileLoc(newPt); // update the sprite's tile location
if (quad == NE)
setImage("ne");
else if (quad == SE)
setImage("se");
else if (quad == SW)

setImage("sw");
else // quad == NW
setImage("nw");
world.playerHasMoved(newPt, quad);
}
} // end of move( )



The attempt is handled by TiledSprite's inherited tryMove( ) method, and the sprite's tile location is updated if it's successful. The move is dressed up with an image change for the sprite and the playing of a sound effect if the move is blocked.


The player can press 5 to make the sprite stand still, which only changes its associated image. Normally, the sprite is poised in a running position, pointing in one of the quadrant directions.



public void standStill( )
{ setImage("still"); }





Drawing the Player


The statechart includes a draw state, triggered by a draw( ) transition. The draw activity is implemented by using the setPosition( ) and draw( ) methods inherited from Sprite. The drawing isn't initiated by code in PlayerSprite but is by WorldDisplay's draw( ) method:



public void draw(Graphics g)
// in WorldDisplay
{ g.drawImage(floorIm, xOffset, yOffset, null); // draw floor image
wItems.positionSprites(player, aliens); // add sprites
wItems.draw(g, xOffset, yOffset); // draw things
wItems.removeSprites( ); // remove sprites
}



As explained earlier, all the sprites, including the player, are added to WorldItems temporarily so they can be drawn in the correct z-order. Each sprite is stored as a TileOccupier object, and setPosition( ) and draw( ) are called from there.




Being Hit by an Alien


PlayerSprite maintains a hit counter, which is incremented by a call to hitByAlien( ) from the WorldDisplay object:



public void hitByAlien( )
{ clipsLoader.play("hit", false);
hitCount++;
if (hitCount == MAX_HITS) // player is dead
atPanel.gameOver( );
}



When hitCount reaches a certain value (MAX_HITS), it's all over. The sprite doesn't terminate though; it only notifies AlienTilePanel. This allows AlienTilesPanel to carry out "end of game" tasks, which in this case are reporting the game score and playing a sound clip of applause. AlienTilesPanel could do a lot more, such as ask users if they wanted to play another game. These kinds of game-wide activities should be done at the game panel level and not by a sprite.




Trying to Pick Up a Pickup


The user tries to pick up an item by pressing 2 on the numbers keypad. The hard work here is determining if the sprite's current tile location contains a pickup and to remove that item from the scene. The two operations are handled by WorldDisplay methods:



public boolean tryPickup( )
{
String pickupName;
if ((pickupName = world.overPickup( getTileLoc( ))) == null) {
clipsLoader.play("noPickup", false); // nothing to pickup
return false;
}
else { // found a pickup
clipsLoader.play("gotPickup", false);
world.removePickup(pickupName); // tell WorldDisplay
return true;
}
}



The name of the pickup on the current tile is obtained and used in the deletion request. If the tile is empty, a sound clip will be played instead.










    No comments: