FANG:First Game

From GGCWiki
Jump to: navigation, search

Overview
  Courses
  How it works
  Features
  License
Documentation
  API
  FAQ
  Posting game
  Change log
Tutorials
  First Game
  Networking
  First Tracker
  First Alarm
  Introduction
  Method Flow
  Coordinates
Games
  Student
  Example
  Instructor
Assignments
Free Software

FangSmall.gif Freely
Available
Networked
Game Engine
AlexGame.JPG Projectile.jpg

These instructions assume you have downloaded and installed the software needed for designing your game which includes Eclipse, Mozilla, Firefox, and Java 1.5. These instructions include information about using Eclipse. If you are already comfortable using Eclipse to write Java programs, you can use [firstgame_pro.html another version of these instructions] that has less information about using Eclipse. In addition, you will need to be able to use Mozilla Composer to make simple web pages (for creating the game's help page). You are welcome to use other web editing software than Mozilla Composer and other integrated development environments (IDE) than Eclipse, but the instructions given pertain to Mozilla & Eclipse.

Using the FANG Engine you can write a working game very quickly. The steps below will guide you to making a game where red and blue circles appear randomly and you have to move your mouse over them to make the circles go away. The game will keep score of how many red circles and how many blue circles you catch on in 10 seconds.

As with any game you make, you want to keep it functional as much as possible. After you make additions, test them completely before moving on. Keep the additions you make short and simple. Complex games are best written by many simple steps rather than few complex steps. We're going to follow these guidelines in making our game.

Be sure read the Explanations of the Source Code in each of the tables below. Also if you are having trouble, try visiting the [faq.html FAQ].

Before you get started, be sure to [wackadotExperience.html read some advice from students who have already completed this assignment]. They will tell you what it feels like working on the game, the types of problems they encountered, the best strategies for solving these problems, and best of of all, what it feels like when you have your own working game.

  1. Getting the Gaming Engine and Setting Up the Project
    - Save to your computer the latest version of the FANG Engine: fang.jar.
    - Open up Eclipse and start a new Java Project. To start a new project, go to File->New->Project. A dialog with several screens (the first is shown below) will come up.
    File:Newjavaproject1.jpg
    Click Next. On the second screen of the dialog, enter 'Wackadot' in the 'Project name' field, as shown below.
    File:Newjavaproject2.jpg
    In the 'JDK Compliance' section of this dialog, the option 'Use default compiler compliance (Currently 5.0)' should be selected. If the option instead says something else (such as 'Currently 1.4'), then click on the link to the right of the option that says 'Configure default...'. This will cause the dialog below to come up.
    File:Preferences.jpg
    Change the drop down box next to the 'Compiler compliance level' to 5.0.
    - In Eclipse select File->Import->Archive File, then click 'Next'. You will see the screen shown below.
    File:Import.jpg
    Under 'From archive file:' browse to find fang.jar.
    Under 'Into folder:' make sure you have entered the project you just made (if this is not already the case, browse to find it).
    Click on 'Finish'.

  2. Making the Packages for Your Game
    Each game should be made in its own package, and there should be subpackages within the game's primary package We're going to name the game in this example wackadot. You need to make the following packages in your project:
    • wackadot
    • wackadot.resources
To make a package in your project, right-click on the project name (in the 'Package Explorer' pane on the left) and choose New->Package in the menu that appears, as shown below. 
File:Newjavapackage1.jpg
Then complete the dialog that appears with the name of the new package that you want to create, as seen in the example screenshot below.
File:Newjavapackage2.jpg
All of the classes will be put in the wackadot package, and all other files (like audio, images, help files) will go in wackadot.resources.

  1. Extending GameLoop
    - Every game you make will have a class that extends GameLoop. GameLoop is in the fang package. Create a new class in the package wackadot and call the class Wackadot. Creating a new class is similar to creating a new package: right click the name of the package that you want the class to be under and then choose New->Class and complete the dialog that will appear.
    - Some code will be automatically generated when you create the Wackadot class. Replace the generated code with the code in the table below.

A
Source code
Explanation of Source code
1
2
3
4
5
6
7
8
9
10
11
12
package wackadot;

import fang.*;

public class Wackadot extends GameLoop
{
   public static void main(String[] argv)
   {
      Wackadot dot=new Wackadot();
      dot.runAsApplication();
   }
}
Line 1: the package this class is in

Line 3: importing the fang package for use in the class.

Line 7-11: the main method is required to allow the game to be run as an application in addition to it being an applet. (It is an applet because it is derived from the GameLoop class which is indirectly derived from the JApplet class.)


  1. File:Wackadot0.jpgRunning the Game
    - The method runAsApplication in main is what starts the game running. (The method is from the FANG engine.)
    - There are three ways to run your game: as an applet, as an application, and as a networked game. For now we are going to run Wackadot as an application. To do this, highlight the Wackadot class in the Package Explorer, right click, then select 'Run As...' and then select 'Java Application'. You should see a window come up that looks like the image on right, only yours will be about twice as big.

  2. Adding Sprites
    - To make Wackadot, we definitely need dots. The visual elements on the screen in games are called sprites. Sprites have some basic properties such as shape, orientation, location, and color. We're going to start by making a red dot appear in the middle of the screen. The coordinates in the gaming engine are designed such that resizing the screen is not difficult. The location of sprites is given in fractions of the screen. Internally, this fraction is then multiplied by the actual width and actual height of the screen to get the actual location. In this way, the sprites in the game scale smoothly with the size of the screen.
    - Add the code below which is not already there. You already have some of the code below from the previous instructions: new code is shown in bold. This code should make a sprite appear in the middle of the screen.
    - Test the changes to make sure you see the dot appear before going to the next step. Perform the test by running the program as an application, as in the previous section. Or if you click the button that looks like a green circle with a white triangle in the center File:Runbutton.jpg, located in the top row in Eclipse, that will run the same program in the same way that you did last.
B
Source code
Explanation of Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package wackadot;

import java.awt.Color;
import java.awt.geom.*;
import fang.*;

public class Wackadot extends GameLoop
{
   private Sprite dot;
    
   public void startGame()
   {
       makeSprites();
       addSprites();
   }
    
   private void makeSprites()
   {
       Ellipse2D.Double circle=
           new Ellipse2D.Double(0, 0, 1, 1);

       dot=new Sprite(circle);
       dot.setScale(0.1);
       dot.setLocation(0.5, 0.5);
       dot.setColor(Color.RED);
   }
    
   private void addSprites()
   {
       canvas.addSprite(dot);
   }
    
   public static void main(String[] argv)
   {
       Wackadot dot=new Wackadot();
       dot.runAsApplication();
   }
}
Line 1: declares the package this class resides in

Lines 3-5: imports the packages and classes used in the class

Line 9: declares a Sprite instance variable that will be used in the game logic eventually.

Lines 11-15: the startGame method is called when the Start button is pressed the first time. In this method, you need to make and add all the sprites. Note: for multiplayer games, the number of players is only available once the startGame method is called.

Lines 17-26: helper method for constructing and placing sprites. The positions and sizes are relative to a screen which spans (0, 0) to (1, 1).

Lines 28-31: helper method for adding sprites to the canvas. Simply making a sprite does not make it visible. Sprites are only visible once they are added to the canvas within the bounds of the canvas and sized properly.


  1. Making the Sprite move with the mouse
    The gaming engine redraws the screen up to 25 times per second, and may calculate up to 40 intermediate frames for every single frame it displays. After each of these frames, there is an opportunity to provide the game logic in the advanceFrame method. The advanceFrame method is called for you by the gaming engine between frames. To start with, we are going to make the position of the dot follow the mouse. Add the following method to your Wackadot class.

C
Source code
Explanation of Source code
1
2
3
4
5
6
public void advanceFrame(double timePassed)
{
   Point2D.Double mouse=
       getPlayer().getMouse().getLocation();
   dot.setLocation(mouse);
}
Line 1: this method is called automatically between each frame calculated/displayed.

Lines 3-4: gets the mouse of the current player.

Line 5: places the sprite at the same position as the mouse.


  1. Testing your changes
    Always test your changes before making more modifications. Run the game. Does the dot follow the mouse? (Remember to click 'Start' to start the game running!) If so, go on to the next step. If not, reread the instructions above to see what went wrong.

  2. Making other dots appear randomly
    Now we're going to add one red dot and one blue dot which will appear at random positions on the screen. When writing your games, it is important to use the provided random number generator if you are going to make networked games. The provided random number generator gives the same sequence of numbers every time which is essential for making the networked games stay consistent. The gaming engine only sends mouse and keyboard input from all of the players and relies upon common game logic to keep the games consistent. If two games use different sequences of random numbers, then this logic is not identical over the networked games and they will quickly become inconsistent. Add the following instance variables

D
Source code
Explanation of Source code
1
2
private Sprite redDot;
private Sprite blueDot;
Line 1: declares the red dot
Line 2: declares the blue dot


Then, alter the existing methods (new code is bold):

E
Source code
Explanation of Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void makeSprites()
{
   Ellipse2D.Double circle=
       new Ellipse2D.Double(0, 0, 1, 1);
   
   dot=new Sprite(circle);
   dot.setScale(0.1);
   dot.setLocation(0.5, 0.5);
   dot.setColor(Color.RED);

   redDot=new Sprite(circle);
   redDot.setScale(0.1);
   redDot.setLocation(
          random.nextDouble(),
          random.nextDouble());
   redDot.setColor(Color.RED);

   blueDot=new Sprite(circle);
   blueDot.setScale(0.1);
   blueDot.setLocation(
          random.nextDouble(),
          random.nextDouble());
   blueDot.setColor(Color.BLUE);
}

private void addSprites()
{
   canvas.addSprite(dot);
   canvas.addSprite(redDot);
   canvas.addSprite(blueDot);
}
Lines 14-15, 21-22: uses the provided random number generator to get a random number between 0 and 1.

Lines 29-30: adds the sprites to the canvas to make them visible

Note: the dots will appear at the same place every time because they are going through the same sequence of random numbers every time. When we get to making the dots go away, we will handle making the game respond differently every time.


  1. Testing your changes
    Always test your changes before making more modifications. Run the game. Do the red and blue dots appear? If so, go on to the next step. If not, reread the instructions above to see what went wrong.

  2. Repositioning the dots when they collide
    The advanceFrame method is where the game logic is based and is where you will need to test for collisions. We will write a helper method called handleCollisions and call this from the advanceFrame method. Add the following code to your class (new code is bold).

F
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

private void repositionRandomly(Sprite sprite)
{
sprite.setLocation(
random.nextDouble(),
random.nextDouble());
}

private void handleCollisions()
{
if(dot.intersects(blueDot))
{
repositionRandomly(blueDot);
}
if(dot.intersects(redDot))
{
repositionRandomly(redDot);
}
}

public void advanceFrame(double timePassed)
{
Point2D.Double mouse=
getPlayer().getMouse().getLocation();
dot.setLocation(mouse);
handleCollisions();
}

Lines 1-6: helper method for randomly positioning the dot.

Lines 8-18: helper method for handling dot collisions

Lines 10-13: if the dot moving with the mouse collides with the blue dot, then the blue dot is positioned in a random location.

Lines 14-17: if the dot moving with the mouse collides with the red dot, then the red dot is positioned in a random location.

Lines 20-26: don't duplicate the advanceFrame method, just add line 25.

Line 25: calls the helper method for handling collisions


  1. Testing your changes
    Always test your changes before making more modifications. Run the game. Do the red and blue dots reposition randomly when they intersect with the moving dot? If not, reread the instructions above to see what went wrong. If so, do you notice how they always follow the same next random positions each time you run the program?

  2. Making the random numbers less predictable
    This predictability is because the random number generator always starts going through the sequence of random numbers starting at the same place. If you restart the random number generator at a 'random' or at least varying place each time a new place is determined, the new location of the dots will be less predictable. Alter the handleCollisions method to reflect the changes below (new code is bold).

G
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

private void handleCollisions()
{
if(dot.intersects(blueDot) ||
dot.intersects(redDot))
{
long seed=(long)(1000*getTime());
random.setSeed(seed);
}
if(dot.intersects(blueDot))
{
repositionRandomly(blueDot);
}
if(dot.intersects(redDot))
{
repositionRandomly(redDot);
}
}

Lines 3-8: seeds the random number generator when either dot intersects using the current game time in milliseconds. Every time the random generator is seeded, it starts a sequence of random numbers. If seeded with the same seed again, it would give the same sequence of random numbers.


  1. Testing your changes
    Always test your changes before making more modifications. Run the game. Do the red and blue dots reposition less predictably? If not, reread the instructions above to see what went wrong. If so, continue to the next step.

  2. Changing the dot color
    When the circle intersects with a dot of the same color, it should change to the other color. The goal of the game will be to move your dot over the dot of the same color. Alter the handleCollisions method to make this happen (new code is bold).

H
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

private void handleCollisions()
{
if(dot.intersects(blueDot) ||
dot.intersects(redDot))
{
long seed=(long)(1000*getTime());
random.setSeed(seed);
}
if(dot.intersects(blueDot))
{
repositionRandomly(blueDot);
if(dot.getColor().equals(Color.BLUE))
{
dot.setColor(Color.RED);
}
}
if(dot.intersects(redDot))
{
repositionRandomly(redDot);
if(dot.getColor().equals(Color.RED))
{
dot.setColor(Color.BLUE);
}
}
}

Lines 12-15, 20-23: checks to see if the dot instersected matches the color of the dot. If it does, the color of the dot is changed to the other color.


  1. Testing your changes
    Hopefully you get the point by now: Always test your changes before making more modifications. This 'Testing your changes' step will now just be implied after every step.

  2. Keeping score
    Score can be kept using a StringSprite and using an int instance variable. Let's keep score like this: you get 1 point for matching colors, and -1 point for intersecting different colors. Add the following instance variables and constants:

I
Source code
Explanation of Source code

1
2

private StringSprite scoreSprite;
private int score;

Line 1: a sprite which will consist of text
Line 2: the integer which will keep the score


Alter the following methods (new code is bold):

J
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

public void startGame()
{
score=0;
makeSprites();
addSprites();
}

private void makeSprites()
{
Ellipse2D.Double circle=
new Ellipse2D.Double(0, 0, 1, 1);

dot=new Sprite(circle);
dot.setScale(0.1);
dot.setLocation(0.5, 0.5);
dot.setColor(Color.RED);

redDot=new Sprite(circle);
redDot.setScale(0.1);
redDot.setLocation(
random.nextDouble(),
random.nextDouble());
redDot.setColor(Color.RED);

blueDot=new Sprite(circle);
blueDot.setScale(0.1));
blueDot.setLocation(
random.nextDouble(),
random.nextDouble());
blueDot.setColor(Color.BLUE);

scoreSprite=new StringSprite("Score: "+score);
scoreSprite.setHeight(0.1);
scoreSprite.rightJustify();
scoreSprite.topJustify();
scoreSprite.setLocation(1, 0);
}

private void addSprites()
{
canvas.addSprite(dot);
canvas.addSprite(redDot);
canvas.addSprite(blueDot);
canvas.addSprite(scoreSprite);
}

private void updateScore()
{
scoreSprite.setText("Score: "+score);
}

private void handleCollisions()
{
if(dot.intersects(blueDot) ||
dot.intersects(redDot))
{
long seed=(long)(1000*getTime());
random.setSeed(seed);
}
if(dot.intersects(blueDot))
{
repositionRandomly(blueDot);
if(dot.getColor().equals(Color.BLUE))
{
dot.setColor(Color.RED);
score++;
}
else
{
score--;
}
updateScore();
}
if(dot.intersects(redDot))
{
repositionRandomly(redDot);
if(dot.getColor().equals(Color.RED))
{
dot.setColor(Color.BLUE);
score++;
}
else
{
score--;
}
updateScore();
}
}

Line 3: starts the score out at 0

Lines 32-36: makes the score sprite. Right justifying means the location will represent the rightmost location. Similarly top justifying means the location represents the topmost location. (1, 0) is the top right which is where the score will be. The text will be 1/10 of the screen high.

Line 44: adds the score sprite to the canvas to make it visible

Lines 47-50: updates the score sprite to make sure it represents the current score

Lines 63-71, 77-85: changes the score when the dot intersects one of the colored dots. If the dot is the same color as the one interesected, then 1 is added to the score. If the dot is the other color than the one intersected, then 1 is subtracted from the score.

Lines 72, 86: when the int score changes, the StringSprite scoreSprite should change. These lines call the helper method to change the scoreSprite to represent the current score.


  1. Making the timer
    Add similar code to make a timer. The timer won't yet be functional, but it will appear on the screen. Make the following additions/modifications to the code:

K
Source code
Explanation of Source code

1
2

private int timeLeft;
private StringSprite timerSprite;

Line 1: an integer representing the number of second left s
Line 2: the StringSprite which will show the time left


Alter the following methods (new code is bold).

L
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

public void startGame()
{
score=0;
timeLeft=10;
makeSprites();
addSprites();
}

private void makeSprites()
{
Ellipse2D.Double circle=
new Ellipse2D.Double(0, 0, 1, 1);

... code not shown for brevity

scoreSprite.setLocation(1, 0);

timerSprite=new StringSprite("Timer: "+timeLeft);
timerSprite.leftJustify();
timerSprite.topJustify();
timerSprite.setHeight(0.1);
timerSprite.setLocation(0, 0);
}

private void addSprites()
{
canvas.addSprite(dot);
canvas.addSprite(redDot);
canvas.addSprite(blueDot);
canvas.addSprite(scoreSprite);
canvas.addSprite(timerSprite);
}

private void updateTimer()
{
timerSprite.setText("Timer: "+timeLeft);
}

Line 4: starts the timer out at 10

Line 14: Do not copy this line, read it.

Lines 18-22: makes the timer sprite

Line 31: adds the timer sprite to the canvas to make it visible

Lines 34-37: updates the timer sprite to make sure it represents the current time


  1. Making the timer tick
    You need an alarm to make the timer go down every second. To make an alarm, the class needs to have only a single method called alarm. This method will be called when it is scheduled. We're going to write a class to make the time go down by 1 second in the alarm method. Because this class is trivial, we're going to write it as an inner class. We'll call the alarm method every second while there is time remaining. Add the following inner class modification to the constructor and make the other changes indicated (new code is bold):

M
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

public void startGame()
{
score=0;
timeLeft=10;
makeSprites();
addSprites();
scheduleRelative(new TimeUpdater(), 1);
}

class TimeUpdater implements Alarm
{
public void alarm()
{
timeLeft--;
updateTimer();
if(timeLeft>0)
{
scheduleRelative(this, 1);
}
}
}

public void advanceFrame(double timePassed)
{
if(timeLeft>0)
{
Point2D.Double mouse=
getPlayer().getMouse().getLocation();
dot.setLocation(mouse);
handleCollisions();
}
}

Line 7: schedules the alarm method of TimeUpdater to be called 1 second from the start of the game. Adding this line will cause an error until the class below in line 10-21 is copied into the class.

Lines 10-21: an inner class in Wackadot used to update the timeLeft.

Lines 12-20: the method called when the alarm goes off

Lines 16-19: if there is still time remaining, this schedules the alarm to go off again in 1 second

Lines 25-33: allows game control and scoring only while there is time left


  1. Making the Help File
    Every game must have an html help file. Create an html page called WackadotHelp.html and save it in the wackadot.resources package. Packages are really just folders. You can get to the wackadot.resources package by first going to the folder where you have your Eclipse workspace, then going to Wackadot/wackadot/resources. For now it does not matter what you put in the html help file, just that you have one.

    Alter the following method (new code is bold).
M
Source code
Explanation of Source code

1
2
3
4
5
6
7
8
9

public void startGame()
{
score=0;
timeLeft=10;
makeSprites();
addSprites();
scheduleRelative(new TimeUpdater(), 1);
setHelp("resources/WackadotHelp.html");
}

Line 8: customizes the help to display the help file just created


  1. Comment the code and make your own modifications
    The game works. Congratulations! Comment the code you've written/copied. Documenting your code is essential if you are to share it or collaborate with others. Now that you have a working version, play with it. Make modifications and enhancements. Take a look at the examples page for some ideas. The game you have written is also an applet. You can also make a jar file of the project and put your code on a web page. See instructions on the main page about posting your games.


If you have any questions about making this sample game, be sure to take a look at the [faq.html FAQ]. Chances are someone else has had the same difficulty and the solution has been posted.

Good luck making your games with the FANG Engine. I'm always interested in posting well commented well designed games that are fun to play. Visit the [studentgames.html sample student] and [instructorgames.html instructor games] for information on how to send me your game.

Personal tools