Old Style Game Framework How To..
This walk through create a "bounce" game, where the player bounces balls back up into the air.
- Setup new project with main class (BounceGame).
- (Optional) I update the build xml for keeping track of my build version.
This is a quick and easy to do.
- I use a "pre-compile" target that checks if the files
have been changed since the game.properties file was changed.
<target name="-pre-compile" description="">
<echo message="pre-compile:"/>
<uptodate property="nochanges" targetfile="${src.dir}/org/deken/bounceGame/game.properties">
<srcfiles dir="src" includes="**/*.*"/>
</uptodate>
</target>
- Next I use a "post-compile" target, that if the "nochanges"
is set, it will update the build number in the game.properties file.
<target name="-post-compile" unless="nochanges">
<echo message="post-compile:"/>
<propertyfile file="${src.dir}/org/deken/bounceGame/game.properties">
<entry key="Application.buildnumber" value="1" type="int" operation="+"/>
</propertyfile>
</target>
- The property file looks like this:
Application.version=1.0.0.
Application.buildnumber=0
- I use a "pre-compile" target that checks if the files
have been changed since the game.properties file was changed.
- Next add the OldStyleGame.jar. Be sure to use the latest version. This code was built with Version 0.5.2.
- Create a new class (BounceCanvas) that extends GameCanvas. Create
a default constructor that calls super(int width, int height);
public class BounceCanvas extends GameCanvas {
public BounceCanvas(int width, int height) {
super(width, height);
}
} - Update the main class (BounceGame), instantiating itself and creating
a GameFrame, with the BounceCanvas.
public class BounceGame {
private BounceCanvas canvas;
public BounceGame() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
BounceGame game = new BounceGame();
game.createFrame();
}
private void createFrame() {
int width = 800;
int height = 600;
GameFrame frame = new GameFrame(width, height);
canvas = new BounceCanvas(width, height);
frame.setGameCanvas(canvas);
}
} - The next step is to load animations. Create a Setup class for putting together all the game pieces.
- Create animation stills for the character movements. Use the ImageFactory to load the images and create individual cells. ImageFactory makes it easy to load up images and easily split it into cells. The ImageFactory is a singleton, create it by calling getInstance().
- Add these into an Animation. There are several types of Animation
classes. The Animation class encapsulates the switching between which
image is to display on the screen for us. Here we will use the LoopedAnimation,
which will loop through the cells at given intervals for us. Once it
reaches the end of images, it will start back at the beginning.
Image charImage = imageFactory.loadImage("images/character.png");
Image[] charImgs = imageFactory.getCellsFromImage(charImage, new Measurements(40, 80), 8, ImageFX.Flipped.NONE);
Animation rightAnimation = new LoopedAnimation(charImgs[0], 100);
rightAnimation.addFrame(charImgs[1], 100);
rightAnimation.addFrame(charImgs[2], 100);
rightAnimation.addFrame(charImgs[3], 100);
Animation leftAnimation = new LoopedAnimation(charImgs[4], 100);
leftAnimation.addFrame(charImgs[5], 100);
leftAnimation.addFrame(charImgs[6], 100);
leftAnimation.addFrame(charImgs[7], 100); - Next we are going to add sound to the Animation, by using the AudioFactory.
This class is a singleton, create it by calling getInstance(). Sounds
are encapsulated in the Audio interface. This setups basic methods that
we need for playing the sound and stopping it.
Audio step1 = audioFactory.loadClipAudio("audios/footsetp1.wav");
- Create a Sound object. Use the RandomSound so the footsteps will change.
This will play the sound as the player walks. The Sound is then added
to a TimeListeningSound, that the Animations can use.
List<Audio> audios = new ArrayList<Audio>();
audios.add(audioFactory.loadClipAudio("audios/Footstep-sneaker1.wav"));
audios.add(audioFactory.loadClipAudio("audios/Footstep-sneaker2.wav"));
audios.add(audioFactory.loadClipAudio("audios/Footstep-sneaker3.wav"));
audios.add(audioFactory.loadClipAudio("audios/Footstep-sneaker4.wav"));
audios.add(audioFactory.loadClipAudio("audios/Footstep-sneaker5.wav"));
audios.add(audioFactory.loadClipAudio("audios/Footstep-sneaker6.wav"));
RandomSound sound = new RandomSound("sneakers", audios);
TimeListeningSound tlSound = new TimeListeningSound(sound, 1280, new long[]{320, 960});
rightAnimation.setSound(tlSound);
leftAnimation.setSound(tlSound); - Add the animations into a Motion class. The motion class, uses the
Sprites direction to determine which animation to use. The Motion class
uses the Sprites GameVector to determine direction.
TwoWayMotion motion = new TwoWayMotion(rightAnimation, leftAnimation);
- Create a Movement class. The Movement class does all the handling
of the sprites movement. For the Character it will move the character
back and forth on the screen, based on two key entries. We set which
keys we want to control the movement. When we add the character to the
GameMap, it will get wired into the input listener for us. Set a speed,
based on how fast you want the character to move. Note: a speed of 1
or greater is VERY fast.
TwoKeyMovement movement = new TwoKeyMovement(KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT);
movement.setSpeed(.4); - Create a class for our player that extends the BaseActor class. This
allows for customization of the sprite. Currently this class doesn't
have anything in it.
public class Batter extends BaseActor {
public Batter(Motion motion, Movement movement, SpriteSize size, Animation stillAnimation) {
super(motion, movement, size, stillAnimation);
}
} - The StillAnimation will simple be the first image in our animation
sequence.
Animation standAnimation = new StaticAnimation(charImgs[0]);
- Now create the player sprite.
Batter batter = new Batter(motion, movement, new SpriteSize(40, 80), standAnimation);
- Now we will create our Ball sprite. Make a Ball class, just like the
Batter class, with the one constructor. Create a BallMovement class
that implements the Movement interface. This is for the custom movement
of the ball. Implement all the abstract methods, and create these class
variables. We'll come back to implementing the other methods.
private GameVector gameVector = new GameVector();
private double currentXMovement = 0.0;
private double currentYMovement = 0.0; - Add a method to create our Ball in the Setup class. Here we will use
a graphic element instead of an image.
Animation ballAnimation = new EllipseShapeAnimation(20, 20, Color.BLUE, true);
Motion motion = new StaticMotion(ballAnimation);
BallMovement movement = new BallMovement();
Ball ball = new Ball(motion, movement, new SpriteSize(20, 20), ballAnimation); - Now we are ready to add these to the GameMap. Update the BounceCanvas
to build the GameMap and add the player and the ball. Stick the player
at the bottom. For now place the ball near the top. The FreeStyleMap
can be setup to keep sprites in the visible area. This is set to false
by default.
public BounceCanvas(int width, int height) {
super(width, height);
GameMap map = new FreeStyleMap(Setup.WIDTH, Setup.HEIGHT);
new FreeStyleRenderer(map);
map.setCollisionMap(new SimpleCollisionDetection(map));
Setup setup = new Setup();
Actor player = setup.loadCharacter();
map.setPlayer(player, new GameLocation(20, 515));
Actor ball = setup.loadBall();
map.addSprite(ball, new GameLocation(300, 40)); setGameMap(map);
} - Run the game. The character will move across the bottom based on you key pressed. You will hear his foot steps as he walks. The ball will float above him.
- To make the ball move, update the BallMovement.
private GameVector gameVector = new GameVector();
private double currentXMovement = 0.0;
private double currentYMovement = 0.0;
private double speed = 2;
private boolean movingDown = true;
private Random r = new Random(new Date().getTime());
public BallMovement() {
int offset = r.nextInt(30) - 15;
gameVector.setDirection(90 + offset);
gameVector.setSpeedXY(speed);
}
@Override
public void collideVertical() {
// This gets called when the ball hits the player.
gameVector.setYMagnitude(-gameVector.getYMagnitude());
}
public boolean isMovingLeft() {
return gameVector.getXMagnitude() < 0;
}
public boolean isMovingRight() {
return gameVector.getXMagnitude() > 0;
}
public boolean isMovingUp() {
return gameVector.getYMagnitude() < 0;
}
public void setHitLeftWall() {
gameVector.setXMagnitude(-gameVector.getXMagnitude());
}
public void setHitRightWall() {
gameVector.setXMagnitude(-gameVector.getXMagnitude());
}
public void setHitTopWall() {
gameVector.setYMagnitude(-gameVector.getYMagnitude());
}
@Override
public void update(long l) {
currentXMovement = gameVector.getXMagnitude();
currentYMovement = gameVector.getYMagnitude();
//
} - Next update the Ball's update method.
public void update(long elaspeTime) {
super.update(elaspeTime);
BallMovement bm = (BallMovement) movement;
if (location.x <= 0 && bm.isMovingLeft()) {
// hit left wall
bm.setHitLeftWall();
}
else if (location.x >= (780) && bm.isMovingRight()) {
// hit right wall.
bm.setHitRightWall();
}
if (location.y < 0 && bm.isMovingUp()) {
bm.setHitTopWall();
}
} - The old style frame work helps you get the basics. The source code for this example can be download from here. Source code