Groovy Invaders III


Welcome to part three of my series. We are going to pick up speed and fill in some more of the blanks in this installment. If you’ve been following along you will have a small amount of code that describes a Game object that is an accelerated graphics canvas with a life cycle loop controlling the high level logic of the game. The would be a Game class definition that looks like this:


package com.craig.groovyinvaders

import java.awt.Canvas

public class Game extends Canvas
{
    def gameRunning = true
    def strategy
    def lastLoopTime = System.currentTimeMillis()

    public Game()
    {
        def container = new groovy.swing.SwingBuilder().frame(title:”Groovy Space Invaders”,
        defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE)
        def panel = container.getContentPane()
        panel.setPreferredSize new Dimension(800, 600)
        panel.setLayout null
        setBounds 0, 0, 800, 600
        panel.add(this)

        setIgnoreRepaint true
        container.pack()
        container.setResizable false
        container.setVisible true

        createBufferStrategy 2
        strategy = getBufferStrategy()
   }

   public Game gameLoop()
   {
       while(gameRunning)
       {
           elapsedTime = calculateElapsedTime()
           processInput()
           display(draw(elapsedTime))
           delay()
       }
       return this
   }

   public static void main(String[] args)
   {
       def g = new Game()
       g.gameLoop()
   }
}


Let me explain a line or two from the above example. First off, regarding code style, you’ll notice in my examples I use a mixture of Java style and Groovy style. I tend to avoid semi-colons because they’re not necessary in Groovy. I also avoid parenthisis around method arguments as I can because they too are optional. You won’t see it in the above example but I may sometimes use GPath expressions and groovy style bean property assignments in places. I don’t do so often because I had a scenario where using them didn’t work as expected and since I want to keep the project moving without senseless debugging I’ll tend to use what I know works. The last thing I’ll mention about style is how I avoid void methods. Every method that declares a void return I change to return the current instance or the “this” reference. That’s just a personal preference of mine and you can use your own discretion here. In the example, there is a call to createBufferStrategy() which is a method on the super class java.awt.Canvas. We pass a literal “2” as the argument. That indicates that we’ll be using double buffering, a technique where graphics are drawn to an offscreen bufferand that buffer is swapped up to the monitor. (The buffering strategy is actually a little more complicated than that but for the purpose of my tutorial that’s as far as we need to know about it.)

Now we’re going to go into the game loop and break it down into a little more detail. I’ll give you the code for two of the easier methods in the game loop first so we can get them out of the way. Figuring out the time elapsed and delaying the loop are two operations where we’ll difference the system time, cache it and tell our current thread to sleep respectively. My code is here:


   def calculateElapsedTime()
   {
       try{ return System.currentTimeMillis() - lastLoopTime }
       finally { lastLoopTime = System.currentTimeMillis() }
   }

   def delay()
   {
       try { Thread.sleep GAME_DELAY }
       catch(Exception e) { println e.getMessage() }
   }


(You’ll want to tuck a definition of our GAME_DELAY constant in the instance variable section of our class file. It should be something like, “def GAME_DELAY = 10 // delay set to 10ms”)

Next I’ll refactor what I said in the part II. (Remember how I told you that method is where I “innovated” and it would change as we moved along?) Here’s what I think the game loop should look like now.


   public Game gameLoop()
   {
       while(gameRunning)
       {
           elapsedTime = calculateElapsedTime()
           processInput()
           display( moveSprites(elapsedTime,draw()) )
           delay()
       }

       return this
   }


I think the above lines up just a little better to what I explained our high level lifecycle logic would be. Most of the code in the while loop is self documenting, but let’s talk about the third line in the while loop. It looks a little out of sequence but I’ll clarify. The third line is concerned with this part of our life cycle logic.

# Move everything based on the time since last loop
# Draw everything on screen
# Swap the buffers over to make the new image visible

Re-wording it a little from the original tutorial I’ll express it this way.

# Draw the background or blank screen
# Tell the sprites to move (They’ll draw themselves)
# Swap the buffers over to make the new image visible

Now for the third line in the while loop. We’ll tackle the “blank the screen” and “swap buffers” part first since they’re simple enough. The draw() method is where we’ll draw a blank screen and return the graphics object for the game sprites to draw themselves on. (That makes sense doesn’t it? A draw() method clears the screen! Of course you’re not going to argue with me here because I’m in the drivers seat. You wouldn’t argue with the pilot on a flight to the Carribeans either would you?) The display() method is where we’ll swap the buffers pulling the back buffer to the screen for display, hence the name “display”. He we go…


   def draw()
   {
       def g = strategy.getDrawGraphics()
       g.setColor Color.black
       g.fillRect 0, 0, 800, 600
       return g
   }

   def display(def graphics)
   {
       graphics.dispose()
       strategy.show()
   }


The next thing we’ll do is describe the movement in our game. Movement logic is interesting because that’s the part of our code that makes things dance across the screen. For now we will use very simple logic that will express our intent. The details will be filled in as we go along. We begin by assuming a list of “entities” that our game will deal with. These “entities” know how to move themselves when asked. They only need to be told how much time has elapsed so they know how far across the screen they should move. We will assume our entities know how to draw themselves as well. Understanding that movement is a matter of updating internal coordinates and drawing is the actual painting of graphics to the screen I come up with code like this:


   def entities = []
   def moveSprites(def elapsedTime, def g)
   {
       entities.each { it.move(elapsedTime) }
       entities.each { it.draw(g) }
       return g
   }


That says that we need to initialize our entity list so for now I’m thinking of something like this…


    public Game()
    {
        //other logic in costructor
        initEntities() //initialize entities at the end
    }

    private void initEntities()
    {
    }


And now we can start talking about what an “entity” is. For all intents and purposes an “entity” is something that will compose a sprite. (In video game speak a “sprite” is an image or graphic that has behaviour or moves or interacts with the player in some way.) For our game the entity will be the Sprite and logic behind the sprite. We come up with an Entity class definition, which will need to know it’s location on screen as well as its direction of movement, or heading. The Entity will also need to hold the “Sprite”, which we will soon define in a separate class as the visual representation of the Entity. The last thing we will put in our Entity is a reference to the Game object so that it can communicate with the game logic as necessary. Our Entity will have a move() method that will update it’s screen coordinates on each call by calculating where it should be based on the elapsed time and the directional speed. It will also contain a draw() method that will be delegated to our Sprite definition.


package com.craig.groovyinvaders

import java.awt.Graphics

public class Entity {

    /** Entity location
    */
    int x,y

    /** Entity movement velocities (specified in pixels per second) */
    def dx = 0 , dy = 0

    /** Entity visual representation */
    Sprite sprite

    /** Reference to the Game object */
    Game game

    public Entity(Game g, String spriteRef, def locX, def locY)
    {
        game = g; sprite = SpriteStore.get().getSprite(spriteRef); x = locX; y = locY;
    }

    public void move(long elapsedTimeMillis) {
        def adjustMillisToSeconds = 1000
        // update the location of the entity based on move speeds
        x += (elapsedTimeMillis * dx) / adjustMillisToSeconds
        y += (elapsedTimeMillis * dy) / adjustMillisToSeconds
    }

    public void draw(Graphics g) {
        sprite.draw(g, x, y)
    }
}


The above implies a SpriteStore class that functions as a singleton Sprite factory. (For the unfamiliar, singleton factories are class definitions with a static member method that’s used for instantiating the factory while the factory itself is merely an indirect way of creating an instance of a particular class. In short, they allow you to enhace the code used to instantiate objects with touching/breaking the code that uses the objects they create.) I use a factory here because, well because the tutorial I’m copying from uses one and I’m too lazy to come up with a better way. So let’s talk about our SpriteStore. It has a couple of important jobs. The store makes sure that only one instance of a SpriteStore is ever created in the VM running the game. It will be our storage facility for all of our sprites so we only need one instance floating around. The store is also responsible for creating and caching sprites for our game to use. The way it will work is on the first request for a sprite the store will create a new Sprite instance and load an image from disk to use for the sprite. All other requests for the same sprite will be served from the cache. Requests will come in the form of a string referencing the relative location of the sprite and to keep things simple I’ll use a HashMap to map the string references to the instantiated objects.


package com.craig.groovyinvaders

import java.awt.Image
import java.util.HashMap

import javax.imageio.ImageIO

public class SpriteStore {
    /** The single instance of this class */
    private static SpriteStore single = new SpriteStore()

    /**
     * Get the single instance of this class
     *
     * @return The single instance of this class
     */
    public static SpriteStore get() {
        return single;
    }
   /** The cached sprite map, from reference to sprite instance */
   private HashMap sprites = new HashMap()

   /**
    * Retrieve a sprite from the store
    *
    * @param ref The reference to the image to use for the sprite
    * @return A sprite instance containing an accelerate image of the request reference
    */
   public Sprite getSprite(String ref) {

        //If we don't have the sprite in cache, create it and put it in cache
      if (false==sprites.containsKey(ref))
          sprites.put(ref, createSprite(ref))

        //Return the sprite from cache
      return sprites.get(ref)
   }

   Sprite createSprite(def ref)
   {
      Image image = loadSpriteImage(ref)

      // create a sprite with the loaded image then return it
      return new Sprite(image)
   }

   Image loadSpriteImage(def ref)
   {
   }

   /**
    * Utility method to handle resource loading failure
    *
    * @param message The message to display on failure
    */
   private void fail(String message) {
      // wasn't available
      // we dump the message and exit the game

      System.err.println(message)
      System.exit(0)
   }
}


We’re getting close now! We have to give special attention to the loadSpriteImage() method. Loading a sprite image involves more than reading a file from disk. We want to use accelerated graphics to hold our image so our loading is done in multiple stages. We load the graphic from disk, we allocate some accelerated graphics memory. then we place our image data into the accelerated graphics memory. Importing java.awt.image.BufferedImage and java.io.IOException into the the SpriteStore I now fill in the loadSpriteImage method.

   Image loadSpriteImage(def ref)
   {
      BufferedImage sourceImage = null

      try {
         // The ClassLoader.getResource() ensures we get the sprite
         // from the appropriate place, this helps with deploying the game
         // with things like webstart. You could equally do a file look
         // up here.
         def url = this.getClass().getClassLoader().getResource(ref)

         if (url == null) {
            fail("Classloader " + this.getClass().getClassLoader() + " can't find ref: "+ref)
         }

         // use ImageIO to read the image in

         sourceImage = ImageIO.read(url)
      } catch (IOException e) {
         fail("Failed to load: "+ref + " " + e)
      }

      // create an accelerated image of the right size to store our sprite in
      GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration()
      Image image = gc.createCompatibleImage(sourceImage.getWidth(),sourceImage.getHeight(),Transparency.BITMASK)

      // draw our source image into the accelerated image
      image.getGraphics().drawImage(sourceImage,0,0,null)

      return image
   }


That’ll do it for now. Come back for the next installment where I’ll define the Sprite class and add some game initialization logic and a few entity definitions. By then we should be able to run what will be a screenshot of the game! (…still with no movement.) Bear with me on my updates to the tutorial as I’m trying to fit in as much as possible between all of the other interesting stuff that has been going on throught my day. Hit me off with any feedback or good ideas as you follow along. I’ll incorporate any good ideas in my posts and we can all learn as we move along. Until next time, holla…

Previous Part Next Part

4 thoughts on “Groovy Invaders III

  1. Hello There, I have some questions…. Can groovy call a java method? What I mean, if i have a java class then i would access its behavior and attributes in groovy. Will that be possible? Hope to hear from you.. Thank you so much.

  2. Yes, Groovy can call Java and vice versa. Groovy is compiled down to Java byte code so it would have direct access to any Java object on the classpath.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s