Working with Multiple Sprites. Android Game Programming 6.
In this tutorial we are going to see the creation of several sprites. Each sprite with its own position, speed, and orientation moving.
We are going to change in GameView the variable sprite for a List of sprites.
private List<Sprite> sprites = new ArrayList<Sprite>();
We need to copy the characters images in the resource directory as we did with bad1.pgn in the "Android Game Programming 4. Sprites 1". Then we are going to create a new sprite with each image in the contructor.
sprites.add(createSprite(R.drawable.bad1));
sprites.add(createSprite(R.drawable.bad2));
sprites.add(createSprite(R.drawable.bad3));
sprites.add(createSprite(R.drawable.bad4));
sprites.add(createSprite(R.drawable.bad5));
sprites.add(createSprite(R.drawable.bad6));
sprites.add(createSprite(R.drawable.good1));
sprites.add(createSprite(R.drawable.good2));
sprites.add(createSprite(R.drawable.good3));
sprites.add(createSprite(R.drawable.good4));
sprites.add(createSprite(R.drawable.good5));
sprites.add(createSprite(R.drawable.good6));
using this method
private Sprite createSprite(int resouce) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce);
return new Sprite(this,bmp);
}
and update the onDraw method with
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
if we run this we are going to notice an unpleasant efect due to the fact that all sprites start at the same point.
We can fix this easily adding
x = rnd.nextInt(gameView.getWidth() - width);
y = rnd.nextInt(gameView.getHeight() - height);
in the Sprite constructor. But if you run it again you are going to get an error.
If we put a break point in the line we just added and run the application in debug mode, we can get this
here I inspect the value of gameView.getWidth() and I found that the width is 0. What happen here? The problem is that we ask for the view width before the view is ready.
If you remember, we use the surfaceCreated method in the Callback listener to know when the view is ready. We can move the sprites creation to this method and fix our problem.
package com.edu4java.android.killthemall;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView
{
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Sprite> sprites = new ArrayList<Sprite>();
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
private void createSprites() {
sprites.add(createSprite(R.drawable.bad1));
sprites.add(createSprite(R.drawable.bad2));
sprites.add(createSprite(R.drawable.bad3));
sprites.add(createSprite(R.drawable.bad4));
sprites.add(createSprite(R.drawable.bad5));
sprites.add(createSprite(R.drawable.bad6));
sprites.add(createSprite(R.drawable.good1));
sprites.add(createSprite(R.drawable.good2));
sprites.add(createSprite(R.drawable.good3));
sprites.add(createSprite(R.drawable.good4));
sprites.add(createSprite(R.drawable.good5));
sprites.add(createSprite(R.drawable.good6));
}
private Sprite createSprite(int resouce) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce);
return new Sprite(this,bmp);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
}
}
package com.edu4java.android.killthemall;
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Sprite {
// direction = 0 up, 1 left, 2 down, 3 right,
// animation = 3 back, 1 left, 0 front, 2 right
int[] DIRECTION_TO_ANIMATION_MAP = { 3, 1, 0, 2 };
private static final int BMP_ROWS = 4;
private static final int BMP_COLUMNS = 3;
private static final int MAX_SPEED = 5;
private GameView gameView;
private Bitmap bmp;
private int x = 0;
private int y = 0;
private int xSpeed;
private int ySpeed;
private int currentFrame = 0;
private int width;
private int height;
public Sprite(GameView gameView,
Bitmap bmp) {
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight()
/ BMP_ROWS;
this.gameView = gameView;
this.bmp = bmp;
Random rnd = new Random();
x = rnd.nextInt(gameView.getWidth() - width);
y = rnd.nextInt(gameView.getHeight() - height);
xSpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
ySpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
}
private void update() {
if (x >= gameView.getWidth() - width - xSpeed || x + xSpeed <= 0) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y >= gameView.getHeight() - height - ySpeed || y + ySpeed <= 0) {
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = getAnimationRow()
* height;
Rect
src = new Rect(srcX, srcY,
srcX + width, srcY + height);
Rect
dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
private int getAnimationRow() {
double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int direction = (int) Math.round(dirDouble)
% BMP_ROWS;
return DIRECTION_TO_ANIMATION_MAP[direction];
}
}
<< Sprites: Speed and Animation | Touch Events and Sprite Collision Detection >> |