Colorado State University

CS150: Interactive Programming with Java

Lab 10


The purpose of this lab is


You're going to start creating a game like Zelda. Although we won't have time to finish it, this will give you some ideas how to get started on game programming.

We have a dungeon that is a big image with maps of all the rooms that our player could go through:

We'll only show a small portion of the dungeon at any given time: a 480 by 500 pixel section of the map where the player currently is.

For example, the first room will be displayed as follows:

For the player, we have several images to use for the player. These images are animated, so when we want the player to be walking, it will actually look like the player is walking.
The one that is standing is what we'll display when the player isn't moving.

         

Instructions:

  1. Download and import the image files in to Eclipse.
  2. Develop the Sprite. In game programming, many 2-D games rely on a fundamental class called a Sprite. This keeps track of either players and/or monsters, astroids, or any other type of object that moves around and may or may not collide with other objects.
    The Sprite will be its own class and will keep track of our player.
    1. Create a class named Sprite that extends the JComponent class.
    2. Create our instance variables, as follows:
      • image of type Image the current image of the player
      • stand of type Image the image of the player when standing
      • up of type Image the image of the player when walking upwards
      • down of type Image the image of the player when walking down
      • left of type Image the image of the player when walking left
      • right of type Image the image of the player when walking right
      • x and y of type int to keep track of the x and y coordinates of the player
      • speed of type int to keep track of how fast our player can move (set = to 5)
    3. Create a constructor for the Sprite, as follows:
          public Sprite( Image i, Image u, Image d, Image l, Image r )
          {
              image = i; stand = i;
              up = u; down = d; left = l; right = r;
              x = 0; y=0;
              setOpaque(false);		// ensures transparency
          }
      	

  3. Now lets start creating the main program. Create a new class named GameVersion1.
  4. Add instance variables for the background image, named bkgrnd, the player images (stand,front,back,left,right),
    the player named player of type Sprite, and a variable named thread of type Thread.
    We'll be using threads to enable the animation updating of the game.
  5. To enable this animation, we need to also specify this in a class header, add:
    	implements Runnable
    
    after your class header extends JApplet, e.g.:
    	public class GameVersion1 extends JApplet implements Runnable
    
  6. Create an init method.
  7. Inside the init method,
    1. resize the applet to 480 by 500 for Eclipse
    2. get the image for the background bkgrnd which should be "dungeonMap.gif"
    3. Create an image for the player standing and get the image "stand_front.gif"
    4. Create an image for the player walking back and get the image "walk_back.gif"
    5. Create an image for the player walking left and get the image "walk_left.gif"
    6. Create an image for the player walking right and get the image "walk_right.gif"
    7. Create an image for the player walking front and get the image "walk_front.gif"

    8. With applications using a lot of images, we need to ensure all the images properly load before we go any further. We can do this by using the MediaTracker, as follows.
      First, instantiate the MediaTracker:
              	MediaTracker track = new MediaTracker( this );
      	
      Now add each of the images we want to wait for:
              track.addImage( bkgrnd, 1 ); 	track.addImage( stand, 2);      
      	track.addImage( back, 3 ); 	track.addImage( front, 4 );  
      	track.addImage( left, 5 ); 	track.addImage( right, 6 );
      	
      Note: the numbers are unique IDs necessary for reference specific images in the MediaTracker.

      Now we'll tell the MediaTracker to wait for all the images to load. We need to put this code within a try...catch block in case there is a problem with one of the images.

              try {   track.waitForAll( );
              } catch(Exception e ) { }
      	

    9. Now we can create the player, sending to it all the images for the player:
              player = new Sprite( stand, back, front, left, right );
      	

    10. Before we start, let's set the x and y coordinates of where we want our player to start:
      We can reference the x and y instance variables in our player:
              player.x = 130;
              player.y = 200;
      	

    11. Add the following line to help start out drawing our background image
              getRootPane().getGraphics().drawImage( bkgrnd, 0,0, this );
      	this.setFocusable(true);   // Allow this panel to get focus.
      	

    12. The last thing we need right now in the init method is to start our thread:
      A thread allows us to perform multi-tasking, and is necessary for game animation.
              thread = new Thread(this);
              thread.start( );
      	

  8. In order for us to use Threads, we are now required to write a method named run
    Inside the run method, add the following code:
    	Graphics g = getGraphics( );		// obtains a Graphics object of our applet
    
            while( true )				// loop forever while we're playing
            {
                g.drawImage( bkgrnd,0,0, this);		// draw the background
                g.drawImage( player.image, player.x, player.y, this );	// draw the player at coordinates x,y
                try {					// wait for a bit between drawings
                    Thread.sleep(10);
                } catch( Exception ex ) { stop( ); }
            }
    	

  9. You should be able to run the applet now.
    Do you notice some bad flicker?

To fix the flicker problem

Flicker is a common problem in animation and game programming. The way we fix this is by first drawing the image to a BufferedImage before drawing it to the screen.
  1. To do this, we need to add a new package for accessing these extra image classes:
    	import java.awt.image.*;
    

  2. Inside the run method,
    Change the line with
    	Graphics g = getGraphics( );
    	
    with the following code:
            Graphics gapplet = (Graphics2D )getGraphics( );
            BufferedImage bimg = new BufferedImage( this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB );
            Graphics2D g = bimg.createGraphics();
    
            fullimg = new BufferedImage(bkgrnd.getWidth(null),bkgrnd.getHeight(null), BufferedImage.TYPE_INT_RGB);
            fullg = fullimg.createGraphics();
            fullg.drawImage(bkgrnd, 0,0,this);
    	
    Now, inside the while loop, change the code to have the following:
            while( true )
            {
                BufferedImage bkg = fullimg.getSubimage(0,0, this.getWidth()-1, this.getHeight()-1);
                g.drawImage( bkg, 0,0,  this );	 // draw the background on to the BufferedImage
                g.drawImage( player.image, player.x, player.y, this );	// draw the player
                gapplet.drawImage( bimg, 0,0, this );	// draw the buffered image to the applet
                try { Thread.sleep(10);
                } catch( Exception ex ) { stop( ); }
            }
    	

  3. Also we will add one more method stub:
    	public void update(Graphics g) {      }
    	

  4. Try running the applet now - no more flicker!


    Events - movement

    So far our game is pretty boring. Although we got rid of the flicker, the player can't move yet! So let's enable our player to move around.
    1. Add the four things necessary for events to occur. The event we're interested in is when the user presses certain keys, so we'll be working with the KeyListener.
      add the key listener to the applet
      	public void keyPressed(KeyEvent ke)
      	{
      		
      	}
      	public void keyTyped(KeyEvent ke)
      	{
      		
      	}
      	public void keyReleased(KeyEvent ke)
      	{
      		
      	} 
      	
      		addKeyListener(this);
      	

      Write the stubs for all the required methods.

    2. Now let's look specifically at the keyPressed method.
      Inside this method, we can determine what key the user pressed by finding the key code:
      	 int code = key.getKeyCode( );
      	
      We'll assume the user will use the arrow keys to move around, so let's check for each.
      Write if-else structure for each of the arrow keys.
      The arrow keys can be referenced as:
      		KeyEvent.VK_LEFT 	= left arrow key
      		KeyEvent.VK_RIGHT 	= right arrow key
      		KeyEvent.VK_UP 		= up arrow key
      		KeyEvent.VK_DOWN 	= down arrow key
      	
      For example, to get you started,
      	  if( code == KeyEvent.VK_UP )
      		player.moveUp( );
      	
      Inside the if-else structure, call methods in the player class (which we'll write next!) : moveUp, moveDown, moveLeft and moveRight.

    3. Now go back in to the Sprite class and write the methods for moving: moveUp, moveDown, moveLeft and moveRight.
      Inside each of these methods, move the player by adjusting either the x or y coordinate plus or minus the speed (which is one of your instance variables).
      You also need to set the current image of the player to the correct direction: to either up, down, left or the right image.

    4. Run the program and move the player around!

    5. The last thing we'll do for now is to change the image of the player when he's not moving.
      Inside the Sprite class, add a method named stopMoving and set the image to stand.

      Now inside the GameVersion1 class, in the keyReleased method, call the stopMoving method on the player.

    6. Run the program and move the player around!

    We'll add some code in a later recit/lab to restrict the player to move only within the walls of the room and to move between rooms.

    © 2006 by E.S.Boese All Rights Reserved