Reputation: 11
I am writing a breakout Game and everything is working fine except one little thing.
I have a ball object which extends from thread and RepainterThread which can either implement Runnable or extends Thread which calls the paint method which re-renders the game field with bricks, a paddle, and a Ball
I have a Singelton GameController which connects all things.
I have a GameState with an isActive boolean to decide if the game should be paused or not.
I start the game and I can play and the program behaves as it should. The Frame gets drawn the ball moves the bricks break when the ball hits everything fine.
Then I pause the game via a Button where I set is Active to false. The Ball stops as it should. Then I hit the continue Button and isActive is again true. The ball object starts running again and the running method of Repainter Thread is allso triggered but the Swing Frame Freezes completely.
I tried various things these are my nearest approaches i have.
I spent days on it please help
public class Ball extends MovingObject {
private double hSpeed; // Horizontal velocity
private double vSpeed; // Vertical velocity
public Ball() {
this.color = Color.MAGENTA;
this.height = GameSettings.ballSize;
this.width = GameSettings.ballSize;
this.position = new Point2D.Double(GameSettings.defaultBallX, GameSettings.defaultBallY);
this.hSpeed = GameSettings.ballHSpeed;
this.vSpeed = GameSettings.ballYSpeed;
}
public Ball(Ball ball) {
color = ball.color;
height = ball.height;
width = ball.width;
position = ball.position;
hSpeed = ball.hSpeed;
vSpeed = ball.vSpeed;
}
public double getHSpeed() {
return this.hSpeed;
}
public double getVSpeed() {
return this.vSpeed;
}
public void run() {
try {
while (GameController.getInstance().getGameState().isActive()) {
System.out.println("Ich run im Ball");
Thread.sleep(10);
this.meetingWall();
this.meetingBrick();
this.position.setLocation(this.getPosition().getX() + this.hSpeed,
this.getPosition().getY() + this.vSpeed);
if (this.meetingPaddle()) {
this.newDirection();
}
if (this.out()) {
GameController.getInstance().stopGame();
this.stopThread();
}
this.position = this.getPosition();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void stopThread() {
GameController.getInstance().getGameState().setActive(false);
}
public void startThreadAgain() {
this.run();
}
@Override
public synchronized void start() {
this.position.setLocation(GameSettings.defaultBallX, GameSettings.defaultBallY);
super.start();
}
class GamePanel extends JPanel {
private static final long serialVersionUID = 1L;
private final Color backgroundColor = Color.BLACK;
GameState gameState = GameController.getInstance().getGameState();
public GamePanel() {
super();
this.addKeyListener(new KeyListener() {
// Dieser KeyListener soll auf Inputs der Pfeiltasten nach links
// <- und rechts -> hoeren und eine entsprechende Bewegung des
// Schlaegers erwirken, aber nur, wenn das Spiel nicht
// pausiert/gestoppt ist.
public void keyPressed(KeyEvent keyEvent) {
if (gameState.isActive()) {// gameState.isActive()
if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
gameState.getPaddle().setPositionRigth();
}
if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
gameState.getPaddle().setPositionLeft();
}
}
}
public void keyReleased(KeyEvent keyEvent) {
// TODO
}
public void keyTyped(KeyEvent arg0) {
}
});
}
public void paint(Graphics g) {
Graphics2D graphics2D = (Graphics2D) g;
graphics2D.setColor(this.backgroundColor);
graphics2D.fillRect(0, 0, this.getWidth(), this.getHeight());
for (int i = 0; i < gameState.getBricks().length; i++) {
for (int j = 0; j < gameState.getBricks()[i].length; j++) {
if ((gameState.getBricks()[i][j] != null)) {
graphics2D.setColor(gameState.getBricks()[i][j].getColor());
graphics2D.fillRect(
(i * GameSettings.brickWidth) + (i + 1) * (GameSettings.spaceAroundBrick + 1),
(j * GameSettings.brickHeight) + (j + 1) * GameSettings.spaceAroundBrick,
GameSettings.brickWidth, GameSettings.brickHeight);
}
scoreLabel.setText(this.gameState.getScore() + "");
gameState.getPaddle().draw(graphics2D);
gameState.getBall().draw(graphics2D);
}
}
}
}
// First Approach
private class RepainterThread implements Runnable {
public RepainterThread() {
System.out.println("RepainThreadCOntructor");
}
private void updateGUI() {
System.out.println("before invoke later");
System.out.println("repaint");
getGamePanel().requestFocus();
getGamePanel().repaint();
}
@Override
public void run() {
System.out.println("Repainter run");
System.out.println(GameController.getInstance().getGameState().isActive());
while (GameController.getInstance().getGameState().isActive()) {
System.out.println("inside while");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
updateGUI();
}
}
}
// Second Approach
private class RepainterThread implements Runnable {
public RepainterThread() {
System.out.println("RepainThreadCOntructor");
}
private void updateGUI(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println("repaint");
getGamePanel().requestFocus();
getGamePanel().repaint();
}
});
}
@Override
public void run() {
System.out.println("Repainter run");
System.out.println(GameController.getInstance().getGameState().isActive());
while (GameController.getInstance().getGameState().isActive()) {
System.out.println("inside while");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
updateGUI();
}
}
}
Frame should no longer freeze
please help
Upvotes: 1
Views: 83
Reputation: 82889
This is kind of a wild guess, but since according to your description the program works correctly until you pause and unpause it, the problem likely lies with the startThreadAgain
method:
public void startThreadAgain() {
this.run();
}
Your code does not show how you call this method, but in that method you just call this.run()
, i.e. you call the run
method as a regular, blocking method, while probably still in the UI thread. Instead, you should call start()
to start a proper new thread executing the run
method.
public void startThreadAgain() {
super.start(); // not this start, otherwise it resets the ball's location
}
Upvotes: 1