You are here

Chapter 35: Surface dimensions during game start-up

I tested JustRoids on a few different devices, and noticed that the ship's starting position isn't exactly according to what I originally wanted: in the middle at the bottom of the screen.

The reason for this is just as simple as the reason that the missiles had strange trajectories - we hard coded some values instead of using a proper calculation.

In GameEngine.setLevel() we create the ship at a specific position:

private void setLevel(int level) {
  gameStatus.setLevel(level);
  asteroidHandler = new AsteroidHandler(resources, level);
  missileHandler = new MissileHandler(resources);
  ship = new Ship(resources, 120, 280, 0.1, 0, 0);
}

The reason I did that, was due to the fact that Android does not provide any means to get the dimensions of a surface until during the layout stage, which occurs before anything is drawn but after the construction. If the getWidth() and getHeight() methods are called too early, they will just return zero. (That's also the reason I call "setSurfaceDimensions(240, 320)" in GameEngine.Init(), just so that there will some value there during the first update-phase.)

But as soon as Android knows the dimensions, the following method in GameSurface is called automatically:

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  gameEngine.setSurfaceDimensions(width, height);
}

And in it we forward the values to GameEngine, so that the correct height and width are there for the rest of the game.

In order to have the ship at the right place from the beginning, we could simply wait until that call before we create it.

This requires minor changes in a few different places in the GameEngine:

package com.ajomannen.justroids;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;

public class GameEngine {

  Context context;
  Resources resources;

  public float screenWidth;
  public float screenHeight;
  private Paint blackPaint;

  private AsteroidHandler asteroidHandler;
  private MissileHandler missileHandler;
  private Ship ship;
  private GameStatus gameStatus;

  public static final int EVENT_NONE = 0;
  public static final int EVENT_LEFT = 1;
  public static final int EVENT_RIGHT = 2;
  public static final int EVENT_THRUST = 3;
  public static final int EVENT_FIRE = 4;
  public int pendingEvent = EVENT_NONE;

  private boolean surfaceReady = false;

  public void Init(Context context) {
   this.context = context;
   resources = context.getResources();

   blackPaint = new Paint();
   blackPaint.setColor(Color.BLACK);
   blackPaint.setStyle(Style.FILL);

   gameStatus = new GameStatus();

   // setLevel(1);
   // setSurfaceDimensions(240, 320);
  }

  private void setLevel(int level) {
   gameStatus.setLevel(level);
   asteroidHandler = new AsteroidHandler(resources, level);
   missileHandler = new MissileHandler(resources);
   // ship = new Ship(resources, 120, 280, 0.1, 0, 0);
   ship = new Ship(resources, screenWidth / 2, screenHeight - 30, 0.1, 0, 0);
  }

  public void onDestroy() {
   try {
   } catch (Exception e) {
   }
  }

  public void setSurfaceDimensions(int width, int height) {
   screenWidth = width;
   screenHeight = height;
   if (!surfaceReady) {
    setLevel(1);
    surfaceReady = true;
   }

  }

  public void update() {
   gameStatus.update();
   if (surfaceReady && gameStatus.getPassedLevelTime() > 0) {
    asteroidHandler.update(screenWidth, screenHeight);
    ship.update(screenWidth, screenHeight, asteroidHandler.asteroids,
      pendingEvent, gameStatus);
    missileHandler.update(screenWidth, screenHeight, pendingEvent,
      ship, asteroidHandler.asteroids, gameStatus);
    pendingEvent = EVENT_NONE;

    if (asteroidHandler.asteroids.isEmpty())
     setLevel(gameStatus.getLevel() + 1);

   }
  }

  public void draw(Canvas canvas) {
   if (surfaceReady) {
    canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(),
      blackPaint);
    asteroidHandler.draw(canvas);
    missileHandler.draw(canvas);
    ship.draw(canvas);
    gameStatus.draw(canvas, screenHeight, screenWidth);
   }
  }

}

Now we have the ship nicely located where we want it when each level starts:

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer