Stick Man Game Example

Stick Man Game Example
Computer Science 1710:
Object-Oriented Programming I
Faculty of Engineering & Applied Science
Memorial University of Newfoundland
July 13, 2007
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
1 / 37
1
The stick man game
1
Version 1
1
Version 2
1
Version 3
1
Version 4
1
Version 5
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
2 / 37
The stick man game
Computer games are programs that involve several elements:
Interaction with the user
Carrying out the game’s rules
Modelling the behaviour of non-player characters
Displaying the game world
We will look at a simple “shoot ’em up” game where the player controls a
stick man who runs around the screen. A number of enemy stick men
attempt to attack the player. The player survives and wins by shooting
bullets at his enemies.
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
3 / 37
All of the game’s activities will repeat in a continuous loop. We wish this
loop to run every DELAY milliseconds.
We have not covered sufficient material in this course to understand how
to implement this type of loop. Also, we have not covered the concept of
events generated by interaction with the user.
Therefore, these tasks are delegated to the GameGUI class. We will not
examine this class in detail. The following slide gives the documentation
for the class and its constructor.
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
4 / 37
/∗ ∗
A c l a s s t o s u p p o r t v e r y s i m p l e v i d e o games and o t h e r
interactive applications .
P r o v i d e s a JFrame f o r
g r a p h i c a l d i s p l a y and t h e a b i l i t y t o r e c e i v e t h e
c h a r a c t e r s t y p e d by t h e u s e r when t h e JFrame h a s t h e
focus .
An i n s t a n c e o f GameGUI w i l l c a l l t h e ’ s t e p ’ method o f t h e
Game o b j e c t e v e r y DELAY m i l l i s e c o n d s . The ’ s t e p ’ method
must be d e f i n e d a s f o l l o w s :
p u b l i d v o i d s t e p ( G r a p h i c s g , char key ) ;
where g i s t h e g r a p h i c s c o n t e x t o f t h e GameGUI ’ s JFrame
and k e y i s t h e k e y b o a r d c h a r a c t e r most r e c e n t l y p r e s s e d
by t h e u s e r .
∗/
public class GameGUI
{
/∗ ∗
Constructor .
@param inGame t h e i n s t a n c e o f Game whose ’ s t e p ’ method
w i l l be c a l l e d e v e r y DELAY m i l l i s e c o n d s
@param w i d t h t h e w i d t h o f t h e JFrame i n p i x e l s
@param h e i g h t t h e h e i g h t o f t h e JFrame i n p i x e l s
@param t i t l e t h e t e x t t o a p p e a r i n t h e t i t l e b a r o f
t h e JFrame
∗/
public GameGUI ( Game inGame , int width , int height ,
String title ) {
...
Version 1
We can illustrate the use of GameGUI by providing an initial Game class:
public class Game
{
public Game ( ) {
gameGUI = new GameGUI ( this , WIDTH , HEIGHT ,
" Stick Man Game " ) ;
}
...
/∗ ∗
T h i s method i s c a l l e d from t h e GameGUI o b j e c t t o
i n d i c a t e t h a t t h e game s h o u l d move a l o n g by one s t e p .
@param g t h e g r a p h i c s c o n t e x t f o r d r a w i n g game
elements into
@param k e y t h e k e y p r e s s j u s t made by t h e u s e r .
’ \ 0 ’ i n d i c a t e s t h a t no k e y was p r e s s e d .
∗/
public void step ( Graphics g , char key )
{
System . out . println ( " Step called . key : " + key ) ;
}
private GameGUI gameGUI ;
private static final int WIDTH = 6 0 0 ;
private static final int HEIGHT = 6 0 0 ;
}
DEMO VERSION 1
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
9 / 37
Version 2
We will now add the necessary code to control the player’s stick man.
First, we will represent a stick man using the StickMan class from
assignment 3. This class has been modified as follows:
The parameters to the constructor have changed:
public StickMan ( int x , int y , int w , int h , Color col )
where (x, y ) is the position of the upper-left corner of the stick man,
w and h are his width and height, and col is his colour.
The following methods have been added:
public void translate ( int dx , int dy )
{
xLeft = xLeft + dx ;
yTop = yTop + dy ;
}
public Rectangle getBoundingBox ( )
{
return new Rectangle ( xLeft , yTop , width , height ) ;
}
The Game class needs to be modified to add the player:
public Game ( ) {
// The p l a y e r s t a r t s i n t h e c e n t r e o f t h e s c r e e n
player = new StickMan ( WIDTH / 2 , HEIGHT / 2 , 2 0 , 2 0 ,
Color . BLUE ) ;
gameGUI = new GameGUI ( this , WIDTH , HEIGHT ,
" Stick Man Game " ) ;
}
The following instance fields are added:
private StickMan player ;
private static final int PLAYER_ACCEL = 3 ;
The step method calls a new method called handleInput to handle the
user’s key presses and control the player’s stick man. We then draw the
stick man:
public void step ( Graphics g , char key )
{
Graphics2D g2d = ( Graphics2D ) g ;
handleInput ( key ) ;
player . draw ( g2d ) ;
}
is not to be called from outside the class. It is private to the
Game class and is therefore declared private not public...
handleInput
/∗ ∗
C o n t r o l t h e p l a y e r a c c o r d i n g t o t h e u s e r ’ s command .
@param k e y an i n p u t c h a r a c t e r from t h e u s e r
∗/
private void handleInput ( char key )
{
if ( key == ’8 ’ )
{
player . translate ( 0 , −PLAYER_ACCEL ) ;
}
else if ( key == ’6 ’ )
{
player . translate ( PLAYER_ACCEL , 0 ) ;
}
else if ( key == ’2 ’ )
{
player . translate ( 0 , PLAYER_ACCEL ) ;
}
else if ( key == ’4 ’ )
{
player . translate(−PLAYER_ACCEL , 0 ) ;
}
}
DEMO VERSION 2
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
14 / 37
Version 3
Next we will add the player’s enemies. The new constructor:
public Game ( ) {
random = new Random ( ) ;
// The p l a y e r s t a r t s i n t h e c e n t r e o f t h e s c r e e n
player = new StickMan ( WIDTH / 2 , HEIGHT / 2 , 2 0 , 2 0 ,
Color . BLUE ) ;
(cont’d...)
// C r e a t e e n e m i e s
enemies = new ArrayList<StickMan > ( ) ;
final double radius = 0 . 3 7 5 ∗ WIDTH ;
for ( int i = 0 ; i < NUMBER_ENEMIES ; i++) {
// The enemy ’ s p o s i t i o n w i l l be r a n d o m l y s e l e c t e d t o
// l i e on a c i r c l e o f r a d i u s 0 . 3 7 5 ∗ WIDTH, c e n t r e d
// on p o s i t i o n (WIDTH/ 2 , HEIGHT / 2 ) . The r a n d o m n e s s
// comes from s e l e c t i n g a random a n g l e b e t w e e n 0 and
// 2∗ p i r a d i a n s w h i c h g i v e s t h e enemy ’ s p o s i t i o n on
// t h e c i r c l e .
double angle = 2 ∗ Math . PI ∗ random . nextDouble ( ) ;
int randX = WIDTH / 2 + ( int ) ( radius ∗ Math . cos ( angle ) ) ;
int randY = HEIGHT / 2 + ( int ) ( radius ∗ Math . sin ( angle ) ) ;
StickMan enemy = new StickMan ( randX , randY , 3 0 , 3 0 ,
Color . RED ) ;
enemies . add ( enemy ) ;
}
gameGUI = new GameGUI ( this , WIDTH , HEIGHT ,
" Stick Man Game " ) ;
We must add the following instance fields that pertain to the enemies:
Random random ;
ArrayList<StickMan> enemies ;
private static final int NUMBER_ENEMIES = 3 ;
private static final int ENEMY_ACCEL = 2 ;
We add one method call to step:
public void step ( Graphics g , char key )
{
Graphics2D g2d = ( Graphics2D ) g ;
handleInput ( key ) ;
player . draw ( g2d ) ;
moveAndDrawEnemies ( g2d ) ;
}
/∗ ∗
Move t h e e n e m i e s t o w a r d s t h e p l a y e r ’ s s t i c k man . Redraw
them a l l i n t h e i r new p o s i t i o n s .
∗/
private void moveAndDrawEnemies ( Graphics2D g2d )
{
for ( StickMan enemy : enemies )
{
// D e t e r m i n e t h e d i r e c t i o n i n w h i c h t h e enemy s h o u l d
// move t o a p p r o a c h t h e p l a y e r d i r e c t l y .
double vx = player . getX ( ) − enemy . getX ( ) ;
double vy = player . getY ( ) − enemy . getY ( ) ;
double distance = Math . sqrt ( vx ∗ vx + vy ∗ vy ) ;
int dx = ( int ) ( ENEMY_ACCEL ∗ vx / distance ) ;
int dy = ( int ) ( ENEMY_ACCEL ∗ vy / distance ) ;
enemy . translate ( dx , dy ) ;
enemy . draw ( g2d ) ;
}
}
DEMO VERSION 3
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
20 / 37
Version 4
The next step is to allow the player to launch bullets. We create a new
Bullet class to represent bullets. This class is similar to the StickMan class:
The constructor:
/∗ ∗
C o n s t r u c t s a b u l l e t w i t h t h e u p p e r l e f t −hand c o r n e r o f i t s
b o u n d i n g box a t t h e g i v e n c o o r d i n a t e s .
@param x t h e x c o o r d i n a t e o f t h e t o p l e f t −hand c o r n e r
@param y t h e y c o o r d i n a t e o f t h e t o p l e f t −hand c o r n e r
@param r t h e r a d i u s o f t h e b u l l e t
@param vx t h e x component o f t h e b u l l e t ’ s v e l o c i t y
@param vy t h e y component o f t h e b u l l e t ’ s v e l o c i t y
@param c o l t h e c o l o u r o f t h e b u l l e t
∗/
public Bullet ( int x , int y , int r , int vx , int vy , Color col )
{
xLeft = x ;
yTop = y ;
radius = r ;
xVel = vx ;
yVel = vy ;
color = col ;
// The f o l l o w i n g v a r i a b l e s a r e u s e d t o a n i m a t e t h e b u l l e t .
baseRadius = r ;
deltaRadius = r / 2 ;
shrinking = true ;
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
22 / 37
/∗ ∗
Move t h e b u l l e t a l o n g a c c o r d i n g t o t h e v e l o c i t y s p e c i f i e d i n
the c o n s t r u c t o r .
∗/
public void move ( )
{
xLeft = xLeft + xVel ;
yTop = yTop + yVel ;
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
23 / 37
public void draw ( Graphics2D g2 )
{
Ellipse2D . Double body = new Ellipse2D . Double ( xLeft , yTop ,
radius , radius ) ;
g2 . setColor ( color ) ;
g2 . fill ( body ) ;
// M o d i f y t h e r a d i u s t o c r e a t e a c r u d e s o r t o f a n i m a t i o n
if ( shrinking ) {
radius −−;
if ( radius == baseRadius − deltaRadius )
shrinking = false ;
} else {
radius++;
if ( radius == baseRadius + deltaRadius )
shrinking = true ;
}
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
24 / 37
Now look at the constructor of the Game class again...
public Game ( ) {
random = new Random ( ) ;
// The p l a y e r s t a r t s i n t h e c e n t r e o f t h e s c r e e n
player = new StickMan ( WIDTH / 2 , HEIGHT / 2 , 2 0 , 2 0 , Color . BLUE )
// C r e a t e e n e m i e s
...
// C r e a t e A r r a y L i s t o f b u l l e t s ( i n i t i a l l y empty )
bullets = new ArrayList<Bullet > ( ) ;
direction = UP ;
gameGUI = new GameGUI ( this , WIDTH , HEIGHT ,
" Stick Man Game " ) ;
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
25 / 37
The following instance fields are added:
ArrayList<Bullet> bullets ;
private int direction ;
private static final int BULLET_SPEED = 4 ;
private static final int UP = 1 ;
private static final int RIGHT = 2 ;
private static final int DOWN = 3 ;
private static final int LEFT = 4 ;
gives the last movement direction of the player. Bullets will be
launched in this direction.
direction
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
26 / 37
public void step ( Graphics g , char key )
{
Graphics2D g2d = ( Graphics2D ) g ;
handleInput ( key ) ;
player . draw ( g2d ) ;
moveAndDrawEnemies ( g2d ) ;
moveAndDrawBullets ( g2d ) ;
}
moveAndDrawBullets
COMP 1710 (MUN)
has been added. Also handleInput has changed...
Stick Man Game
July 13, 2007
27 / 37
private void handleInput ( char key )
{
if ( key == ’8 ’ )
{
direction = UP ;
player . translate ( 0 , −PLAYER_ACCEL ) ;
}
else if ( key == ’6 ’ )
{
direction = RIGHT ;
player . translate ( PLAYER_ACCEL , 0 ) ;
}
. . . similarly for left and right movement . . .
else if ( key == ’ ’ )
{
fire ( ) ;
}
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
28 / 37
/∗ ∗
C r e a t e a new b u l l e t moving i n t h e d i r e c t i o n t h a t t h e p l a y e r
was l a s t moving i n .
∗/
private void fire ( )
{
int xVel = 0 , yVel = 0 ;
if ( direction == UP )
yVel = −BULLET_SPEED ;
else if ( direction == RIGHT )
xVel = BULLET_SPEED ;
else if ( direction == DOWN )
yVel = BULLET_SPEED ;
else if ( direction == LEFT )
xVel = −BULLET_SPEED ;
Bullet bullet = new Bullet ( player . getX ( ) , player . getY ( ) ,
5 , xVel , yVel , Color . GREEN ) ;
bullets . add ( bullet ) ;
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
29 / 37
/∗ ∗
Move t h e b u l l e t s a c c o r d i n g t o t h e i r e x i s t i n g v e l o c i t i e s .
Get r i d o f any b u l l e t s t h a t h a v e l e f t t h e s c r e e n and
redraw a l l of the remaining b u l l e t s .
∗/
private void moveAndDrawBullets ( Graphics2D g2d )
{
// Move t h e b u l l e t s
for ( Bullet bullet : bullets )
bullet . move ( ) ;
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
30 / 37
// Some b u l l e t s w i l l h a v e moved o f f s c r e e n . Get r i d o f them .
int i =0;
while ( i < bullets . size ( ) )
{
Bullet bullet = bullets . get ( i ) ;
int x = bullet . getX ( ) ;
int y = bullet . getY ( ) ;
if ( x < 0 | | x >= WIDTH | | y < 0 | | y >= HEIGHT )
bullets . remove ( i ) ;
else
i++;
}
// Draw t h e s u r v i v i n g b u l l e t s
for ( Bullet bullet : bullets )
bullet . draw ( g2d ) ;
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
31 / 37
DEMO VERSION 4
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
32 / 37
Version 5
Finally, we add code to handle collisions. We also add the rules for scoring
and for terminating the game. Each type of collision results in a different
response:
Player / enemy collision: The game ends. The current score is
printed.
Bullet / enemy collision: Both the bullet and the enemy are
deleted. The score is increased by one.
All other types of collision (player / bullet, enemy / enemy) are ignored.
The game will also end if all enemies have been destroyed.
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
33 / 37
The only new instance field is an int called score. It is initialized to 0 in
the constructor.
The following is the complete code for step:
public void step ( Graphics g , char key )
{
Graphics2D g2d = ( Graphics2D ) g ;
handleInput ( key ) ;
player . draw ( g2d ) ;
moveAndDrawEnemies ( g2d ) ;
moveAndDrawBullets ( g2d ) ;
handleCollisions ( ) ;
if ( enemies . size ( ) == 0 )
{
System . out . println ( " You win !" ) ;
System . out . println ( " Score : " + score ) ;
System . exit ( 0 ) ;
}
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
34 / 37
/∗ ∗
H a n d l e c o l l i s i o n s b e t w e e n t h e e n e m i e s and t h e p l a y e r , and
b e t w e e n t h e b u l l e t s and t h e e n e m i e s . A c o l l i s i o n b e t w e e n
t h e p l a y e r and an enemy w i l l t e r m i n a t e t h e game . Any
c o l l i s i o n b e t w e e n a b u l l e t and an enemy w i l l c a u s e t h e
enemy t o be removed and w i l l i n c r e a s e t h e p l a y e r ’ s s c o r e .
∗/
private void handleCollisions ( )
{
// Check f o r c o l l i s i o n b e t w e e n e n e m i e s and t h e p l a y e r
for ( StickMan enemy : enemies )
{
if ( player . getBoundingBox ( ) . intersects (
enemy . getBoundingBox ( ) ) )
{
System . out . println ( " Game Over " ) ;
System . out . println ( " Score : " + score ) ;
System . exit ( 0 ) ;
}
}
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
35 / 37
// Check f o r c o l l i s i o n b e t w e e n t h e b u l l e t s and t h e e n e m i e s
int bulletIndex = 0 ;
while ( bulletIndex < bullets . size ( ) )
{
Bullet bullet = bullets . get ( bulletIndex ) ;
boolean hit = false ;
int enemyIndex = 0 ;
while ( ! hit && enemyIndex < enemies . size ( ) )
{
StickMan enemy = enemies . get ( enemyIndex ) ;
if ( bullet . ge tB ou ndi ng Bo x ( ) . intersects (
enemy . ge tB oundi ngBo x ( ) ) )
{
score = score + 1 ;
enemies . remove ( enemyIndex ) ;
hit = true ;
}
else
enemyIndex++;
}
if ( hit )
bullets . remove ( bulletIndex ) ;
else
bulletIndex++;
}
}
DEMO VERSION 5
COMP 1710 (MUN)
Stick Man Game
July 13, 2007
37 / 37