Search code examples
javaclasstimergame-physicscollision

Collision Game Errors and Timers


In my game I have two problems. First I am getting some errors that I have no idea how to resolve. Secondly my goal for this project is to add a ball every 30 seconds the player survives. However I have tried several methods in doing so (timers and for loops). However these methods have resulted in graphics not appearing but the rest of the functions working (an invisible ball). If anyone could help me fix these issues it would be much appreciated.

import java.awt.*;
import java.lang.*;
import java.awt.event.KeyEvent;
import java.util.Formatter;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Polygon;
import java.awt.geom.Area;
public class  Man  implements KeyListener {

private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;
private float ballSpeedX3 = 7;
private float ballSpeedY3 = 7;
private double ball3Radius = 20;
private double ball3X = 320 ;
private double ball3Y = 120 ;
private float ballSpeedX4 = -10;
private float ballSpeedY4 = 10;
private double ball4Radius = 15;
private double ball4X = 600 ;
private double ball4Y = 300 ;
private float ballSpeedX = 0;
private float ballSpeedY = 0;
private double ballRadius = 20;
private double ballX = 120;
private double ballY = 140;
private float ballSpeed1X = 10;
private float ballSpeed1Y = -10;
private double ballRadius1 = 20;
private double ball1X = 320;
private double ball1Y = 340;
private float ballSpeed2X = -3;
private float ballSpeed2Y = -3;
private double ballRadius2 = 50;
private double ball2X = 50;
private double ball2Y = 400;

private static final int UPDATE_RATE = 30;

public Man() {
    this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
    Thread gameThread = new Thread() {
        public void run() {
while(true){             

              if ( Math.sqrt(    (Math.pow((ballX- ball1X), 2))    +    Math.pow((ballY-ball1Y), 2)) <= (ballRadius1 + ballRadius)) {
    System.exit(0);}
              if ( Math.sqrt(    (Math.pow((ball4X- ballX), 2))    +    Math.pow((ball4Y-ballY), 2)) <= (ball4Radius + ballRadius)) {
                    System.exit(0);}
              if ( Math.sqrt(    (Math.pow((ball2X- ballX), 2))    +    Math.pow((ball2Y-ballY), 2)) <= (ballRadius2 + ballRadius)) {
                System.exit(0);}        

                  ball4X += ballSpeedX4;
                  ball4Y += ballSpeedY4;
                  if (ball4X - ball4Radius < 0) {
                      ballSpeedX4 = -ballSpeedX4;
                      ball4X = ball4Radius;
                  } else if (ball4X + ball4Radius > BOX_WIDTH) {
                      ballSpeedX4 = -ballSpeedX4;
                      ball4X = BOX_WIDTH - ball4Radius;
                  }
                  if (ball4Y - ball4Radius < 0) {
                      ballSpeedY4 = -ballSpeedY4;
                      ball4Y = ball4Radius;
                  } else if (ball4Y + ball4Radius > BOX_HEIGHT) {
                      ballSpeedY4 = -ballSpeedY4;
                      ball4Y = BOX_HEIGHT - ball4Radius;
                  }

              if ( Math.sqrt(    (Math.pow((ball3X- ballX), 2))    +           Math.pow((ball3Y-ballY), 2)) <= (ball3Radius + ballRadius)) {
                System.exit(0);}


                ball3X += ballSpeedX3;
                ball3Y += ballSpeedY3;
                if (ball3X - ball3Radius < 0) {
                    ballSpeedX3 = -ballSpeedX3;
                    ball3X = ball3Radius;
                } else if (ball3X + ball3Radius > BOX_WIDTH) {
                    ballSpeedX3 = -ballSpeedX3;
                    ball3X = BOX_WIDTH - ball3Radius;
                }
                if (ball3Y - ball3Radius < 0) {
                    ballSpeedY3 = -ballSpeedY3;
                    ball3Y = ball3Radius;
                } else if (ball3Y + ball3Radius > BOX_HEIGHT) {
                    ballSpeedY3 = -ballSpeedY3;
                    ball3Y = BOX_HEIGHT - ball3Radius;
                }

                ballX += ballSpeedX;

                ballY += ballSpeedY;


                if (ballX - ballRadius < 0) {

                    ballX = ballRadius;
                } else if (ballX + ballRadius > BOX_WIDTH) {

                    ballX = BOX_WIDTH - ballRadius;
                }

                if (ballY - ballRadius < 0) {

                    ballY = ballRadius;
                } else if (ballY + ballRadius > BOX_HEIGHT) {

                    ballY = BOX_HEIGHT - ballRadius;
                }

                ball1X += ballSpeed1X;
                ball1Y += ballSpeed1Y;
                if (ball1X - ballRadius1 < 0) {
                    ballSpeed1X = -ballSpeed1X;
                    ball1X = ballRadius1;
                } else if (ball1X + ballRadius1 > BOX_WIDTH) {
                    ballSpeed1X = -ballSpeed1X;
                    ball1X = BOX_WIDTH - ballRadius1;
                }

                if (ball1Y - ballRadius1 < 0) {
                    ballSpeed1Y = -ballSpeed1Y;
                    ball1Y = ballRadius1;
                } else if (ball1Y + ballRadius1 > BOX_HEIGHT) {
                    ballSpeed1Y = -ballSpeed1Y;
                    ball1Y = BOX_HEIGHT - ballRadius1;
                }
                ball2X += ballSpeed2X;
                ball2Y += ballSpeed2Y;
                if (ball2X - ballRadius2 < 0) {
                    ballSpeed2X = -ballSpeed2X;
                    ball2X = ballRadius2;
                } else if (ball2X + ballRadius2 > BOX_WIDTH) {
                    ballSpeed2X = -ballSpeed2X;
                    ball2X = BOX_WIDTH - ballRadius2;
                }

                if (ball2Y - ballRadius2 < 0) {
                    ballSpeed2Y = -ballSpeed2Y;
                    ball2Y = ballRadius2;
                } else if (ball2Y + ballRadius2 > BOX_HEIGHT) {
                    ballSpeed2Y = -ballSpeed2Y;
                    ball2Y = BOX_HEIGHT - ballRadius2;
                }

                repaint();
                try {
                    Thread.sleep(1000 / UPDATE_RATE);

                } catch (InterruptedException ex) { }
            }
        }  
    };
    gameThread.start();

}
@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);
    g.setColor(Color.BLUE);
    g.fillOval((int) (ballX - ballRadius), (int) (ballY - ballRadius),
               (int)(2 * ballRadius), (int)(2 * ballRadius));
    g.setColor(Color.RED);
    g.fillOval((int) (ball1X - ballRadius1), (int) (ball1Y - ballRadius1),
               (int)(2 * ballRadius1), (int)(2 * ballRadius1));    
    g.setColor(Color.PINK);
    g.fillOval((int) (ball2X - ballRadius2), (int) (ball2Y - ballRadius2),
               (int)(2 * ballRadius2), (int)(2 * ballRadius2));   
           g.setColor(Color.GREEN);
    g.fillOval((int) (ball3X - ball3Radius), (int) (ball3Y - ball3Radius),
                           (int)(2 * ball3Radius), (int)(2 * ball3Radius));
    g.setColor(Color.YELLOW);
    g.fillOval((int) (ball4X - ball4Radius), (int) (ball4Y - ball4Radius),
                           (int)(2 * ball4Radius), (int)(2 * ball4Radius));


}

public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
        ballSpeedX = 5;
    }
    else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
        ballSpeedX = -5;
    }
    else if (e.getKeyCode() == KeyEvent.VK_UP ) {
        ballSpeedY = -5;
    }
    else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
        ballSpeedY = 5;
    }
}

public void keyReleased(KeyEvent e) {
     if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
         ballSpeedX = 0;
     }
     else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
         ballSpeedX = 0;
     }
     else if (e.getKeyCode() == KeyEvent.VK_UP ) {
         ballSpeedY = 0;
     }
     else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
         ballSpeedY = 0;

     }  
}
public void keyTyped(KeyEvent e) { }

public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame("Collision");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            Man man = new Man();
            frame.setContentPane(man);
            frame.pack();
            frame.addKeyListener(man);
            frame.setVisible(true);
        }
    });
}
}

Solution

  • I reworked your code and created the following GUI.

    Collision

    The red ball hit the pink player, which ended the animation.

    All of your code was in one large class. It was too difficult for me to understand what was going on, so I broke your code up into 7 classes. That way, each class could do one thing and do it well. Don't be afraid to use classes and methods to simplify your code and make it easier to find problems.

    Here are the changes I made.

    1. I created a Player class to define the player.

    2. I created a Ball class to hold the values of a Ball; the X and Y position, the color, the radius, and the X and Y speed of the ball.

    3. I created a GameModel class to hold an instance of Player and a List of Ball instances. Whenever you're creating a game, you should use the model / view / controller pattern. This pattern allows you to separate your code and focus on one part of the code at a time.

    4. I renamed your Main class to CollisionGame. The only code left in the CollisionGame class is the code to create the game model, create the JFrame and drawing panel, and start the animation.

    5. I created a DrawingPanel from a JPanel. You should always draw on a JPanel. You should never draw on a JFrame.

    6. I put the KeyListener in it's own class. I added the KeyListener to the JPanel. I made sure that the JPanel would have focus.

    7. I put the animation in its own Animation class.

    Here's the code. I put all the classes in one file so it would be easier for me to copy and paste. These classes should be put in separate files.

    package com.ggl.testing;
    
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class CollisionGame {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new CollisionGame();
                }
            });
        }
    
        private static final int BOX_WIDTH = 640;
        private static final int BOX_HEIGHT = 480;
    
        public CollisionGame() {
            GameModel gameModel = new GameModel();
    
            JFrame frame = new JFrame("Collision");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            DrawingPanel drawingPanel = new DrawingPanel(gameModel, BOX_WIDTH,
                    BOX_HEIGHT);
            frame.add(drawingPanel);
            frame.pack();
            frame.setVisible(true);
    
            Animation animation = new Animation(drawingPanel, gameModel, BOX_WIDTH,
                    BOX_HEIGHT);
            new Thread(animation).start();
        }
    
        public class DrawingPanel extends JPanel {
            private static final long serialVersionUID = -8219208002512324440L;
    
            private int width;
            private int height;
    
            private GameModel gameModel;
    
            public DrawingPanel(GameModel gameModel, int width, int height) {
                this.gameModel = gameModel;
                this.width = width;
                this.height = height;
    
                this.setFocusable(true);
                this.requestFocusInWindow();
                this.addKeyListener(new GameKeyListener(gameModel.getPlayer()));
                this.setPreferredSize(new Dimension(width, height));
            }
    
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.BLACK);
                g.fillRect(0, 0, width, height);
    
                Player player = gameModel.getPlayer();
                g.setColor(player.getColor());
                double playerRadius = player.getRadius();
                double playerDiameter = playerRadius + playerRadius;
                g.fillOval((int) (player.getPositionX() - playerRadius),
                        (int) (player.getPositionY() - playerRadius),
                        (int) (playerDiameter), (int) (playerDiameter));
    
                for (Ball ball : gameModel.getBalls()) {
                    g.setColor(ball.getColor());
                    double ballRadius = ball.getRadius();
                    double ballDiameter = ballRadius + ballRadius;
                    g.fillOval((int) (ball.getPositionX() - ballRadius),
                            (int) (ball.getPositionY() - ballRadius),
                            (int) (ballDiameter), (int) (ballDiameter));
                }
            }
        }
    
        public class Animation implements Runnable {
            private static final long UPDATE_RATE = 30;
    
            private boolean running;
    
            private double width;
            private double height;
    
            private DrawingPanel drawingPanel;
    
            private GameModel gameModel;
    
            public Animation(DrawingPanel drawingPanel, GameModel gameModel,
                    double width, double height) {
                this.drawingPanel = drawingPanel;
                this.gameModel = gameModel;
                this.width = width;
                this.height = height;
                this.running = true;
            }
    
            @Override
            public void run() {
                sleep(1000L);
                long ballTime = System.currentTimeMillis();
                long nextBallTime = 30000L;
                gameModel.addBall();
    
                while (running) {
                    long elapsedTime = System.currentTimeMillis() - ballTime;
                    if (elapsedTime >= nextBallTime) {
                        gameModel.addBall();
                        ballTime += nextBallTime;
                    }
    
                    movePlayer(gameModel.getPlayer());
                    for (Ball ball : gameModel.getBalls()) {
                        moveBall(ball);
                    }
    
                    repaint();
    
                    if (isPlayerHit()) {
                        running = false;
                    } else {
                        sleep(1000L / UPDATE_RATE);
                    }
                }
            }
    
            private void movePlayer(Player player) {
                player.setPositionX(player.getPositionX() + player.getSpeedX());
                player.setPositionY(player.getPositionY() + player.getSpeedY());
    
                double radius = player.getRadius();
                if (player.getPositionX() - radius < 0) {
                    player.setSpeedX(-player.getSpeedX());
                    player.setPositionX(radius);
                } else if (player.getPositionX() + radius > width) {
                    player.setSpeedX(-player.getSpeedX());
                    player.setPositionX(width - radius);
                }
    
                if (player.getPositionY() - radius < 0) {
                    player.setSpeedY(-player.getSpeedY());
                    player.setPositionY(radius);
                } else if (player.getPositionY() + radius > height) {
                    player.setSpeedY(-player.getSpeedY());
                    player.setPositionY(height - radius);
                }
            }
    
            private void moveBall(Ball ball) {
                ball.setPositionX(ball.getPositionX() + ball.getSpeedX());
                ball.setPositionY(ball.getPositionY() + ball.getSpeedY());
    
                double radius = ball.getRadius();
                if (ball.getPositionX() - radius < 0) {
                    ball.setSpeedX(-ball.getSpeedX());
                    ball.setPositionX(radius);
                } else if (ball.getPositionX() + radius > width) {
                    ball.setSpeedX(-ball.getSpeedX());
                    ball.setPositionX(width - radius);
                }
    
                if (ball.getPositionY() - radius < 0) {
                    ball.setSpeedY(-ball.getSpeedY());
                    ball.setPositionY(radius);
                } else if (ball.getPositionY() + radius > height) {
                    ball.setSpeedY(-ball.getSpeedY());
                    ball.setPositionY(height - radius);
                }
            }
    
            private boolean isPlayerHit() {
                Player player = gameModel.getPlayer();
                for (Ball ball : gameModel.getBalls()) {
                    double radiusSquared = Math.pow(
                            ball.getRadius() + player.getRadius(), 2D);
                    double distanceSquared = Math.pow(
                            (ball.getPositionX() - player.getPositionX()), 2D)
                            + Math.pow(ball.getPositionY() - player.getPositionY(),
                                    2D);
                    if (distanceSquared <= radiusSquared) {
                        return true;
                    }
                }
    
                return false;
            }
    
            private void repaint() {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        drawingPanel.repaint();
                    }
                });
            }
    
            private void sleep(long sleepTime) {
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
    
                }
            }
        }
    
        public class GameKeyListener implements KeyListener {
            private float playerSpeedX;
            private float playerSpeedY;
    
            private Player player;
    
            public GameKeyListener(Player player) {
                this.player = player;
            }
    
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                    playerSpeedX = 5;
                } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    playerSpeedX = -5;
                } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                    playerSpeedY = -5;
                } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                    playerSpeedY = 5;
                }
    
                updatePlayer();
            }
    
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                    playerSpeedX = 0;
                } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    playerSpeedX = 0;
                } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                    playerSpeedY = 0;
                } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                    playerSpeedY = 0;
                }
    
                updatePlayer();
            }
    
            @Override
            public void keyTyped(KeyEvent e) {
            }
    
            private void updatePlayer() {
                player.setSpeedX(playerSpeedX);
                player.setSpeedY(playerSpeedY);
            }
    
        }
    
        public class GameModel {
            private List<Ball> balls;
            private List<Ball> newBalls;
    
            private Player player;
    
            public GameModel() {
                this.balls = new ArrayList<>();
                this.newBalls = createBalls();
                this.player = new Player(Color.PINK, 120, 140, 20, 0, 0);
            }
    
            private List<Ball> createBalls() {
                List<Ball> balls = new ArrayList<>();
                balls.add(new Ball(Color.BLUE, 320, 120, 20, 7, 7));
                balls.add(new Ball(Color.RED, 600, 300, 15, -10, 10));
                balls.add(new Ball(Color.GREEN, 320, 340, 20, 10, -10));
                balls.add(new Ball(Color.YELLOW, 50, 400, 50, -3, -3));
    
                return balls;
            }
    
            public void addBall() {
                if (!newBalls.isEmpty()) {
                    balls.add(newBalls.get(0));
                    newBalls.remove(0);
                }
            }
    
            public List<Ball> getBalls() {
                return balls;
            }
    
            public Player getPlayer() {
                return player;
            }
    
        }
    
        public class Player {
            private float speedX;
            private float speedY;
            private double radius;
            private double positionX;
            private double positionY;
            private Color color;
    
            public Player(Color color, double positionX, double positionY,
                    double radius, float speedX, float speedY) {
                this.color = color;
                this.positionX = positionX;
                this.positionY = positionY;
                this.radius = radius;
                this.speedX = speedX;
                this.speedY = speedY;
            }
    
            public float getSpeedX() {
                return speedX;
            }
    
            public void setSpeedX(float speedX) {
                this.speedX = speedX;
            }
    
            public float getSpeedY() {
                return speedY;
            }
    
            public void setSpeedY(float speedY) {
                this.speedY = speedY;
            }
    
            public double getRadius() {
                return radius;
            }
    
            public double getPositionX() {
                return positionX;
            }
    
            public void setPositionX(double positionX) {
                this.positionX = positionX;
            }
    
            public double getPositionY() {
                return positionY;
            }
    
            public void setPositionY(double positionY) {
                this.positionY = positionY;
            }
    
            public Color getColor() {
                return color;
            }
        }
    
        public class Ball {
            private float speedX;
            private float speedY;
            private double radius;
            private double positionX;
            private double positionY;
            private Color color;
    
            public Ball(Color color, double positionX, double positionY,
                    double radius, float speedX, float speedY) {
                this.color = color;
                this.positionX = positionX;
                this.positionY = positionY;
                this.radius = radius;
                this.speedX = speedX;
                this.speedY = speedY;
            }
    
            public float getSpeedX() {
                return speedX;
            }
    
            public void setSpeedX(float speedX) {
                this.speedX = speedX;
            }
    
            public float getSpeedY() {
                return speedY;
            }
    
            public void setSpeedY(float speedY) {
                this.speedY = speedY;
            }
    
            public double getRadius() {
                return radius;
            }
    
            public double getPositionX() {
                return positionX;
            }
    
            public void setPositionX(double positionX) {
                this.positionX = positionX;
            }
    
            public double getPositionY() {
                return positionY;
            }
    
            public void setPositionY(double positionY) {
                this.positionY = positionY;
            }
    
            public Color getColor() {
                return color;
            }
    
        }
    }