We just need to tie up a few loose ends and we will at last be able to run the game.
Add an instance of the Level
class to GameEngine
.
...
HUD mHUD;
Renderer mRenderer;
ParticleSystem mParticleSystem;
PhysicsEngine mPhysicsEngine;
Level mLevel;
Initialize the instance of Level
in the GameEngine
constructor.
public GameEngine(Context context, Point size) { super(context); mUIController = new UIController(this, size); mGameState = new GameState(this, context); mSoundEngine = new SoundEngine(context); mHUD = new HUD(size); mRenderer = new Renderer(this); mPhysicsEngine = new PhysicsEngine(); mParticleSystem = new ParticleSystem(); mParticleSystem.init(1000); mLevel = new Level(context, new PointF(size.x, size.y), this); }
Now we can add some code to the deSpawnRespawn
method that we coded the signature for in chapter 18. Remember that this method is called by the GameState
class when a new game is needed to start. Add the highlighted code:
public void deSpawnReSpawn() { // Eventually this will despawn // and then respawn all the game objects ArrayList<GameObject> objects = mLevel.getGameObjects(); for(GameObject o : objects){ o.setInactive(); } objects.get(Level.PLAYER_INDEX) .spawn(objects.get(Level.PLAYER_INDEX) .getTransform()); objects.get(Level.BACKGROUND_INDEX) .spawn(objects.get(Level.PLAYER_INDEX) .getTransform()); }
The code creates a new ArrayList
called objects
and initializes it by calling getGameObjects
on the instance of Level
. A for
loop goes through each of the GameObject
instances and sets them to an inactive status.
Next, we call spawn
on the player and then we call spawn
on the background. We use the public static final
variables from the Level
class to make sure we are using the correct index.
Now we can code the body of the method we added for spawning the player's lasers interface method contents.
public boolean spawnPlayerLaser(Transform transform) { ArrayList<GameObject> objects = mLevel.getGameObjects(); if (objects.get(Level.mNextPlayerLaser) .spawn(transform)) { Level.mNextPlayerLaser++; mSoundEngine.playShoot(); if (Level.mNextPlayerLaser == Level.LAST_PLAYER_LASER + 1) { // Just used the last laser Level.mNextPlayerLaser = Level.FIRST_PLAYER_LASER; } } return true; }
The spawnPlayerLaser
method creates and initializes a reference to the ArrayList
of GameObject
instances by calling getGameObjects
.
The code then attempts to spawn a laser from objects at the Level.mNextPlayerLaser
index. If it is successful Level.mNextPlayerLaser
is incremented ready for the next shot and a sound effect is played using the SoundEngine
class.
Finally, there is a nested if
which checks if the LAST_PLAYER_LASER
was used and if it was sets mNextPlayerLaser
back to FIRST_PLAYER_LASER
.
Now, update the run
method to get all the game objects from the Level
class and pass them first into the PhysicsEngine
and then the Renderer
. The new and altered lines are highlighted.
@Override public void run() { while (mGameState.getThreadRunning()) { long frameStartTime = System.currentTimeMillis(); ArrayList<GameObject> objects = mLevel.getGameObjects(); if (!mGameState.getPaused()) { // Update all the game objects here // in a new way // This call to update will evolve // with the project if(mPhysicsEngine.update(mFPS,objects, mGameState, mSoundEngine, mParticleSystem)){ // Player hit deSpawnReSpawn(); } } // Draw all the game objects here // in a new way mRenderer.draw(objects, mGameState, mHUD, mParticleSystem); // Measure the frames per second in the usual way long timeThisFrame = System.currentTimeMillis() - frameStartTime; if (timeThisFrame >= 1) { final int MILLIS_IN_SECOND = 1000; mFPS = MILLIS_IN_SECOND / timeThisFrame; } } }
This new code will have errors until we update the PhysicsEngine
and Renderer
next.
Update the update
method with the new and altered highlighted lines of code.
// This signature and much more will change later in the project boolean update(long fps, ArrayList<GameObject> objects, GameState gs, SoundEngine se, ParticleSystem ps){ // Update all the GameObjects for (GameObject object : objects) { if (object.checkActive()) { object.update(fps, objects.get(Level.PLAYER_INDEX) .getTransform()); } } if(ps.mIsRunning){ ps.update(fps); } return false; }
The first change is with the method signature to accept an ArrayList
of GameObject
instances. The next change is an enhanced for
loop that goes through each of the items in the objects ArrayList
, checks if it is active and if it is calls its update
method.
At this point all the objects are being updated each frame. We just need to be able to see them.
Update the draw
method in GameEngine
with the new and modified lines which are highlighted next.
void draw(ArrayList<GameObject> objects, GameState gs, HUD hud, ParticleSystem ps) { if (mSurfaceHolder.getSurface().isValid()) { mCanvas = mSurfaceHolder.lockCanvas(); mCanvas.drawColor(Color.argb(255, 0, 0, 0)); if (gs.getDrawing()) { // Draw all the game objects here for (GameObject object : objects) { if(object.checkActive()) { object.draw(mCanvas, mPaint); } } } if(gs.getGameOver()) { // Draw a background graphic here objects.get(Level.BACKGROUND_INDEX) .draw(mCanvas, mPaint); } // Draw a particle system explosion here if(ps.mIsRunning){ ps.draw(mCanvas, mPaint); } // Now we draw the HUD on top of everything else hud.draw(mCanvas, mPaint, gs); mSurfaceHolder.unlockCanvasAndPost(mCanvas); } }
First, we updated the method signature to receive the ArrayList
with all the objects in. Next there is an enhanced for
loop that takes each object in turn, checks if it is active and if it is calls its draw
method. The final minor change adds a line of code to the if(gs.getGameOver)
block to draw the background (only) when the game is paused.
18.190.155.49