androidandroid-studiosurfaceviewstart-activity

Can I switch activities from a SurfaceView?


I am trying to adapt a snake game in Android Studio so that game over triggers a GameOverActivity. The problem is that the game over text is currently written to the screen in the redrawCanvas() function:

public void redrawCanvas(Canvas canvas) {
        if (this.snake.isEnabled()) {
            this.snake.draw(canvas);
            this.apple.draw(canvas);
            this.score.draw(canvas);
        } else {
            Paint p = getPaint();
            p.setTextSize(50);
            p.setColor(Color.BLACK);
            canvas.drawText("Game over!", 100, 100, p);

            // LAUNCH PLAY AGAIN ACTIVITY HERE?
        }
    }

and this redrawCanvas code is contained in a class extending SurfaceView. I would ordinarily call an intent, but I can't call startActivity() from within a SurfaceView class. My SnakeGameActivity just sets the content view, and all the code occurs in this surface view. Here is the code in SnakeGameActivity:

public class SnakeGameActivity extends com.codepath.simplegame.GameActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        
        //before activity is created : cold start
        //switch back to original Theme (App Theme)
        setTheme(R.style.AppTheme);

        switchFullscreen();
        setContentView(new SnakeGamePanel(this));
    }
}

And here is the full code in SnakeGamePanel:

public class SnakeGamePanel extends AbstractGamePanel {

    public SnakeGamePanel(Context context) {
        super(context);
    }

    private SnakeActor snake;
    private AppleActor apple ;
    private ScoreBoard score;
    private boolean isPaused = false;

    @Override
    public void onStart() {
        this.snake = new SnakeActor(100, 100);
        this.apple = new AppleActor(200, 50);
        this.score = new ScoreBoard(this);
    }

    @Override
    public void onTimer() {
        if (!isPaused) {
            if (this.snake.checkBoundsCollision(this)) {
                this.snake.setEnabled(false);
            }
            this.snake.move();
            if (this.apple.intersect(this.snake)) {
                this.snake.grow();
                this.score.earnPoints(50);
                this.apple.reposition(this);
            }
        }
    }

    @Override
    public void redrawCanvas(Canvas canvas) {
        if (this.snake.isEnabled()) {
            this.snake.draw(canvas);
            this.apple.draw(canvas);
            this.score.draw(canvas);
        } else {
            Paint p = getPaint();
            p.setTextSize(50);
            p.setColor(Color.BLACK);
            canvas.drawText("Game over!", 100, 100, p);

            // LAUNCH PLAY AGAIN ACTIVITY?
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        this.snake.handleKeyInput(keyCode);
        if (keyCode == KeyEvent.KEYCODE_G) {
            this.onStart();
        }
        if (keyCode == KeyEvent.KEYCODE_P) {
            isPaused = !isPaused;
        }
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            this.snake.handleTouchInput(event);
            return true;
        }
        return false;
    }

}

Is there any way to start an activity when the game ends?


Solution

  • One alternative to your inner class solution is to pass a Context object to the constructor of your SurfaceView subclass. Then you can call startActivity() on that context.