Home Game Development Creative Greenfoot

Creative Greenfoot

By Michael Haungs
books-svg-icon Book
eBook $39.99 $27.98
Print $48.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $39.99 $27.98
Print $48.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Let's Dive Right in…
About this book
Publication date:
April 2015
Publisher
Packt
Pages
310
ISBN
9781783980383

 

Chapter 1. Let's Dive Right in…

 

"It does not matter how slowly you go as long as you do not stop."

 
 --Confucius

In this chapter, you will build a simple game where the player controls a character using the mouse to try to avoid oncoming enemies. As the game progresses, the enemies become harder to avoid. This game contains many of the basic elements needed to create interactive Greenfoot applications. Specifically, in this chapter, you will learn how to:

  • Create introduction and game-over screens

  • Display a user score

  • Use the mouse to control the movement of an actor

  • Play background music

  • Dynamically spawn enemies and remove them when appropriate

  • Create game levels

Throughout this chapter, we'll learn basic programming concepts and gain familiarity with the Greenfoot development environment. As you proceed, think about the concepts presented and how you would use them in your own projects. If you are new to Java, or it's been a while since you've programmed in Java, be sure to take the time to look up things that may be confusing to you. Java is a well-established programming language, and there are endless online resources you can consult. Similarly, this book assumes a minimal understanding of Greenfoot. Be sure to look at the simple tutorials and documentation at www.greenfoot.org when needed. Experiment with the code and try new things—you'll be glad you did. In other words, follow the advice of Confucius, quoted in the first line of this chapter.

Many of the chapters in this book are independent; however, most are dependent on this chapter. This chapter provides the framework to create Greenfoot applications that we will continue to use, and refer to, in later chapters.

 

The Avoider Game tutorial


This tutorial is heavily based on AS3 Avoider Game Tutorial by Michael James Williams (http://gamedev.michaeljameswilliams.com/as3-avoider-game-tutorial-base/). In that tutorial, you build a game that creates smiley-faced enemies that rain down from the top of the screen. The goal for the player is to avoid these enemies. The longer you avoid them, the higher your score. We will build the same game in Greenfoot, instead of Flash and ActionScript. As with Michael James Williams' tutorial, we will start small and slowly layer on functionality. We will pause frequently to consider best practices and good programming practice. Enjoy these learning opportunities!

We will first build the basic components of the Avoider game, including the initial scenario, the game environment, the enemies, and the hero. Then, we will layer on additional functionality, such as scoring, introduction and game-over screens, and the notion of levels.

As mentioned in the preface, we'll assume you have downloaded Greenfoot and have it installed. If you still haven't, do so now. Go to www.greenfoot.org for easy-to-follow instructions on downloading and installing Greenfoot. While you are there, make sure you are minimally familiar with all the tutorials provided on http://www.greenfoot.org/doc.

 

Basic game elements


All games have an environment in which the game takes place and objects interact. In Greenfoot, the environment is represented by the World class, and objects that interact in the environment are represented by the Actor class. In this section of the chapter, we will create a world, add enemies to the world, and add a hero that will be controlled by the player.

Creating a scenario

Start Greenfoot and create a new scenario by clicking on Scenario in Greenfoot's Menu bar and then clicking on New…. You will see the window shown in Figure 1. Type AvoiderGame as the name of the file, and then hit the Create button.

Figure 1: Here's Greenfoot's New Scenario window

Creating our world

Next, we need to create a world for our game. We do this by right-clicking (or ctrl-clicking on Mac) on the World class in the scenario window (see Figure 2) and choosing New subclass... in the pop-up menu that appears.

Figure 2: This is about right-clicking on the World class in order to subclass it

In the New class pop-up window, name the class AvoiderWorld, select the backgrounds image category, and then select the space1.jpg library image as the new class image. Once this is done, the pop-up window should resemble Figure 3.

Tip

Once you associate an image with a new World class or Actor class, that image will be copied to the images directory in your Greenfoot project. We will count on this in later chapters.

Figure 3: This shows the New class pop-up window

Hit the Ok button in the New class pop-up window, and then, in the main scenario window, hit the Compile button. You should now have a scenario that looks like that shown in Figure 4.

Figure 4: This shows our AvoiderGame scenario after compiling the AvoiderWorld class

We now have our own world, named AvoiderWorld, which we will soon populate with actors.

Tip

Later in this chapter, we will add two subclasses of World to our game—one for our introduction screen and one for our game-over screen. Those instructions will be abbreviated. Be sure to refer back to this section if you need detailed instructions on subclassing the World class.

Creating our hero

Let's create the character our players will control when they play our game. Greenfoot makes this really easy. We will just follow the same steps we used to create the World class earlier. Start by right-clicking on the Actor class in the scenario window (see Figure 5) and choose the New subclass... menu item.

Figure 5: This shows right-clicking on the Actor class in order to subclass it

In the New class pop-up window, name the class Avatar and select symbols->skull.png as the new class image. In the main scenario window, hit the Compile button.

Now, to create an enemy, you perform the same steps you just did for the hero, except choose symbols->Smiley1.png as the image and Enemy as the class name. Again, hit the Compile button when this is done.

You should now have a scenario that looks like the one shown in Figure 6.

Figure 6: This shows the Avoider Game scenario after creating the world and adding two actors

What have we just done?

Greenfoot views a scenario as World that contains Actor. The main responsibilities of World is to add and remove each Actor from the screen and to periodically call the act() method of each Actor. It is the responsibility of each Actor to implement their act() method to describe their actions. Greenfoot provides you with the code that implements general World and Actor behavior. (You right-clicked on those implementations previously.) As a game programmer, you must code specific behaviors for World and Actor. You do this by subclassing the provided World and Actor classes to create new classes and writing code in them. You have already done the subclassing, and now it is time to add the code.

Tip

Look at http://www.greenfoot.org/files/javadoc/ to learn more about the World and Actor classes.

Oracle provides an excellent overview of object-oriented programming concepts at http://docs.oracle.com/javase/tutorial/java/concepts/. If you are serious about learning Java and writing good Greenfoot scenarios, you should read that material.

Adding our hero

Last, we need to add our hero to the game. To do this, right-click on the Avatar class, select new Avatar() from the pop-up menu, drag the picture of the skull that appears collocated with your mouse pointer to the center of the screen and then click the left mouse button. Now, right-click anywhere on the black space background (do not right-click on the skull) and choose Save the world in the pop-up menu that appears.

Doing this will permanently add our hero to the game. If you hit the Reset button on Greenfoot's scenario window, you should still see the skull you placed in the middle of the screen.

Using the mouse as a game controller

Let's add some code to the Avatar class that will allow us to control its movement using the mouse. Double-click on Avatar to pull up the code editor (You can also right-click on the class and select Open editor).

You will see a code-editing window appear that looks as shown in Figure 7.

Figure 7: This is the code for our Avatar class

You can see the act() method we discussed earlier. Because there is no code in it, Avatar will not move or display any other behavior when we run our scenario. What we would like, is to have Avatar follow the mouse. Wouldn't it be nice if there was a followMouse() method we could use? Let's pretend there is! Inside the act() method, type followMouse();. Your act() method should look like Figure 8.

Figure 8: This shows the act() method with the followMouse() function added

Just for fun, let's compile this and see what happens. What do you think will happen? Click the Compile button to find out. Did you see something like what is shown in Figure 9?

Figure 9: This is about viewing a compilation error in Greenfoot

If you look at the bottom of the window in Figure 9, you'll see that Greenfoot has provided us with a useful error message and has even highlighted the code that has the problem. As we know, we were pretending that the method followMouse() existed. Of course, it does not. We will, however, write it soon. Throughout the course of this manual (and during any Java coding), you are going to make errors. Sometimes, you'll make a "typo" and at other times, you'll use a symbol that doesn't exist (just as we did earlier). There are other common errors you will make as well.

Note

Help! I just made a programming error!

Don't panic! There are a number of things you can do to remedy the situation. I will list some here. First and foremost, the process you use to code can greatly aid you in debugging code (finding errors). The process you should follow is called Incremental Development. Simply follow these steps:

  • Code a couple of lines of code. (Really!! Don't code any more!)

  • Save and compile.

  • Run and test your code. (Really!! Try it out!)

  • Repeat.

Now, if you get an error, it has to be due to the last 2-5 lines of code you just wrote. You know exactly where to look. Compare this to writing 30 lines of code and then testing them out. You will have compounding bugs that are hard to find. Here are some other debugging tips:

  • Very carefully read the error message you get. While they can be cryptic, they really do point you to the location of the bug (sometimes even giving line numbers).

  • Sometimes, you get multiple, long error messages. Don't worry. Just go to the top and read and deal with only the first one. Often, by fixing the first one, many others will be taken care of too.

  • If you just can't find it, have someone else read your code. It's amazing how fast someone else can spot your error.

  • Print some information out. You can use System.out.println() to print out variables and check that the code you are looking at is actually running.

  • Learn how to use a debugger. This is a very useful tool, but beyond the scope of this book. Learn what a debugger is and use it. Greenfoot has a nice, built-in debugger you can use.

In the extremely rare case that there is an error in the Greenfoot program, report it by following the instructions found at http://www.greenfoot.org/support.

Creating the followMouse function

Ok, let's get back to our hero. We last left our hero (the Avatar class) with an error, because there was actually no followMouse() method. Let's fix that. Add the method shown in the following code after the act() method in the Avatar class:

private void followMouse() {
  MouseInfo mi = Greenfoot.getMouseInfo();
  if( mi != null ) {
    setLocation(mi.getX(), mi.getY());
  }
}

We now have an implementation of followMouse(). Save the file, compile the Greenfoot scenario, and try the code out. The picture of the skull should follow your mouse. If something went wrong, look closely at the debugging window (shown in Figure 9) to see the clues Java is giving you about your error. Did you mistype something? Verify that the code in your Avatar class looks exactly like the code in Figure 10. Follow the debugging tips provided earlier.

Figure 10: This shows the Avatar class with completed followMouse() method

Hey, wait! How did I come up with the code for the followMouse() method? Was I born with that information? No, I actually just looked over the Greenfoot documentation (http://www.greenfoot.org/files/javadoc/) and saw there was a class named MouseInfo. I clicked on that and read about all of its methods.

Tip

Go read the Greenfoot documentation now. It's actually pretty short. There are only seven classes and each only has around 20, or fewer, methods.

Breaking down the code

Let's break down this code. First, we get access to an object that represents mouse data via Greenfoot.getMouseInfo(). We then use that object to get the location of the mouse, via getX() and getY(), and then set the x and y locations of our hero using setLocation(x,y). How did I know to use setLocation()? Again, it is in the Greenfoot documentation for the Actor class. It is a method that Greenfoot provides for all actors. Last, we had to include the if(mi != null) part because if you accidentally move the mouse outside the Greenfoot window, there will be no mouse information, so trying to access it will cause an error (check out the comment in the code in Figure 10, line 22).

Since the followMouse() method is called in the act() method, our hero will continually be moved to the location of the mouse.

Tip

When typing a method in Greenfoot, you can hit Ctrl + space bar and Greenfoot will display a list of potential methods you may have been trying to write. Select a method from the list and Greenfoot will autocomplete the method for you, including space holders for method parameters.

Adding enemies

We're going to add enemies to our game in two steps. First, we need to write the code for the Enemy class, and then we will add code to our world, AvoiderWorld, to create a never-ending army of enemies. Both steps are surprisingly simple.

Enemy code

Double-click on the Enemy class and change its act() method to look like the following code snippet:

public void act() {
  setLocation(getX(), getY() + 1);
}

Remember using setLocation() earlier in the Avatar class? We use it again here to move an enemy down one pixel every time the act() method is called. In Greenfoot, the upper-left corner of the screen is the coordinate (0,0). The x coordinate increases as you move to the right and the y coordinate increases as you move down. That is why we set the x location of the enemy to be its current x coordinate value (we are not moving to the left or the right) and its y location to be its current y coordinate plus one (we are moving down one pixel.)

Save your Enemy class, and then compile your scenario. Run the scenario, right-click on the Enemy class, and choose new Enemy() in the pop-up menu. Add this enemy to the screen and watch it move down.

Creating an army

Now that we have completed our Enemy class, we can use it to create an army. To do this, we are going to add code to the act() method in our AvoiderWorld class. Open the editor for AvoiderWorld by double-clicking on it, or right-clicking on it and selecting Open editor in the pop-up menu. If you look around the code for AvoiderWorld, you'll notice that Greenfoot does not automatically create an act() method for you. No problem, we'll just add it. Put the following code in AvoiderWorld:

public void act() {
  // Randomly add enemies to the world
  if( Greenfoot.getRandomNumber(1000) < 20 ) {
    Enemy e = new Enemy();
    addObject(e, Greenfoot.getRandomNumber(getWidth()-20)+10, -30);
  }
}

The act() method starts by checking whether a randomly generated number between 0 and 1000, including 0 but not 1000, was less than 20. In the long run, this code will run 2 percent of the times the act() method is called. Is this enough? Well, the act() method is typically called 50 times per second (ranges from 1 to 100, depending on the position of the speed slider bar), so 2 percent of 50 is 1. Therefore, on average one enemy will be created per second. This feels about right for the starting level of our game.

Inside the if statement, we create an enemy and place it at a specific location in the world using the method addObject(). The addObject() method takes three parameters: the object to add, the x coordinate of the object, and the y coordinate of the object. The y coordinate is constant and chosen so that the newly created enemy starts off at the top of the screen and will appear as it slowly moves down. The x coordinate is trickier. It is dynamically generated so that the enemy could appear on any valid x coordinate on the screen. The following is the code we are talking about:

Greenfoot.getRandomNumber( (getWidth() – 20) + 10, -30);

Figure 11 demonstrates the range of x coordinate values that are generated. In this figure, the rectangles represent the possible set of values for the x coordinate for the given code. This method of generating ranges of values for screen coordinates is common in Greenfoot.

Figure 11: This is the range of x coordinate values generated by the code

Compile and run the scenario; you should see a continuous stream of enemy hordes moving down the screen.

Unbounding the world

After running the scenario, you'll notice that the enemies end up piling up at the bottom of the screen. In Greenfoot, you can create worlds that are bounded (where actors are not allowed to go past the screen borders) and unbounded (where actors are allow to exit the screen.) By default, Greenfoot creates bounded worlds. However, changing the world to unbounded is extremely easy. Double-click on AvoiderWorld to open the code editor. Take this line of code:

super(600, 400, 1);

Change the preceding code to the following line of code:

super(600, 400, 1, false);

Looking at the Greenfoot documentation for the World class, we notice there are two constructors (see http://www.greenfoot.org/files/javadoc/greenfoot/World.html for detailed information on these constructors): one that takes three parameters and another that takes four. The constructor with four parameters has the same parameters as the one that takes three, plus one additional boolean parameter that indicates whether the world is bounded or not. Our code change added the fourth Boolean parameter and set it to false (no bounds in the world.)

Now, compile and run the scenario. The enemies fall off the bottom of the screen as required.

Where do all those enemies go? We'll deal with that next.

Memory management

In Greenfoot applications, you'll create hundreds and thousands of actors. When we are done with an actor, such as when it is killed or goes off screen, we would like to remove that object and not have it consume any more system resources. Java manages memory resources via a method called garbage collection. With this method, Java tries to automatically determine whether you no longer need an actor, and if you don't, it deletes that actor and frees up all resources associated with it. In Greenfoot, you can let Java know you are done with the actor by removing it from World using the removeObject() method. This is what we want to do to an Enemy actor, after we have successfully avoided it and it has moved off the screen.

The most convenient place to remove an Enemy, after it has gone off the screen, is within the Enemy class itself. Add the following code as the last line of code inside the act() method in the Enemy class:

checkRemove();

Now, we need to add the checkRemove() method. Put the definition of this method below the act() method. Here is the definition:

private void checkRemove() {
  World w = getWorld();
  if( getY() > w.getHeight() + 30 ) {
    w.removeObject(this);
  }
}

The code for your Enemy class should look like that shown in Figure 12.

Figure 12: This shows the adding of code to remove the enemy if it goes off the bottom of the screen

Now, compile and run the scenario. The enemies fall of the bottom of the screen, as before, but you can feel good knowing that they are soon removed from the world and the garbage is collected.

Your assignment

Learning is not passive, and you really need to engage in the process. Before moving on to the next section of this chapter, you should:

  1. Make sure your version of our Avoider Game works, click on Scenario in Greenfoot's main application menu, and then choose Save as… to create an experimental copy of Avoider Game. Let's name this experimental copy AvoiderGameIExperimentation.

  2. Play around with your experimental copy. Change the spawn rates of the enemies. Change how fast the enemies descend.

  3. Add turn(5); to the act() method of the Enemy class. Compile and run. What's going on? Try different values instead of 5 as the input parameter to turn().

If things get too crazy, delete your experimental copy and make a new copy to play with from our original Avoider Game. There's no harm done, nor any foul.

Tip

Throughout this book, take this approach of experimenting with the code. Much learning will happen during the playing. The very act of thinking about how to change the code provides your brain with a new way to process and understand it. Making mistakes in a controlled environment will better prepare you to handle mistakes later on. You will start to become familiar with Greenfoot's error messages.

Next…

Great work until now! We have built the basics of our game and will next add some things, such as an introduction screen, game-over screen, and a score, to make it look and feel more like a game.

Making it a game

In this section, we will add a game-over screen, an introduction screen, and some background music. But, before we do all that, we need to know when our hero touches one of the enemies. This will be our cue to end the game. The act of determining when two actors touch is called collision detection. Collision detection is used to tell whether a bullet hit an enemy, whether the player landed on a platform after jumping, or to tell whether a falling leaf landed on a surface. We will discuss this important topic next and spend considerable time on it in the upcoming chapters.

Detecting collisions

Greenfoot provides several Actor methods you can use to determine whether you are touching another Actor. These methods, in no particular order, are: getIntersectingObjects(), getNeighbors(), getObjectsAtOffset(), getObjectsInRange(), getOneIntersectingObject(), and getOneObjectAtOffset(). They all provide slightly different ways of determining collision. For our game, we are going to use getOneIntersectingObject(). The prototype of this method is as follows:

protected Actor getOneIntersectingObject(java.lang.Class cls)

This method takes one parameter, which is the class of the objects you want to check for collision. This method defines collision in terms of bounding boxes; a bounding box is the minimal rectangle that can surround all pixels in the graphic. This method is efficient and fast, but not the most accurate. In Figure 12, we can see a picture of a skull and a picture of a smiley face. Even though the pixels of the two pictures are not overlapping, we can see that their bounding boxes are overlapping; therefore, getOneIntersectingObject() would report that these two actors are touching. In Chapter 3, Collision Detection, we will explore more advanced methods of collision detection.

Figure 13: This shows the bounding boxes of two actors

Armed with this new information, we are going to add collision detection to our Avatar class. We will remove our hero from the game if it touches one of the enemies. (Later in this chapter, we will display a game-over screen after removing our hero.) Double-click on the Avatar class to bring up its editing window. Change its act() method to this:

public void act() {
 followMouse();
 checkForCollisions();
}

Then, add this checkForCollisions() method's definition under the act() method:

private void checkForCollisions() {
  Actor enemy = getOneIntersectingObject(Enemy.class);
  if( enemy != null ) {
    getWorld().removeObject(this);
    Greenfoot.stop();
  }
}

The Avatar class should look like the code shown in Figure 14.

Figure 14: The Avatar class with collision detection added.

Let's examine exactly what's going on in the checkForCollisions() method. The first thing we do is call getOneIntersectionObject() and save its return value in the variable enemy. This variable will be null if this object is not touching any enemies, in which case, the expression in the if statement will evaluate to false, and we will not execute the statements inside. Otherwise, we are touching an object of the type Enemy and do execute the contents of the if statement.

There are only two lines of code in the if statement. In the first line, we use the method getWorld(), implemented in the Actor class, to get a reference to the instance of the World we are in. Instead of saving the reference in a variable, we immediately invoke the World method removeObject() supplying the keyword this as the argument to remove our hero. Lastly, we use the stop() method in the Greenfoot utility class to pause our game.

Now, compile and run the scenario. Enemies should stream down from the top of the screen and exit out at the bottom. You should be able to control the hero, an instance of the Avatar class, by moving your mouse. If our hero touches one of the enemies, the game should stop.

Adding a game-over screen

First, you need to draw an entire game-over screen in your favorite graphic design/drawing program, such as GIMP, CorelDRAW, Inkscape, Greenfoot's built-in graphic editor, or even Windows Paint. I used Adobe Illustrator to create the screen shown in Figure 15.

Figure 15: My AvoiderGame game-over screen; try designing your own.

Whatever you use to draw your image, make sure you can save it in either PNG or JPG format. Its size should be 600 x 400 (the same size as your world). Save this image in the images folder in your AvoiderGame scenario.

Using the same steps that you used to create AvoiderWorld (The Avoider Game tutorial section), create another world; call it AvoiderGameOverWorld and associate the image you created earlier with it. In the World classes area of your scenario, you should see what is shown in Figure 16.

Figure 16: The World classes section after adding AvoiderGameOverWorld

Switching scenes

Now, we want to display the game-over screen if our hero touches an enemy. To do this, we need to perform the following three steps:

  1. Detect when we collide with an enemy and then tell (by calling a method) our world, AvoiderWorld, that the game is over.

  2. In our AvoiderWorld class, we need to implement the game-over method that the Avatar will use to signal the end of days.

  3. In our game-over method, set the world to be AvoiderGameOverWorld, instead of AvoiderWorld.

Let's start with step 1. Previously, in the Detecting collisions subsection of this section, you wrote code to remove the hero from the game if it touches one of the enemies. This code was contained in the method checkForCollisions(). To implement step 1, we need to change that method to the following method:

private void checkForCollisions() {
  Actor enemy = getOneIntersectingObject(Enemy.class);
  if( enemy != null ) {
    AvoiderWorld world = (AvoiderWorld) getWorld();
    world.endGame();
  }
}

The only difference is the code inside the if statement. I hope it makes sense that we are now asking the world to end the game, as opposed to removing the hero object. The part that could be confusing is the substitution of AvoiderWorld for World and the addition of the (AvoiderWorld) part. The problem, is that we are going to implement endGame() in AvoiderWorld, not World. So, we need some way of specifying that the return value of getWorld() will be treated as AvoiderWorld and not just plain old ordinary World. In Java terms, this is called casting.

Now, let's look at steps 2 and 3. Here's the code you need to add to AvoiderWorld.

Figure 17: This shows the endGame() method added to AvoiderWorld

We have changed, and added, a minimal amount of code, but if you have followed along carefully, you should be able to save, compile, and run the code. See the game-over screen when our hero touches an enemy? (If not, go back and retrace your steps. Something you typed in is wrong.)

Note

The three Ps: Plan, Plan, and Plan

Coding is complicated stuff. When you have a problem to solve, you don't just want to sit down and start hacking away at the computer until you bang out a solution. You want to sit down with a stylus and ePad (used to be pen and paper in my day) and plan. I gave you a small example when I wrote out the three steps needed to display the game-over screen. One of the best methods to help you design a solution is a top-down design (also know as divide and conquer).

In the top-down design, you start thinking of a solution to a problem at a very high level and then repeatedly break down this solution into subsolutions until the subsolutions are small and manageable

Adding a "play again" button

The game-over screen is great and all, but we don't want to just stare at it all day. OK, so let's make it so that you can restart the game by clicking on the game-over screen. AvoiderGameOverWorld needs to keep checking whether the mouse has been clicked and then set the world back to AvoiderWorld, so that we can play the game again. Looking at the Greenfoot documentation, we can see the mouseClicked() function. Let's use that method in the act() method of AvoiderGameOverWorld, along with the change world code. Add the following code to AvoiderGameOverWorld:

public void act() {
  // Restart the game if the user clicks the mouse anywhere
  if( Greenfoot.mouseClicked(this) ) {
    AvoiderWorld world = new AvoiderWorld();
    Greenfoot.setWorld(world);
  }
}

This code should look very familiar to you. The code inside the if statement is nearly identical to the code we added to the endGame() method in the AvoiderWorld class, except this time we are creating and switching to AvoiderWorld.

The new part is to check to see whether the user clicked the mouse anywhere on the screen. The Greenfoot.mouseClicked() method returns true if the user just clicked on the object supplied in its parameter. We supplied the this variable, which represents the whole instance of the AvoiderGameOverWorld world.

Compile and run. Great job! Our game is coming along nicely!

Adding an introduction screen

Adding an introduction screen is really easy, and we just need to perform many of the same steps we did in creating a game-over screen. First, we need to create an introduction screen image in whatever graphics editor program you want. The one I created is shown in Figure 18.

Figure 18: The image of the introduction screen for our game.

Make sure the image is either in PNG or JPG format and has a pixel size of 600 x 400. Save this image in the images folder in your AvoiderGame scenario.

Create a new world (by subclassing World), call it AvoiderGameIntroScreen, and associate the image you just created with it. When you are done with this, the World classes area of your scenario should look like the screenshot shown in Figure 19.

Figure 19: These are all the worlds you created in your AvoiderGame

Setting the initial screen

We obviously want our new introduction screen to display first when the player first starts the game. To select AvoiderGameIntroScreen world as our starting World, we need to right-click on it in the World classes area and select the new AvoiderGameIntroScreen() menu option in the pop-up window that appears (see Figure 20).

Figure 20: This is about selecting our starting world

Let's make sure everything is hooked up correctly. Compile and run your Greenfoot application. You should start with the introduction screen you just created, but can't do much else. We'll fix that now.

Adding a "play" button

We are going to repeat exactly the same steps we did in implementing the restarting of the game from the game-over screen.

Add the following code to AvoiderGameIntroScreen:

public void act() {
  // Start the game if the user clicks the mouse anywhere 
  if( Greenfoot.mouseClicked(this) ) {
    AvoiderWorld world = new AvoiderWorld();
    Greenfoot.setWorld(world);
  }
}

This code should look very familiar to you. This is exactly the same code we added to the AvoiderGameOverWorld class.

Compile and run. Have some fun. See how long you can last!

So far so good, but it is definitely missing some key gaming elements.

Adding background music

In this part of the tutorial, you need to search the Web for a song (.mp3) you would like to play during the game.

Note

Acquiring music

Whenever you are adding assets (music or graphics) to your game, make sure you do so legally. There are many sites on the Internet that offer free use of the music or pictures provided. Never use proprietary music, and always cite the sources from which you acquired assets. I got the music I added to the game from newgrounds.com, and I gave credit to the author in my code.

We only want the music to play when we start playing the game, not during the introduction or game-over screens. Therefore, we'll start the music when we display AvoiderWorld and turn it off before we display AvoiderGameOverWorld. We only want to start the music once, so we don't want to add the code to play the music in the act() method—imagine the noise from doing that! What we need is a method that is only called once at the creation of the object. That's what the constructors of a class provide. (If you need to review what a class and an object are, see the information box in the What have we just done? section)

Note

What is a constructor?

In programming in Java (and other object-oriented languages), we write code in classes. A class describes the methods and attributes of objects we want to create in our program. You can think of a class as a blueprint for building objects. For example, our Enemy class describes the behavior and attributes of every enemy object that appears in our Avoider Game. Each class has a constructor that performs all initialization needed for each object created. You can identify the constructor of a class easily. Constructors have exactly the same name as the class they are in and have no return type. As a quick test, find the constructor in our AvoiderWorld class. Found it?

We call the constructor every time we create a new object. In Greenfoot, right-click on the Enemy class and you'll see that the top-menu choice is new Enemy(). The Enemy() part is the constructor. The new keyword creates the new object and the Enemy() initializes that new object. Got it?

The following are some good resources you should read to learn more about constructor functions:

http://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html

http://java.about.com/od/workingwithobjects/a/constructor.htm

Writing the music code

Now that we know where to put the code (everyone say constructor), we need to know what code to write. Greenfoot provides a class for playing and managing music called GreenfootSound. This class makes playing music really easy. Before I show you the code to put in the constructor, you should take a look at the documentation for GreenfootSound and see if you can figure out what to write.

Tip

No, really! Go read the documentation! Trying to do it on your own will really help you.

Here's the code you need to add to the constructor of AvoiderWorld.

Figure 21: Here's the constructor for AvoiderWorld

Analyzing the music code

Let's look at every line of code in the AvoiderWorld constructor. First, you have the call to the superclass's constructor, which is needed, as described earlier, to properly initialize your game world. Next, we have this line:

bkgMusic = new GreenfootSound("sounds/UFO_T-Balt.mp3");

This creates a new GreenfootSound object and saves a reference to it in the bkgMusic variable. You need to change the preceding code, so that instead of sounds/UFO_T-Balt.mp3, you use a string that gives the name of the music file you downloaded to play (you need to save the music in your sounds folder in your Greenfoot project's folder). We also need to declare the bkgMusic variable we are using in the constructor. To do that, you need to add a variable declaration at the top of your class, as shown in Figure 22. By declaring the variable at the top of your class, it will be accessible to all the methods in your class. This will be important when we add code to stop playing the music.

Figure 22: This shows the variable declaration for bkgMusic in the AvoiderWorld class

The next line of code we have to discuss is this one:

bkgMusic.playLoop();

This line starts playing the music and will start it over once it finishes. If we would have only done bkgMusic.play(), then the song would have played through only once.

The last line in the constructor is a very important one, and it was added automatically by Greenfoot. Remember when, back in the Adding our hero section of this chapter, I instructed you to place an instance of the Avatar class (our hero) in the center of the screen, right-click, and choose the menu option Save the World? When you did this, Greenfoot created this prepare() method. If you look at the contents of this method, you will see that it contains the code to create an Avatar object and add it to the screen. Then, it added the call to use prepare() in the constructor. If you choose the menu option Save the World again, this prepare() method will be updated.

OK, save, compile, and run. Did it work? If not, go back and find the typo.

Stop the music

If you ran your code, you had music during the game, but it did not turn off when you died and went to the game-over screen. We have to explicitly turn off the music before displaying AvoiderGameOverWorld. This is super easy! All we need to do is add the following line of code at the beginning of the endGame() method you added to AvoiderWorld earlier:

bkgMusic.stop();

Now, save, compile, and run. It should all work according to plan.

Note

Private, Protected, and Public

The Java keywords private, protected, and public modify how a variable, method, or class is accessed in Java. Good programming practice dictates that you make all of your class instance variables private and require access to that variable to only occur through methods. For methods, you want to make ones you only access within the private class; otherwise, make it public. The keyword protected is used to a method available to subclasses of the class but not to external classes. For more information, refer to the following links:

Your assignment

Perform the following actions before continuing:

  • Once the game-over screen is displayed, play music. Are you going to make it peppy music to lift the spirits of your player or sad and morose to really rub it in? Make sure you turn it off before switching to AvoiderWorld.

  • Our enemy's movements are pretty vanilla. Can you spice it up? Some ideas are to have the enemy characters have variable speed, drift left or right, or enter from the top or bottom. What will you come up with?

Remember to create a backup copy of AvoiderGame before trying these challenges.

Next…

Almost done! We have built the basics of our game and will next add some things to make it challenging.

Enhancing playability

In the final section of this chapter, we will add code to increase the game's playability. First, we will add a score. Next, we need to increase the challenge of the game over time. As the player gets better at the game, we want to ramp up the challenge; we will add a leveling system to do this.

Game scoring

Our game is evolving; however, we need a way to judge how well we are doing in the game. There are many ways to judge game performance, for example, levels completed, time, progression, and so on—but the most common method is to assign the player a score. We are going to add a scoring system to the game that rewards players for the number of enemies they avoid.

Adding the Counter class

Keeping a count of things and displaying that count is so common in games that Greenfoot provides you with a Counter class. To get access to this class, you need to import it into your scenario. To do this, select Edit in Greenfoot's main menu, and then select the Import Class… submenu choice. You will see a window, like the one shown in Figure 23. Make sure the Counter box is selected on the left-hand side and then click on the Import button.

Figure 23: Here's Greenfoot's Import Class window

This will add the Counter class to your list of Actor classes available for use in our game as shown in Figure 24.

Figure 24: The Actor classes section of your scenario window now includes the Counter class

We want the score to appear immediately in the game. In tutorial 4 (http://www.greenfoot.org/doc/tut-4) on the Greenfoot site, you were introduced to "Saving the World" to have the World class automatically place Actor in your world. I'm going to describe how to place Actor in your world manually; specifically, you are going to add an instance of the Counter class to your AvoiderWorld world.

We discussed that Greenfoot already added the call to the prepare() method in your AvoiderWorld() constructor. Locate the definition of this method in the AvoiderWorld class. Change this method to look like the following code:

private void prepare() {
  Avatar avatar = new Avatar();
  addObject(avatar, 287, 232);
  scoreBoard = new Counter("Score: ");
  addObject(scoreBoard, 70, 20);
}

The first two lines of this method were already present. The last two lines put a score display on our game screen. The scoreBoard = new Counter("Score: "); code creates a new Counter object with a label Score: and stores a reference to it in the scoreBoard variable (we haven't declared this variable yet, but will soon.) The next line of code adds our Counter to the upper-left corner of our game screen.

Lastly, we need to declare the scoreBoard variable at the top of our class. Add private Counter scoreBoard; above the constructor, as shown in Figure 25.

Figure 25: The declaration of the scoreBoard variable in the class AvoiderWorld.

Compile, run, and test your scenario.

Increasing the score over time

We need to do just one more thing. We need to call setValue() on our scoreBoard variable to increase our score over time. One place we could do this is where we create the enemies in AvoiderWorld. The thinking, is that you get some points for every enemy created, because you will ultimately have to avoid it. Here's how you should change the act() method in AvoiderWorld:

public void act() {
  // Randomly add enemies to the world
  if( Greenfoot.getRandomNumber(1000) < 20) {
    Enemy e = new Enemy();
    addObject( e, Greenfoot.getRandomNumber(getWidth()-20)+10, -30);
    // Give us some points for facing yet another enemy
    scoreBoard.setValue(scoreBoard.getValue() + 1);
  }
}

The only thing I changed was adding the comment about points and adding the call to setValue() on scoreBoard. This line of code retrieves the current score using getValue(), adds 1 to it, and then sets the new value using setValue(). The typical usage of the Counter class is also provided in a comment at the top of the Counter class. Check it out!

Compile your AvoiderGame scenario and try it out. Are you getting an increased score?

Adding levels

Our game isn't very challenging at this point. One thing we could do, is make the game become more challenging over time. To do this, we are going to add the notion of levels to Avoider Game. We are going to increase the challenge of the game by periodically increasing the rate at which enemies spawn and the speed at which they travel.

Increasing spawn rates and enemy speed

In AvoiderWorld, add two variables, enemySpawnRate and enemySpeed, and give them initial values; we will use these two variables to increase difficulty. The top of your AvoiderWorld class should look like Figure 26.

Figure 26: This shows the variables in AvoiderWorld

Increasing difficulty based on the score

Next, we need to add a method that increases the difficulty of the game based on the player's score. To do this, we need to add the following method to AvoiderWorld:

private void increaseLevel() {
  int score = scoreBoard.getValue();

  if( score > nextLevel ) {
    enemySpawnRate += 2;
    enemySpeed++;
    nextLevel += 100;
  }
}

We introduced a new variable, nextLevel, in increaseLevel(), and we need to add its declaration at the top of the AvoiderWorld class. Here is the declaration you need to add next to the variable declarations of enemySpawnRate and enemySpeed:

private int nextLevel = 100;

As evident from the code in increaseLevel(), we increase both enemySpawnRate and enemySpeed as the player's score increases. The last thing we need to do is use the enemySpawnRate and enemySpeed variables in the creation of enemies and call increaseLevel() from the act() method in AvoiderWorld. Here is the new act() method:

public void act() {
  // Randomly add enemies to the world
  if( Greenfoot.getRandomNumber(1000) < enemySpawnRate) {
    Enemy e = new Enemy();
    e.setSpeed(enemySpeed);
    addObject( e, Greenfoot.getRandomNumber(getWidth()-20)+10, -30);
    // Give us some points for facing yet another enemy
    scoreBoard.setValue(scoreBoard.getValue() + 1);
  }
  increaseLevel();
}
Implementing enemy speed increases

I'd love to yell compile and run! at this point, but there is one last detail. In the act() method, we use the line e.setSpeed(enemySpeed); to change the speed of the enemy; however, we never have implemented that method in the Enemy class. In addition, we need to change the Enemy class a bit to use the newly set speed.

Figure 27 gives the complete code for the Enemy class.

Figure 27: This shows the finished Enemy class

As you can see, we made some really simple changes to the Enemy class. We added the setSpeed() method, which simply accepts an integer parameter and uses that value to set the speed variable that has been declared at the top of the class. In the act() method, we use the value of the speed variable in the setLocation() call; we continually add speed to the current y coordinate.

Compile and run and enjoy your new game!

Your assignment

Since this is the end of the Avoider Game instruction. I'm going to give you a few challenge assignments. Good luck! Try to implement the following:

  • Once the player's score is above 600, add a new enemy that spawns in addition to the enemies we have now. The new enemy should visually be very distinct from our existing enemies. If you are feeling up to it, have the new enemy move differently from the existing enemies too.

  • Periodically, spawn a power-up that gives our hero a special ability. For example, the power-up could make our hero temporarily invincible, allow our hero to kill three enemies, or shrink the size of the avatar making it easier to avoid enemies.

  • Display the player's final score on the game-over screen.

These challenges will definitely take some time and you should not feel compelled to try them. I just wanted to give those who are really interested a way to continue working on the Avoider Game. You will not need to have completed these challenges to move on to the next chapter.

Next…

Congratulations! You did it! Have fun. Play your new game.

 

Summary


This chapter demonstrated how to make a fun and engaging game. We have mouse control, a hero, enemies, a score, and introduction and game-over screens.

As this book assumes you have some experience working in Greenfoot, this chapter also served the purpose of refreshing your memory of how to program in Greenfoot.

In the upcoming chapters, we'll look at advanced programming concepts in Greenfoot that will allow you to create fun, innovative, and engaging applications. These chapters will assume that you have mastered the material in this one.

About the Author
  • Michael Haungs

    Michael Haungs is a professor at California Polytechnic State University, San Luis Obispo, where he teaches and conducts research in game design, game development, web application development, and distributed systems. He received his bachelor's degree in science in industrial engineering and operations research from UC Berkeley, his master's degree in science in computer science from Clemson University, and his PhD from UC Davis. He is the author of PolyXpress (http://mhaungs.github.io/PolyXpress)a system that allows the writing and sharing of location-based stories. Haungs is actively involved in curriculum development and undergraduate education. Through industry sponsorship, he has led several K-12 outreach programs to inform and inspire both students and teachers about opportunities in computer science. Haungs is also a co-director of the liberal arts and engineering studies (LAES) program. LAES is a new, multidisciplinary degree offered jointly by the College of Liberal Arts and the College of Engineering at Cal Poly and represents a unique focus on graduating creative engineers.

    Browse publications by this author
Creative Greenfoot
Unlock this book and the full library FREE for 7 days
Start now