How to restart a Java Thread in an Android game?

881 Views Asked by At

I am creating a demo game in Android for learning purposes. In the game, when a collision is detected between two objects - I want to show a "game over" dialog. Inside the dialog box there is a play again button. When pressed, the thread should be started again.

I am getting the following error java.lang.IllegalThreadStateException: Thread already started .

Here is my code:

public class GamePanel extends SurfaceView implements Runnable {

    private Thread thread = null;
    private Ball ball;
    private SurfaceHolder surfaceHolder;
    private Paint paint;
    private Canvas canvas;

    volatile boolean playing = true;

    private int hurdleCount = 3;
    private Hurdles[] hurdles;

    private int screenX, screenY;
    private Rect ball_detectCollision;

    public GamePanel(Context context, final int screenX, final int screenY) {
        super(context);

        ball = new Ball(context, screenX, screenY);
        surfaceHolder = getHolder();

        this.screenX = screenX;
        this.screenY = screenY;

        paint = new Paint();
        canvas = new Canvas();

        hurdles = new Hurdles[hurdleCount];
        for (int i = 0; i < hurdleCount; i++) {
            hurdles[i] = new Hurdles(context, screenX, screenY);
        }

        ball_detectCollision = new Rect(ball.getBall_x(), ball.getBall_y(), ball.getBitmap().getWidth(), ball.getBitmap().getHeight());
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceCreated(SurfaceHolder holder) {

                System.out.println("Surface Created");
                setUpdated_x(ball.getBall_x());
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

                System.out.println("Surface Changed");
                thread = new Thread(GamePanel.this);
                thread.start();
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

                System.out.println("Surface Destroyed");
            }
        });
    }

    public int getUpdated_x() {
        return updated_x;
    }

    public void setUpdated_x(int updated_x) {
        this.updated_x = updated_x;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        setUpdated_x((int) event.getX());

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_UP:

                break;

            case MotionEvent.ACTION_DOWN:

                initial_X = getUpdated_x();
                break;

            case MotionEvent.ACTION_MOVE:

                if (getUpdated_x() < screenX - ball.getBitmap().getWidth() || getUpdated_x() > screenX - ball.getBitmap().getWidth()) {
                    draw(getUpdated_x());
                }
                break;
        }
        return true;
    }

    private void draw(int updatedValue) {

        canvas = surfaceHolder.lockCanvas();
        canvas.drawColor(Color.RED);
        canvas.drawBitmap(ball.getBitmap(), updatedValue, ball.getBall_y(), paint);
        ball.setBall_x(updatedValue);

        ball_detectCollision.left = ball.getBall_x();
        ball_detectCollision.top = screenY - ball.getBitmap().getHeight() - 260;
        ball_detectCollision.right = ball.getBall_x() + ball.getBitmap().getWidth();
        ball_detectCollision.bottom = screenY - ball.getBitmap().getHeight() - 260 + ball.getBitmap().getHeight();

        for (int i = 0; i < hurdleCount; i++) {
            canvas.drawBitmap(hurdles[i].getBitmap(), hurdles[i].getX(), hurdles[i].getY(), paint);
        }
        surfaceHolder.unlockCanvasAndPost(canvas);
    }

    @Override
    public void run() {

        while (playing) {
            update();
            draw(getUpdated_x());
            control();
        }
    }

    private void update() {

        for (int i = 0; i < hurdleCount; i++) {
            hurdles[i].update();

            if (Rect.intersects(getBall_detectCollision(), hurdles[i].getDetectCollision())) {
                System.out.println("Collision Detected");

                playing = false;
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        showGameOverMessage();

                    }
                });
            }
        }
    }


    public void pause() {

        playing = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void showGameOverMessage() {

        Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();
        Dialog showDialog = new Dialog(getContext());
        showDialog.setContentView(R.layout.dialog_game_over);
        Button playAgainButton = (Button) showDialog.findViewById(R.id.playAgainButton);
        playAgainButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                playing = true;
                thread.start();
            }
        });
        showDialog.show();

    }
}
2

There are 2 best solutions below

3
On

When the game is over, just stop the thread and play again button should kick a new thread.

If you need to save any instance of your previous thread, do save them in external variables. There are plenty of options in this case anyway.

Edit

You stopped your thread perfectly. You just have to start a new thread when you want the new game to be started.

I would suggest to keep a function like this and remove implements Runnable.

private void startGame() {
    // Start a new game
    playing = true; 

    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                while (playing) {
                    update();
                    draw(getUpdated_x());
                    control();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    thread.start();
}
1
On

You can't restart a stopped thread. The solution is to simply instantiate a new one and start it.