Specifying all the game objects with GameObjectSpec classes

In the previous project the folder with all our class files was getting a bit crowded. This project will have even more classes, so we will help ourselves a little by separating things out into different packages. We will have a folder(package) for all the GameObjectSpec related classes and a folder for all the Level related classes. Everything else will remain in the usual folder.

When you create a new package, it is important to do so in the correct folder. The correct folder is the same one that we have been putting all the Java files in throughout this book. If you called this project Platformer it will be the app/java/yourdomain.platformer folder.

In the Android Studio solution explorer, right-click the app/java/yourdomain.platformer (NOT yourdomain.platformer(androidTest) and NOT yourdomain.platformer(test)), select New | Package and name it GOSpec.

We will now add a whole bunch of classes that will define all the objects of the game; their sizes, tags (for collision detection mainly), speed, starting location, associated graphic file, frames of animation and a list of components that define their behaviour.

There is one parent class, GameObjectSpec from which all the other specification classes extend. There are lots of them, 23 in total and I don't recommend you sit there and type them all in. They can all be found in the download bundle in the Chapter 22/java/GOSpec folder. You can highlight all the files, copy them and then right-click and Paste them all into the GOSpec folder/package you just created. What you might need to do manually is click into them and check that the package declaration at the top of each file was correctly auto-adjusted from my package name to yours.

If you used Platformer as the project title your package name should be:

package yourdomain.platformer.GOSpec;

Tip

If you check three or four files and the package was auto adjusted correctly then chances are good that they all were, and you don't need to check all 23.

While the specification classes are very similar, I thought it still advantageous to show all the code because they are worth examining. Flick through the next few pages of specification classes. When you look at them take note of the different sizes, speeds, graphics files, frames of animation and especially the different component names in the components array. Here is the complete listing from all the specification classes with a few notes on each.

Note

In a professionally built game it would be more typical to load such things from text files with a single line of text per component or attribute. If you want to upgrade your project (wait until you have it all working in chapter 25 first) you can read about parsing a text file using a simple Web search. However, sorting the required data from the text file is an in-depth process (but not beyond a determined beginner). A simple Web search will provide good example code to get started. By doing things this way we keep all our work inside Android Studio and get to play with making our own packages.

The following list of 23 classes appears in the same order they will appear in Android Studio with the exception that I present the base/parent class to the other 22 classes first to aid understanding.

GameObjectSpec

This is the class that all the …Spec classes will extend. It provides a related member variable/object instance for each of the specifications a game object can have.

import android.graphics.PointF;

public abstract class GameObjectSpec {
    private String mTag;
    private String mBitmapName;
    private float mSpeed;
    private PointF mSize;
    private String[] mComponents;
    private int mFramesAnimation;

    GameObjectSpec(String tag,
                   String bitmapName,
                   float speed,
                   PointF size,
                   String[] components,
                   int framesAnimation ){

        mTag = tag;
        mBitmapName = bitmapName;
        mSpeed = speed;
        mSize = size;
        mComponents = components;
        mFramesAnimation = framesAnimation;
    }

    public int getNumFrames(){
        return mFramesAnimation;
    }

    public String getTag(){
        return mTag;
    }

    public String getBitmapName(){
        return mBitmapName;
    }

    public float getSpeed(){
        return mSpeed;
    }

    public PointF getSize(){
        return mSize;
    }

    public String[] getComponents(){
        return mComponents;
    }
}

The main method (the constructor) has the job of receiving the specifications from all the child classes and copying the values to the member variables/instances. Our code will then be able to handle instances of GameObjectSpec regardless of what the actual game object is; animated, controllable player through to dumb, unmovable tree.

All the other methods of this class are simple getter methods that the various parts of our program can call to find out more about the game object.

BackgroundCitySpec

Review the code for this class and then we can talk about it.

Tip

I will spend more time reviewing this game object because it is the first one we are looking at. In the remaining 22 I will just point out the occasional distinctive feature. It is still important, however, to glance at and make a mental note of the different specifications of the game objects.

import android.graphics.PointF;

public class BackgroundCitySpec extends GameObjectSpec {
    // This is all the specifications for the city background
    private static final String tag = "Background";
    private static final String bitmapName = "city";
    private static final int framesOfAnimation = 1;
    private static final float speed = 3f;
    private static final PointF size = new PointF(100, 70);
    private static final String[] components = new String [] {
             "BackgroundGraphicsComponent",
                      "BackgroundUpdateComponent"};

    public BackgroundCitySpec() {
        super(tag, bitmapName, speed, 
        size, components, framesOfAnimation);
    }
}

The tag is mainly used by the collision detection code we will write in chapter 25. Even the background which doesn't collide needs to be identified so that we can discount it from collision detection.

The bitmapName variable holds the name of the graphics file that is used to represent this game object.

The framesOfAnimation variable is set to 1 because this is not a sprite sheet. The player object on the other hand will be set to 5 because that's how many frames there are and the fire object's framesOfAnimation will be set to 3.

The speed variable in this project is different to that in the previous project because it is the speed in virtual metres per second rather than some convoluted measure relative to the player as it was in the last. Now we are making the jump to game-world based coordinates using a camera we can use these more real-world based size and speed measures.

Next up is size and you can consider the city to be 100 metres by 70 metres. When we code the Camera class in the next chapter we will see how these virtual metres translate to pixels and how we know which parts to show on the screen of the game at any given frame.

We also have a String array for a list of components just like we did in the previous project. The actual components themselves, however will be different to the previous project.

Note

The exception to this is this object, the background, which has very similar components.

Notice the two actual components we will need to code to bring this game object to life:

BackgroundGraphicsComponent
BackgroundUpdateComponent

Finally notice the constructor that does nothing other than pass all the specifications into the parent class constructor which as we saw stashes the values away in the appropriate variables.

BackgroundMountainSpec

This is the same as the previous accept it uses a different graphic, mountain.png.

import android.graphics.PointF;

public class BackgroundMountainSpec extends GameObjectSpec {
    // This is all the specifications for the mountain
    private static final String tag = "Background";
    private static final String bitmapName = "mountain";
    private static final int framesOfAnimation = 1;
    private static final float speed = 3f;
    private static final PointF size = new PointF(100, 70);
    private static final String[] components = new String [] {
            "BackgroundGraphicsComponent",
            "BackgroundUpdateComponent"};

    public BackgroundMountainSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

BackgroundUndergroundSpec

This is the same as the previous accept it uses a different graphic.

import android.graphics.PointF;

public class BackgroundUndergroundSpec extends GameObjectSpec {
    // This is all the specifications for the underground
    private static final String tag = "Background";
    private static final String bitmapName = "underground";
    private static final int framesOfAnimation = 1;
    private static final float speed = 3f;
    private static final PointF size = new PointF(100, 70f);
    private static final String[] components = new String [] {
            "BackgroundGraphicsComponent",
            "BackgroundUpdateComponent"};

    public BackgroundUndergroundSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

BrickTileSpec

This is a regular platform tile. Bob will be able to walk on it, so we will need to perform collision detection on it. Its position in the game world never changes so it is technically inanimate. Note though that the relative position of the block on the screen to the camera will change and the brick graphic will need to be drawn accordingly but the Camera class will take care of all of that.

import android.graphics.PointF;

public class BrickTileSpec extends GameObjectSpec {

    private static final String tag = "Inert Tile";
    private static final String bitmapName = "brick";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String[]{
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public BrickTileSpec() {
        super(tag, bitmapName, speed,
                size, components, framesOfAnimation);
    }
}

Finally notice the size is just one virtual metre wide and high.

CartTileSpec

This specification has the same components as the previous one but note we can assign any value for size we like. This mine cart object is two metres by one metre. The graphic must of course be drawn to suit the size otherwise it will appear squashed or stretched.

import android.graphics.PointF;

public class CartTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "cart";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(2f, 1f);
    private static final String[] components = new String[]{
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public CartTileSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

CoalTileSpec

Just another walkable tile.

import android.graphics.PointF;

public class CoalTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "coal";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public CoalTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

CollectibleObjectSpec

Although this next object has quite a different use to say the brick object, notice that everything is the same apart from the graphic file and the tag. This is fine.

import android.graphics.PointF;

public class CollectibleObjectSpec extends GameObjectSpec {
    private static final String tag = "Collectible";
    private static final String bitmapName = "coin";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public CollectibleObjectSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

We can detect a collision and determine that it is a collectible item from its tag and then handle what should happen.

ConcreteTileSpec

Just another walkable tile.

import android.graphics.PointF;

public class ConcreteTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "concrete";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public ConcreteTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

DeadTreeTileSpec

This tile has minor differences to those we have seen so far. Firstly, it is quite large 2 metres by 4 metres. It also uses a DecorativeBlockUpdateComponent instead of an InanimateBlockUpdateComponent. The differences between these components in code is small but useful. As trees are just decoration in the background we will not bother to add or update a collider thus saving a few computation cycles per tree, per frame.

import android.graphics.PointF;

public class DeadTreeTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "dead_tree";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(2f, 4f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "DecorativeBlockUpdateComponent"};

    public DeadTreeTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the code and move on.

FireTileSpec

This is the first component we have seen that has more than one frame of animation. Our code will detect that an Animator object needs to be assigned to this game object and will manage a simple flickering effect on the fire tile using the frames from the sprite sheet fire.png.

import android.graphics.PointF;

public class FireTileSpec extends GameObjectSpec {
    private static final String tag = "Death";
    private static final String bitmapName = "fire";
    private static final int framesOfAnimation = 3;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String[]{
            "AnimatedGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public FireTileSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

Also notice that the AnimatedGraphicsComponent is used instead of the InanimateBlockGraphicsComponent.

GrassTileSpec

This another walkable tile.

import android.graphics.PointF;

public class GrassTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "turf";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String[]{
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public GrassTileSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

Review the code and move on.

This next spec is for the blocks that will cause the player to instantly die and end the game. It helps the level designer prevent embarrassing bugs like falling out of the game world.

package com.gamecodeschool.c22platformer.GOSpec;
import android.graphics.PointF;

public class InvisibleDeathTenByTenSpec 
	extends GameObjectSpec {
	
    private static final String tag = "Death";
    private static final String bitmapName = "death_visible";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(10f, 10f);
    private static final String[] components 
      = new String[]{"InanimateBlockGraphicsComponent", 
   	"InanimateBlockUpdateComponent"};

    public InvisibleDeathTenByTenSpec() {
        super(tag, 
         bitmapName, 
         speed, 
         size, 
         components, 
         framesOfAnimation);
    }
}

Review the code and move on.

LamppostTileSpec

This is the same as a tree that we discussed previously except the size and the graphic. Review the specifications and move on.

import android.graphics.PointF;

public class LamppostTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "lamppost";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 4f);
    private static final String[] components = new String[]{
            "InanimateBlockGraphicsComponent",
            "DecorativeBlockUpdateComponent"};

    public LamppostTileSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

Review the code and move on.

MoveablePlatformSpec

This game object is new. Notice the MovableBlockUpdateComponent. We will code these to make these platforms move in the game world allowing the player to jump on them and be transported up and down.

import android.graphics.PointF;

public class MoveablePlatformSpec extends GameObjectSpec {
    private static final String tag = "Movable Platform";
    private static final String bitmapName = "platform";
    private static final int framesOfAnimation = 1;
    private static final float speed = 3f;
    private static final PointF size = new PointF(2f, 1f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "MovableBlockUpdateComponent"};

    public MoveablePlatformSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Note that we can still use a regular InanimateBlockGraphicsComponent. Just in case it is causing confusion, inanimate refers to the fact it doesn't use a sprite sheet (has no frames of animation), we can still change its location in the game world (move it) via the MoveableBlockUpdateComponent.

ObjectiveTileSpec

The objective game object is an important game object because it triggers the player reaching the end of the level. However, as with the collectible object all the significant functionality can be handled by the PhysicsEngine via its unique tag and no new components or features are needed for this game object's specification.

import android.graphics.PointF;

public class ObjectiveTileSpec extends GameObjectSpec {
    private static final String tag = "Objective Tile";
    private static final String bitmapName = "objective";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(3f, 3f);
    private static final String[] components = new String[]{
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public ObjectiveTileSpec() {
        super(tag, bitmapName, speed, size,
                components, framesOfAnimation);
    }
}

PlayerSpec

This is perhaps unsurprisingly our most advanced game object. It has an AnimatedGraphicsComponent just as the fire tile does so that it sprite sheet graphic is used to animate its appearance. It also has a specific PlayerUpdateComponent that will be much more advanced than all the other …Update… components. It will handle things like moving, jumping and falling. The PlayerInputComponent will communicate with the GameEngine class to receive and translate the players screen touches. The communication method will use the same Observer pattern that we learnt for the previous project.

import android.graphics.PointF;

public class PlayerSpec extends GameObjectSpec {
    // This is all the unique specifications for a player
    private static final String tag = "Player";
    private static final String bitmapName = "player";
    private static final int framesOfAnimation = 5;
    private static final float speed = 10f;
    private static final PointF size = new PointF(1f, 2f);
    private static final String[] components = new String [] {
            "PlayerInputComponent",
            "AnimatedGraphicsComponent",
            "PlayerUpdateComponent"};

    public PlayerSpec() {
        super(tag, bitmapName, speed, 
                size, components, framesOfAnimation);
    }
}

Review the code and move on.

ScorchedTileSpec

Another simple walkable object.

import android.graphics.PointF;

public class ScorchedTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "scorched";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public ScorchedTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

SnowTileSpec

Another simple walkable object.

import android.graphics.PointF;

public class SnowTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "snow";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(1f, 1f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "InanimateBlockUpdateComponent"};

    public SnowTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

SnowyTreeTileSpec

Just like the dead tree but lusher and covered in snow.

import android.graphics.PointF;

public class SnowyTreeTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "snowy_tree";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(3f, 6f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "DecorativeBlockUpdateComponent"};

    public SnowyTreeTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

StalactiteTileSpec

This is another purely decorative game object.

import android.graphics.PointF;

public class StalactiteTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "stalactite";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(2f, 4f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "DecorativeBlockUpdateComponent"};

    public StalactiteTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

StalagmiteTileSpec

This is another purely decorative object.

import android.graphics.PointF;

public class StalagmiteTileSpec extends GameObjectSpec {
    private static final String tag = "Inert Tile";
    private static final String bitmapName = "stalagmite";
    private static final int framesOfAnimation = 1;
    private static final float speed = 0f;
    private static final PointF size = new PointF(2f, 4f);
    private static final String[] components = new String [] {
            "InanimateBlockGraphicsComponent",
            "DecorativeBlockUpdateComponent"};

    public StalagmiteTileSpec() {
        super(tag, bitmapName, speed, size, 
                components, framesOfAnimation);
    }
}

Review the specifications and move on.

StonePileTileSpec

A pile of stones the player can jump on.

import android.graphics.PointF;

public class StonePileTileSpec extends GameObjectSpec {
        private static final String tag = "Inert Tile";
        private static final String bitmapName = "stone_pile";
        private static final int framesOfAnimation = 1;
        private static final float speed = 0f;
        private static final PointF size = new PointF(2f, 1f);
        private static final String[] components = new String [] {
                "InanimateBlockGraphicsComponent",
                "InanimateBlockUpdateComponent"};

        public StonePileTileSpec() {
            super(tag, bitmapName, speed, size, 
                    components, framesOfAnimation);
        }
}

Review the specifications and move on.

Summary of component classes

Looking at the components you will notice the three main types each has. We will therefore need a graphics, update and input related interface. We will code them now. Throughout the rest of this project we will then code the classes that implement these interfaces and match the component classes we just saw in the GameObjectSpec related classes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.109.21