I know similar questions have been asked before but none of those solutions worked for me.
I'm trying to create a small 2D game for Android and I am having some problems using SurfaceView.
My main activity currently looks like this:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private DrawingSurface drawingsurface;
private Game game;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate()");
setFullscreen();
game = new Game();
drawingsurface = new DrawingSurface(this, game);
setContentView(drawingsurface);
}
private void setFullscreen() {
// ...
}
}
As you can see, I set my activity to fullscreen, create a new SurfaceView (called drawingSurface) and create a new game instance.
My SurfaceView (called DrawingSurface) looks like this:
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
private GameThread thread;
private static final String TAG = "DrawingSurface";
public DrawingSurface(Context context, Game game) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
// create a new game rendering thread and pass it game so it can call the update() and render() functions of game:
thread = new GameThread(getHolder(), this, game);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.v(TAG, "surfaceCreated()");
// start the rendering thread:
thread.setRunning(true);
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.v(TAG, "surfaceChanged()");
// do I need to do anything in here?
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// stop the rendering thread:
Log.v(TAG, "surfaceDestroyed()");
thread.setRunning(false);
boolean retry = true;
while (retry) {
try {
thread.join();
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// pass the touch event to the Game instance (to keep everything in on place)
thread.game.onTouchEvent(event);
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
// I don't use onDraw(), instead I have my own update() and render() functions in my game thread
super.onDraw(canvas);
}
}
This is my game thread:
public class GameThread extends Thread {
private boolean running;
private SurfaceHolder surfaceHolder;
private DrawingSurface drawingSurface;
private static final String TAG = GameThread.class.getSimpleName();
protected Game game;
public GameThread(SurfaceHolder surfaceHolder, DrawingSurface drawingSurface, Game game) {
super();
this.surfaceHolder = surfaceHolder;
this.drawingSurface = drawingSurface;
this.game = game;
}
public void setRunning(boolean running) {
this.running = running;
}
@SuppressLint("WrongCall")
@Override
public void run() {
Log.d(TAG, "Starting game loop");
long now;
long dt;
long last = System.currentTimeMillis();
Canvas canvas;
while (running) {
Log.v(TAG, "GameThread running");
canvas = null;
/* try locking the canvas for exclusive
pixel editing in the surface */
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (this.surfaceHolder) {
now = System.currentTimeMillis();
dt = (now - last);
this.game.update(dt);
if(canvas != null)
this.game.render(canvas, dt);
last = now;
}
} finally {
/*in case of an exception the surface
is not left in an inconsistent state */
if (canvas != null) {
this.surfaceHolder.unlockCanvasAndPost(canvas);
}
}
if (dt < 16) {
try {
Thread.sleep(16 - dt);
} catch (InterruptedException e) {
}
}
}
}
}
And this is the Game class:
public class Game {
private static final String TAG = "Game";
private static int playerRefPosX = 40;
private int playerY = 0;
private int playerVelY = 1;
public Game() {
Log.v(TAG, "Game instance created");
}
public void update(long dt) {
playerY += playerVelY * dt;
if (playerY > 1800) {
playerVelY = -playerVelY;
}
if (playerY < 0) {
playerVelY = -playerVelY;
}
}
public void render(Canvas canvas, long dt) {
canvas.drawColor(Color.BLACK);
// draw Player
Paint paint = new Paint();
paint.setTextSize(100);
paint.setColor(new Color().rgb(255, 0, 0));
canvas.drawRect(playerRefPosX, playerY + 100, playerRefPosX + 200, playerY - 100, paint);
canvas.drawText(String.valueOf(1000/dt), canvas.getWidth()/2, canvas.getWidth()/2, paint);
}
public void onTouchEvent(MotionEvent event) {
Log.v(TAG, "received touch event..");
}
}
The problems I am have right now:
- When I press the home button and reenter the app OR rotate my device it calls surfaceDestroyed() but doesn't recreate it afterwards (the canvas doesn't get repainted)
- The game rendering thread never stops (as indicated by the log messages)