You are here

Chapter 23: Add a ship among our asteroids

In this chapter we will finally add our ship!

It will not be cotrollable yet though, as handling of touch events is the topic for next chapter.

 

First, we need to make a few changes to our ship-image. 100 pixels is too big compared to the asteroid sizes.

I scaled down ship_100.png to 50 pixels, and called it "ship.png". I then made a copy, shifted it's colours to the red spectra and called it "ship_highlighted.png".

Then some coding.

Create "ship.java":

package com.ajomannen.justroids;

import java.util.List;

import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;

public class Ship extends GfxObject {
  private Paint paint;

  public Ship(Resources resources, float x, float y, double velocity,
    double direction, int angle) {
   paint = new Paint();
   bitmap = BitmapFactory.decodeResource(resources, R.drawable.ship);
   bitmapHighlighted = BitmapFactory.decodeResource(resources,
     R.drawable.ship_highlighted);
   this.x = x;
   this.y = y;
   setVelocity(velocity);
   setDirection(direction);
   this.angle = angle;
  }

  public void update(float screenWidth, float screenHeight,
    List<Asteroid> asteroids) {
   float dX;
   float dY;
   float distance;

   move(screenWidth, screenHeight);
   setCollided(false);
   for (Asteroid asteroid : asteroids) {
    dX = Math.abs(x - asteroid.x);
    dY = Math.abs(y - asteroid.y);
    distance = (float) Math.sqrt(dX * dX + dY * dY);
    if (distance <= (bitmap.getWidth() / 2 + asteroid.bitmap.getWidth() / 2)) {
     collided = true;
    }
   }
  }

  public void draw(Canvas canvas) {
   draw(canvas, x, y, paint);
  }

}

The "ship" is similar to "asteroid", apart from that we will not use a handler for it, so a few extra methods needs to be there. I chose to enable collision detection right away, but I only highlight the ship for now. No crashes yet.

I also had to do a few minor changes to GfxObject.java:

package com.ajomannen.justroids;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;

public class GfxObject {

  protected Bitmap bitmap;
  protected Bitmap bitmapHighlighted;
  protected float x;
  protected float y;
  private double velocity = 0;
  private double direction = 0;
  private double dX = 0;
  private double dY = 0;
  protected int rotation = 0;
  protected int angle = 0;
  protected boolean collided = false;

  public boolean isCollided() {
   return collided;
  }

  public void setCollided(boolean collided) {
   this.collided = collided;
  }

  public double getVelocity() {
   return velocity;
  }

  public void setVelocity(double velocity) {
   this.velocity = velocity;
   calculateDXDY();
  }

  public double getDirection() {
   return direction;
  }

  public void setDirection(double direction) {
   this.direction = direction;
   calculateDXDY();
  }

  private void calculateDXDY() {
   double radians = Math.toRadians(direction-90);
   dX = Math.cos(radians) * velocity;
   dY = Math.sin(radians) * velocity;
  }

  public void move(float screenWidth, float screenHeight) {
   float minX = 0 - bitmap.getWidth() / 2;
   float maxX = screenWidth + bitmap.getWidth() / 2;
   float minY = 0 - bitmap.getHeight() / 2;
   float maxY = screenHeight + bitmap.getHeight() / 2;

   x += dX;
   y += dY;
   if (x > maxX)
    x = minX;
   if (x < minX)
    x = maxX;
   if (y > maxY)
    y = minY;
   if (y < minY)
    y = maxY;

   angle += rotation;
   if (Math.abs(angle) >= 360)
    angle = 0;
  }

  public void draw(Canvas canvas, float x, float y, Paint paint) {
   canvas.save(Canvas.MATRIX_SAVE_FLAG);
   canvas.rotate(angle, x, y);
   if (collided) {
    canvas.drawBitmap(bitmapHighlighted,
      x - bitmapHighlighted.getWidth() / 2,
      y - bitmapHighlighted.getHeight() / 2, paint);
   } else {
    canvas.drawBitmap(bitmap, x - bitmap.getWidth() / 2,
      y - bitmap.getHeight() / 2, paint);
   }
   canvas.restore();
  }

}

Now we have the possibility to simply add "ship" to our 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 int level;
  private AsteroidHandler asteroidHandler;
  private Ship ship;

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

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

   level = 5;
   asteroidHandler = new AsteroidHandler(resources, level);
   ship = new Ship(resources, 120, 280, 0.1, 0, 0);

   setSurfaceDimensions(240, 320);

  }

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

  public void setSurfaceDimensions(int width, int height) {
   screenWidth = width;
   screenHeight = height;
  }

  public void update() {
   asteroidHandler.update(screenWidth, screenHeight);
   ship.update(screenWidth, screenHeight, asteroidHandler.asteroids);
  }

  public void draw(Canvas canvas) {
   canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), blackPaint);
   asteroidHandler.draw(canvas);
   ship.draw(canvas);
  }

}

I then took the opportunity to completely remove the collision detection from AsteroidHandler, as  we now have it in Ship. I also had to make the asteroid list public, so that our ship can walk through it during it's collision detection. The asteroids' initial positions and direction was also changed: 

package com.ajomannen.justroids;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;

public class AsteroidHandler {
  private Bitmap[] asteroidBitmaps;
  private Bitmap[] asteroidBitmapsHighlighted;
  public List<Asteroid> asteroids;
  private Random random;
  private Paint paint;

  public AsteroidHandler(Resources resources, int level) {
   random = new Random();

   paint = new Paint();

   asteroidBitmaps = new Bitmap[3];
   asteroidBitmaps[Asteroid.WHOLE] = BitmapFactory.decodeResource(
     resources, R.drawable.asteroid_whole);
   asteroidBitmaps[Asteroid.HALF] = BitmapFactory.decodeResource(
     resources, R.drawable.asteroid_half);
   asteroidBitmaps[Asteroid.QUARTER] = BitmapFactory.decodeResource(
     resources, R.drawable.asteroid_quarter);

   asteroidBitmapsHighlighted = new Bitmap[3];
   asteroidBitmapsHighlighted[Asteroid.WHOLE] = BitmapFactory
     .decodeResource(resources,
       R.drawable.asteroid_whole_highlighted);
   asteroidBitmapsHighlighted[Asteroid.HALF] = BitmapFactory
     .decodeResource(resources, R.drawable.asteroid_half_highlighted);
   asteroidBitmapsHighlighted[Asteroid.QUARTER] = BitmapFactory
     .decodeResource(resources,
       R.drawable.asteroid_quarter_highlighted);

   asteroids = new ArrayList<Asteroid>();
   float x;
   float y;
   double velocity;
   double direction;
   int rotation;

   for (int i = 0; i < level; i++) {
    x = 240 * random.nextFloat();
    y = 50 * random.nextFloat();
    velocity = 0.2 + 0.5 * i;
    direction = 180 - 45 + 90 * random.nextFloat();
    rotation = -1 - random.nextInt(3);
    asteroids.add(new Asteroid(asteroidBitmaps[Asteroid.WHOLE],
      asteroidBitmapsHighlighted[Asteroid.WHOLE], Asteroid.WHOLE,
      x, y, velocity, direction, rotation));
   }
  }

  public void update(float screenWidth, float screenHeight) {

   for (Asteroid thisAsteroid : asteroids) {
    thisAsteroid.move(screenWidth, screenHeight);
   }
  }

  public void draw(Canvas canvas) {
   for (Asteroid asteroid : asteroids) {
    asteroid.draw(canvas, asteroid.x, asteroid.y, paint);
   }
  }

}

 

Well, that's about it. We now have a (very) slowly moving ship, that turns red when it collides with an asteroid.

Great!

In next chapter we will add the possibility to move it also.

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer