2

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)
Dominik Schmidt
  • 537
  • 1
  • 8
  • 22
  • 1
    You should probably create the surfaceview onResume instead of onCreate. It gets called either for a new instance of your activity or if resumed. Keep the data that you need onPause and restore it onResume and basically reload. You can check if the surfaceview is destroyed to not waste time rebuilding every single time, but basically be ready if you need to – MiltoxBeyond Jul 15 '15 at 15:49
  • @MiltoxBeyond I just tried it but it doesn't work either.. The game rendering thread still never stops and the SurfaceView doesn't get recreated after being destroyed – Dominik Schmidt Jul 15 '15 at 15:56
  • 1
    On pause you should be also manually telling your thread to pause. Oh and Android doesn't immediately call onpause it depends on resources available. There is also this answer that should help you out: http://stackoverflow.com/questions/3527621/how-to-pause-and-resume-a-surfaceview-thread – MiltoxBeyond Jul 15 '15 at 16:13

0 Answers0