Eager to get going, I just started coding three new "features" into the code:
It didn't work quite the way I hoped it to:
First, asteroids collide way before they actually meet.
Secondly, they get stuck on each other.
It looks really terrible. Worse than the bad rotation.
This is what I did in AsteroidHandler.java. (Bold parts are to handle the concept of "size", red parts are the collision detection and bouncing.):
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 float[] asteroidRadiuses;
private List<Asteroid> asteroids;
private Random random;
private Paint paint;
public AsteroidHandler(Resources resources, int level) {
paint = new Paint();
random = new Random();
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);
asteroidRadiuses = new float[3];
asteroidRadiuses[Asteroid.WHOLE] = 50;
asteroidRadiuses[Asteroid.HALF] = 30;
asteroidRadiuses[Asteroid.QUARTER] = 15;
asteroids = new ArrayList<Asteroid>();
float x;
float y;
double velocity;
double direction;
int rotation;
for (int i = 0; i < level; i++) {
x = 160 * random.nextFloat();
y = 320 * random.nextFloat();
// No random velocity anymore. Each asteroid is faster than the
// previous.
velocity = 0.2 + 0.5 * i;
direction = 360 * random.nextFloat();
rotation = -1 - random.nextInt(3);
asteroids.add(new Asteroid(asteroidBitmaps[Asteroid.WHOLE],
Asteroid.WHOLE, x, y, velocity, direction, rotation));
}
}
public void update(float screenWidth, float screenHeight) {
int index = 0;
Asteroid otherAsteroid;
float dX;
float dY;
float distance;
for (Asteroid thisAsteroid : asteroids) {
thisAsteroid.move(screenWidth, screenHeight);
for (int i = 0; i < index; i++) {
otherAsteroid = asteroids.get(i);
dX = Math.abs(thisAsteroid.x - otherAsteroid.x);
dY = Math.abs(thisAsteroid.y - otherAsteroid.y);
distance = (float) Math.sqrt(dX * dX + dY * dY);
if (distance <= (asteroidRadiuses[thisAsteroid.size] + asteroidRadiuses[otherAsteroid.size])) {
double newDirection = thisAsteroid.getDirection() + 160
+ 40 * random.nextFloat();
if (newDirection >= 360)
newDirection -= 360;
thisAsteroid.setDirection(newDirection);
break;
}
}
index++;
}
}
public void draw(Canvas canvas) {
for (Asteroid asteroid : asteroids)
asteroid.draw(canvas, asteroid.x, asteroid.y, paint);
}
}
As we call getDirection() and getVelocity() for an asteroid above, we have to add those two methods in GfxObject.java also:
public double getVelocity() {
return velocity;
}
public double getDirection() {
return direction;
}
We also have to add "size" to Asteroid.java:
package com.ajomannen.justroids;
import android.graphics.Bitmap;
public class Asteroid extends GfxObject {
static final int WHOLE = 2;
static final int HALF = 1;
static final int QUARTER = 0;
int size;
public Asteroid(Bitmap bitmap, int size, float x, float y, double velocity,
double direction, int rotation) {
this.bitmap = bitmap;
this.size = size;
this.x = x;
this.y = y;
setVelocity(velocity);
setDirection(direction);
this.rotation = rotation;
}
}
My mistakes here are two;
I think I will have to solve the issues one at a time, and start with disabling "bouncing" and just highlight the collided asteroids in a separate color, while I fix the scaling issue.
Let's start with adding a "collided" property to GfxObject:
protected boolean collided = false;
public boolean isCollided() {
return collided;
}
public void setCollided(boolean collided) {
this.collided = collided;
}
Then we comment out the crappy bouncing code and instead set "collided" for both asteroids in AsteroidHandler update() method:
public void update(float screenWidth, float screenHeight) {
int index = 0;
Asteroid otherAsteroid;
float dX;
float dY;
float distance;
for (Asteroid thisAsteroid : asteroids) {
thisAsteroid.move(screenWidth, screenHeight);
thisAsteroid.setCollided(false);
for (int i = 0; i < index; i++) {
otherAsteroid = asteroids.get(i);
dX = Math.abs(thisAsteroid.x - otherAsteroid.x);
dY = Math.abs(thisAsteroid.y - otherAsteroid.y);
distance = (float) Math.sqrt(dX * dX + dY * dY);
if (distance <= (asteroidRadiuses[thisAsteroid.size] + asteroidRadiuses[otherAsteroid.size])) {
thisAsteroid.setCollided(true);
otherAsteroid.setCollided(true);
// double newDirection = thisAsteroid.getDirection() + 160
// + 40 * random.nextFloat();
// if (newDirection >= 360)
// newDirection -= 360;
// thisAsteroid.setDirection(newDirection);
// break;
}
}
index++;
}
}
After that, we can decide how this collision should be illustrated.
I choose to make a very red copy of all three asteroid images and call them "asteroid_xxxx_highlight.png", add a second Bitmap in GfxObject:
protected Bitmap bitmapHighlighted;
and also add it in the constructor in Asteroid:
public Asteroid(Bitmap bitmap, Bitmap bitmapHilighted, int size, float x,
float y, double velocity, double direction, int rotation) {
this.bitmap = bitmap;
this.bitmapHighlighted = bitmapHighlighted;
this.size = size;
this.x = x;
this.y = y;
setVelocity(velocity);
setDirection(direction);
this.rotation = rotation;
}Time to get another Bitmap array into AsteroidHandler:
private Bitmap[] asteroidBitmaps; private Bitmap[] asteroidBitmapsHighlighted;
Populate it with:
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);
And include one of them when creating the asteroids:
asteroids.add(new Asteroid(asteroidBitmaps[Asteroid.WHOLE], asteroidBitmapsHighlighted[Asteroid.WHOLE], Asteroid.WHOLE, x, y, velocity, direction, rotation));
And finally, get the draw() method in GfxObject to choose between the two images:
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();
}Well, this worked like a charm:
Now we have a good trouble-shooting scenario to fix the scaling issue.
Let's do that in next chapter.
Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer