6
\$\begingroup\$

This is my first application in Java, it imitates the world-known Ping Pong Game. I have a lot of questions in my mind...

I read that the class Timer is not recommended with multiple timers so I use ScheduledThreadPoolExecutor which probably does the same? Is there something better than that?

The collision detection in the Ball class includes a lot of else if statements but I don't have any idea how to improve that...

KeyInput - there was a problem with multiple using keys so I uses a idea from this website, simply "try" to adopt to my code, it works but is it OK?

RandomGenerator class contains several switch-statement, how to make this cleaner? Is there any more sophisticated way than switch?

Every opinion is really appreciated. In case someone wants to play the game I can send .jar file :)

GameFrame class

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;

public class GameFrame extends JFrame
{
    public static  int WIDTH_GAME_FRAME = 800;
    public static  int HEIGHT_GAME_FRAME = 700;
    GamePanel gamePanel;

    public GameFrame()
    {
       this.setTitle("Game");
       this.setLayout(new BorderLayout());
       this.setSize(WIDTH_GAME_FRAME, HEIGHT_GAME_FRAME);
       this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       this.setLocationRelativeTo(null);
       gamePanel = new GamePanel();

       this.add(gamePanel);
       this.setResizable(false);
       this.setVisible(true);

    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run()
            {
                GameFrame ex = new GameFrame();
            }
        });
    }}

GamePanel class

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class GamePanel extends JPanel  
{

    public static enum PaddleDirection {LEFT, RIGHT};
    public static enum State {MENU, GAME};
    public static enum Winner {FIRSTPLAYER, SECONDPLAYER};
    public Paddle firstPaddle, secondPaddle;
    public Ball firstBall, secondBall;
    public static State stateOfGame = State.MENU;
    private final Menu menu;
    private final KeyInput keyInput;
    private String winnerInfo, firstPlayerName, secondPlayerName;
    private final RandomGenerator randomGenerator;
    private final Obstacle obstacle;
    private BufferedImage backgroundImage;

    public GamePanel()
    {

      try 
       {                  
        backgroundImage = ImageIO.read(getClass().getResource
                                             ("/images/bitmap.png"));       
       }         
        catch (IOException e) 
        {
           System.exit(0);
        }

     menu = new Menu();
     firstPaddle = new Paddle(300, 600);
     secondPaddle = new Paddle(300, 42);
     firstBall = new Ball(this, firstPaddle, secondPaddle, true);
     secondBall = new Ball(this, firstPaddle, secondPaddle, false);
     obstacle = new Obstacle(150, 345 , firstBall);
     this.addMouseListener(new MouseInput(this));
     randomGenerator = new RandomGenerator(firstBall, firstPaddle, secondPaddle);
     keyInput = new KeyInput
             (this, firstPaddle, secondPaddle, firstBall, secondBall, obstacle);
     ScheduledThreadPoolExecutor executor, keyExecutor;
     executor = new ScheduledThreadPoolExecutor(10);
     keyExecutor = new ScheduledThreadPoolExecutor(10);
     executor.scheduleAtFixedRate
       (randomGenerator, 0L, 3L, TimeUnit.SECONDS);
     keyExecutor.scheduleAtFixedRate
       (keyInput, 0L, 13L, TimeUnit.MILLISECONDS);
     this.setBackground(Color.LIGHT_GRAY);
     setFocusable(true);
    }

    @Override
    protected void paintComponent(Graphics g) 
    {
       super.paintComponent(g);
       g.drawImage(backgroundImage, 0, 0, null);

       if (stateOfGame == State.GAME)
        {
           firstPaddle.paint(g);
           secondPaddle.paint(g);

           if (randomGenerator.freeSlot)
                 randomGenerator.paint(g);

           if (!RandomGenerator.invisibleBallActive)
                  firstBall.paint(g);

           if (RandomGenerator.secondBallActive)
                 secondBall.paint(g);

           if (RandomGenerator.obstacleActive)
                 obstacle.paint(g);          
        }

       if(stateOfGame == State.MENU)
       {
           menu.paint(g);
           keyInput.resetKeyInput();
       }
    }

    public void endOfGame(GamePanel.Winner win)
    {
        if (Winner.FIRSTPLAYER == win)
        {
            winnerInfo = "" + firstPlayerName + " wins";
            JOptionPane.showMessageDialog(this, winnerInfo,
                    "End of game", JOptionPane.INFORMATION_MESSAGE);
        }

        else if (Winner.SECONDPLAYER == win)
        {
            winnerInfo = "" + secondPlayerName + " wins";
            JOptionPane.showMessageDialog(this, winnerInfo,
                    "End of game", JOptionPane.INFORMATION_MESSAGE);
        }

        resetSettings();  
        GamePanel.stateOfGame = GamePanel.State.MENU;
    }

    public void setName(String firstPlayerName, String secondPlayerName)
    {
        this.firstPlayerName = firstPlayerName;
        this.secondPlayerName = secondPlayerName;
    }

    public void resetSettings()
    {
            firstBall.resetBallPosition();
            secondBall.resetBallPosition();
            firstPaddle.resetSlowPaddle();
            secondPaddle.resetSlowPaddle();
            firstPaddle.resetPaddlePosition();
            secondPaddle.resetPaddlePosition();

            if (RandomGenerator.speedBallActive)
                firstBall.resetBallSpeed();

            RandomGenerator.secondBallActive = false;
            RandomGenerator.slowPaddleActive = false;
            RandomGenerator.obstacleActive = false;
            RandomGenerator.speedBallActive = false;
            RandomGenerator.invisibleBallActive = false;
            randomGenerator.freeSlot = true;
            obstacle.resetObstaclePosition();
    }
}   

Paddle class

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Paddle
{
    public int widthPaddle;
    public static final int HEIGHT_PADDLE = 18; 
    private static  int PADDLE_MOVE = 5;
    private static final int ARC_PADDLE_WIDTH = 12;
    private static final int ARC_PADDLE_HEIGHT = 12;
    private final int START_X_PADDLE_POSITION;
    public int xPaddlePosition;
    public int yPaddlePosition;
    public int yDownPaddle;
    public int xPaddleEnd;
    private BufferedImage paddleImage;


    public Paddle(int xPaddlePosition, int yPaddlePosition)
    {
        this.widthPaddle = 120;
        this.xPaddlePosition = xPaddlePosition;
        this.yPaddlePosition = yPaddlePosition;
        START_X_PADDLE_POSITION = xPaddlePosition;
        yDownPaddle = yPaddlePosition + HEIGHT_PADDLE;
        xPaddleEnd = xPaddlePosition + widthPaddle;    

        try 
       {                  
        paddleImage = ImageIO.read(getClass().getResource
                                             ("/images/yellow.png"));       
       }         
        catch (IOException e) 
        {
           System.exit(0);
        }
    }


    public void move(GamePanel.PaddleDirection dir)
    {
        if (GamePanel.PaddleDirection.LEFT == dir)
        {
            if (xPaddlePosition >= 6)
                xPaddlePosition -= PADDLE_MOVE;
        }

        else
        {
            if (xPaddlePosition + widthPaddle <= 792)
                xPaddlePosition += PADDLE_MOVE;
        }

            xPaddleEnd = xPaddlePosition + widthPaddle;  
    }

    public void resetPaddlePosition()
    {
        xPaddlePosition = START_X_PADDLE_POSITION;
    }

    public void slowPaddle()
    {
        PADDLE_MOVE = 2;
    }

    public void resetSlowPaddle()
    {
        PADDLE_MOVE = 6;
    }


    public void paint(Graphics g) 
    {       
        g.drawImage(paddleImage,xPaddlePosition, yPaddlePosition, null);
    }
}

Ball class

    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import javax.imageio.ImageIO;

    public class Ball
    {

        public int xBallPosition =  (int) (Math.random() * 200 + 33) * 3;
        public int yBallPosition =  (int) (Math.random() * 33 + 100) * 3;
        private int xBallDirection = -3;
        private int yBallDirection = -3;
        private static final int DIAMETER = 15;
        private final GamePanel gPanel;
        private final Paddle firstPaddle, secondPaddle;
        public static boolean firstBallImage ,firstBounce = false;
        private BufferedImage ball;

        public int xCenterBall = xBallPosition + DIAMETER/2;
        public int yCenterBall = yBallPosition + DIAMETER/2;
        public int yDownBall = yBallPosition + DIAMETER;



        public Ball(GamePanel gPanel, Paddle firstPaddle, Paddle secondPaddle, boolean firstBallImage) 
        {
            Ball.firstBallImage = firstBallImage; 
            this.gPanel = gPanel;
            this.firstPaddle = firstPaddle;
            this.secondPaddle = secondPaddle;

            try 
           {          
               if (firstBallImage)
                ball  = ImageIO.read(getClass().getResource
                                                      ("/images/football18.png"));
               else
                ball  = ImageIO.read(getClass().getResource
                                                      ("/images/basketball18.png"));       
           }
            catch (IOException e) 
            {
               System.exit(0);
            }  
        }

        public void move()
        {

            if ((xBallPosition == 0 || xBallPosition == 783 || 
                    xBallPosition + xBallDirection < 0 || 
                    xBallPosition + xBallDirection > 783) &&
                    (yBallPosition < 700 && yBallPosition > 0))
            {
                xBallDirection = -xBallDirection;
            }

            xBallPosition += xBallDirection;
            yBallPosition += yBallDirection;


        }

       public void checkBounce(Paddle fPaddle, Paddle sPaddle, GamePanel g, Obstacle ob)
        {

            yDownBall = yBallPosition + DIAMETER;
            xCenterBall = xBallPosition + DIAMETER/2;
            yCenterBall = yBallPosition + DIAMETER/2;

            if (yDownBall  == fPaddle.yPaddlePosition && 
                 xCenterBall >= fPaddle.xPaddlePosition && 
                 xCenterBall <= fPaddle.xPaddleEnd)
            {
                yBallDirection = -yBallDirection;
                firstBounce = true;
            }

            else if (yDownBall + yBallDirection/2 == fPaddle.yPaddlePosition  &&
                    xCenterBall >= fPaddle.xPaddlePosition + xBallDirection/2 &&
                    xCenterBall <= fPaddle.xPaddleEnd + xBallDirection/2)
            {
                yBallDirection = -yBallDirection;
                firstBounce = true;
            }

            else if (yBallPosition == sPaddle.yDownPaddle && 
                    xCenterBall >= sPaddle.xPaddlePosition &&
                    xCenterBall <= sPaddle.xPaddleEnd)
            {
                yBallDirection = -yBallDirection;
                firstBounce = false;
            }

              else if (yBallPosition + yBallDirection/2 == sPaddle.yDownPaddle && 
                    xCenterBall >= sPaddle.xPaddlePosition + xBallDirection/2 &&
                    xCenterBall <= sPaddle.xPaddleEnd + xBallDirection/2)
            {
                yBallDirection = -yBallDirection;  
                firstBounce = false;
            }

            else if (RandomGenerator.obstacleActive && 
                    yBallPosition == ob.yDownObstacle && 
                    xCenterBall <= ob.xObstacleEnd && 
                    xCenterBall >= ob.xObstaclePosition &&
                    yBallDirection < 0)
            {
                yBallDirection = -yBallDirection;
                firstBounce = true;
            }

            else if (RandomGenerator.obstacleActive &&
                    yDownBall == ob.yObstaclePosition &&
                    xCenterBall <= ob.xObstacleEnd && 
                    xCenterBall >= ob.xObstaclePosition &&
                    yBallDirection > 0)
            {
                yBallDirection = -yBallDirection;
                firstBounce = true;
            }

            else if (yBallPosition < -20 || yBallPosition > 670)
            {
             if (yBallPosition < -20)
               {gPanel.endOfGame(GamePanel.Winner.FIRSTPLAYER);}
               else if (yBallPosition > 670)
               {gPanel.endOfGame(GamePanel.Winner.SECONDPLAYER);} 

            }
        }


        public void resetBallPosition()
        {
             xBallPosition =  (int) (Math.random() * 200 + 33) * 3;
             yBallPosition =  (int) (Math.random() * 33 + 100) * 3;    
        }

        public void changeBallSpeed()
        {
            xBallDirection = 2*xBallDirection;
            yBallDirection = 2*yBallDirection;
        }

        public void resetBallSpeed()
        {
            xBallDirection = xBallDirection/2;
            yBallDirection = yBallDirection/2;
        }


        public void paint(Graphics g) 
        {
             g.drawImage(ball, xBallPosition, yBallPosition, null);
        }
    } 

Menu class

    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import javax.imageio.ImageIO;


    public class Menu 
    {   
        private BufferedImage playImage, helpImage, exitImage, backgroundImage;
        private BufferedImage titleImage;
        public static final int X_IMAGE_POSITION = 251;

        public Menu()
        {
            try 
           {                
            playImage  = ImageIO.read(getClass().getResource
                                                       ("/images/play.png"));
            helpImage  = ImageIO.read(getClass().getResource
                                                       ("/images/help.png"));
            exitImage = ImageIO.read(getClass().getResource
                                                       ("/images/exit.png"));
            backgroundImage = ImageIO.read(getClass().getResource
                                                       ("/images/bitmap.png"));
            titleImage = ImageIO.read(getClass().getResource
                                                       ("/images/title220.png"));

           }         
            catch (IOException e) 
            {
               System.exit(0);
            }
        }

        public void paint(Graphics g)
        {   

            g.drawImage(backgroundImage, 0, 0, null);
            g.drawImage(titleImage, 280, 25, null);
            g.drawImage(playImage, X_IMAGE_POSITION, 280, null);
            g.drawImage(helpImage, X_IMAGE_POSITION, 400, null);
            g.drawImage(exitImage, X_IMAGE_POSITION, 520, null);
        }
    }

MouseInput class

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JOptionPane;
import javax.swing.JTextField;


public class MouseInput extends MouseAdapter
{
    JTextField firstPlayerName = new JTextField();
    JTextField secondPlayerName = new JTextField();
    Object[] message = {"First player : ", firstPlayerName,
                        "Second player : ", secondPlayerName};
    private final GamePanel gPanel;
    private final String helpInfo = "This is a very simple game which imitates"
            + " world-known game Ping Pong \n\n First player uses arrows to"
            + " move the paddle, second player uses keys A and D";

    public MouseInput(GamePanel gPanel)
    {
        this.gPanel = gPanel;
    }

    @Override
    public void mousePressed(MouseEvent e)
    {
      int xMousePosition = e.getX();
      int yMousePosition = e.getY();

      if (xMousePosition > Menu.X_IMAGE_POSITION && xMousePosition < 551)
      {
          if (yMousePosition > 280 && yMousePosition < 350)
          {
              int option = JOptionPane.showConfirmDialog(null, message,
                      "Name of players", JOptionPane.OK_CANCEL_OPTION);

              if (option == JOptionPane.OK_OPTION &&
                      !firstPlayerName.getText().isEmpty() &&
                      !secondPlayerName.getText().isEmpty())
              {
                 gPanel.setName 
                        (firstPlayerName.getText(), secondPlayerName.getText());

                 GamePanel.stateOfGame = GamePanel.State.GAME;
              }       
          }  


          else if (yMousePosition > 400 && yMousePosition < 470)
          {
            JOptionPane.showMessageDialog(gPanel, helpInfo,
                    "Help information", JOptionPane.INFORMATION_MESSAGE);
          }

          else if (yMousePosition > 520 && yMousePosition < 590)
          {
              System.exit(0);
          }
      }

    }
}

KeyInput class

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import java.util.EnumMap;

public final class KeyInput implements Runnable
{

    private static final String PRESSED = "pressed";    
    private static final String RELEASED = "released"; 
    private final EnumMap<Key, Boolean> keyMap; 
    private final GamePanel gPanel;
    private final Paddle firstPaddle, secondPaddle;
    private final Ball firstBall, secondBall;
    private final Obstacle obstacle;

    public KeyInput(GamePanel gPanel, Paddle firstPaddle, Paddle secondPaddle,
            Ball firstBall, Ball secondBall, Obstacle obstacle)
    {
      this.keyMap =  new EnumMap<>(Key.class);
      this.gPanel = gPanel;
      this.firstPaddle = firstPaddle;
      this.secondPaddle = secondPaddle;
      this.firstBall = firstBall;
      this.secondBall = secondBall;
      this.obstacle = obstacle;

      resetKeyInput();

      ActionMap actionMap = gPanel.getActionMap();
      int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = gPanel.getInputMap(condition);

      for (Key key : Key.values()) 
      {
         KeyStroke pressedKeyStroke = KeyStroke.getKeyStroke
                                     (key.getKeyCode(), 0, false);
         KeyStroke releasedKeyStroke = KeyStroke.getKeyStroke
                                     (key.getKeyCode(), 0, true);

         inputMap.put(pressedKeyStroke, key.getText() + PRESSED);
         inputMap.put(releasedKeyStroke, key.getText() + RELEASED);
         actionMap.put(key.getText() + PRESSED, new MyArrowBinding(key, false));
         actionMap.put(key.getText() + RELEASED, new MyArrowBinding(key, true));
      }
    }

    @Override
    public void run()
    {
        if (GamePanel.stateOfGame == GamePanel.State.GAME)
         {
        int order = 1;

          firstBall.checkBounce(firstPaddle, secondPaddle, gPanel, obstacle);
          firstBall.move();

          if (RandomGenerator.secondBallActive)
          {
          secondBall.checkBounce(firstPaddle, secondPaddle, gPanel, obstacle);
          secondBall.move();
          }
          if (RandomGenerator.obstacleActive)
              obstacle.followBall();

          gPanel.repaint();

          for (Key key : keyMap.keySet())
         {
            if (keyMap.get(key) && order == 1)
            {
                secondPaddle.move(GamePanel.PaddleDirection.LEFT);
                gPanel.repaint();
            }

            else if (keyMap.get(key) && order == 2)
            {
                secondPaddle.move(GamePanel.PaddleDirection.RIGHT);
                gPanel.repaint();
            }
            else if (keyMap.get(key) && order == 3)
            {
                firstPaddle.move(GamePanel.PaddleDirection.LEFT);
                gPanel.repaint();
            }
            else if (keyMap.get(key) && order == 4)
            {
                firstPaddle.move(GamePanel.PaddleDirection.RIGHT);
                gPanel.repaint();            
            }

            order++;
         }
      }
    }




    public void resetKeyInput()
    {
         keyMap.put(Key.A, false);
         keyMap.put(Key.D, false);
         keyMap.put(Key.LEFT, false);
         keyMap.put(Key.RIGHT, false);
    }



    private class MyArrowBinding extends AbstractAction 
    {
      private final Key key;
      private final boolean released;

      public MyArrowBinding(Key key, boolean released)
      {
         this.key = key;
         this.released = released;
      }

      @Override
      public void actionPerformed(ActionEvent aEvt)
      {
         keyMap.put(key, !released);
      }
   }

    enum Direction 
    {
      LEFT("Left"), RIGHT("Right"), NEUTRAL("Neutral");
      private final String text;

      private Direction(String text)
      {
         this.text = text;
      }

      public String getText()
      {
         return text;
      }
    }

    enum Key
    {
      A("A", Direction.LEFT, KeyEvent.VK_A),
      D("D", Direction.RIGHT, KeyEvent.VK_D), 
      LEFT("Left", Direction.LEFT, KeyEvent.VK_LEFT),
      RIGHT("Right", Direction.RIGHT, KeyEvent.VK_RIGHT);

      private final String text;
      private final Direction direction;
      private final int keyCode;

      private Key(String text, Direction direction, int keyCode) 
      {
         this.text = text;
         this.direction = direction;
         this.keyCode = keyCode;
      }

      public String getText()
      {
         return text;
      }

      public Direction getDirection()
      {
         return direction;
      }

      public int getKeyCode()
      {
         return keyCode;
      }
    }
}

RandomGenerator class

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;


public class RandomGenerator implements Runnable
{
    public static boolean secondBallActive = false;
    public static boolean obstacleActive = false;
    public static boolean speedBallActive = false;
    public static boolean slowPaddleActive = false;
    public static boolean invisibleBallActive = false;
    public boolean freeSlot = true;
    public Ball ball;
    private static final int IMAGE_WIDTH = 64;
    private int xImagePosition;
    private int yImagePosition;
    private BufferedImage secondBallImage, speedBallImage, slowPaddleImage;
    private BufferedImage invisibleBallImage, obstacleImage;
    private Integer numberFromGenerator;
    private Paddle firstPaddle, secondPaddle;
    private Ball secondBall;
    public RandomElement choice;
    byte  paintCounter = 0;
    byte randomEventCounter = 0;
    public enum RandomElement {SECOND_BALL, SPEED_BALL, SLOW_PADDLE, 
                              INVISIBLE_BALL, OBSTACLE, SMALL_PADDLE};


    public RandomGenerator(Ball ball, Paddle firstPaddle, Paddle secondPaddle) 
    {

       this.ball = ball;
       this.firstPaddle = firstPaddle;
       this.secondPaddle = secondPaddle;

       try 
       {                
        secondBallImage  = ImageIO.read(getClass().getResource
                                                   ("/images/two.png"));
        speedBallImage  = ImageIO.read(getClass().getResource
                                                   ("/images/speed.png"));
        slowPaddleImage = ImageIO.read(getClass().getResource
                                                   ("/images/slow.png"));
        invisibleBallImage = ImageIO.read(getClass().getResource
                                                   ("/images/invisible.png"));
        obstacleImage  = ImageIO.read(getClass().getResource
                                                   ("/images/stop.png"));
       } 

        catch (IOException e) 
        {
           System.exit(0);
        }
    }

    @Override
    public void run() 
    {

        if (secondBallActive || obstacleActive ||  speedBallActive || 
                slowPaddleActive || invisibleBallActive)
                    endRandomEvent();

                if(freeSlot && paintCounter++ == 2)
        {
            numberFromGenerator = (int) (Math.random() * 5 + 1);
            xImagePosition = (int) (Math.random() * 650 + 50);
            yImagePosition = (int) (Math.random() * 200 + 250);
            paintCounter = 0;

            switch(numberFromGenerator)
            {
                case 1:                  choice = RandomElement.SECOND_BALL;  
                                         break;

                case 2:                  choice = RandomElement.SPEED_BALL;  
                                         break;

                case 3:                  choice = RandomElement.SLOW_PADDLE;   
                                         break;

                case 4:                  choice = RandomElement.INVISIBLE_BALL;  
                                         break;

                case 5:                  choice = RandomElement.OBSTACLE;    
                                         break;                          
            }

        }
    }


     public void paint(Graphics g) 
    {


        if (choice != null && freeSlot)
        {
            checkBallPosition(); 

            switch(choice)
          {
           case SECOND_BALL:             g.drawImage(secondBallImage, 
                                         xImagePosition, yImagePosition, null);
                                         break;

           case SPEED_BALL:              g.drawImage(speedBallImage,
                                         xImagePosition, yImagePosition, null);
                                         break;

           case SLOW_PADDLE:             g.drawImage(slowPaddleImage,
                                         xImagePosition, yImagePosition, null);    
                                         break;

           case INVISIBLE_BALL:          g.drawImage(invisibleBallImage,
                                         xImagePosition, yImagePosition, null);                                      
                                         break;

           case OBSTACLE:                g.drawImage(obstacleImage,
                                         xImagePosition, yImagePosition, null);                                         
                                         break;
          }
       }
    }

    public void checkBallPosition()
    {

        if (ball.xCenterBall >=  xImagePosition && 
            ball.xCenterBall <= xImagePosition + IMAGE_WIDTH &&
            ball.yCenterBall >= yImagePosition &&
             ball.yCenterBall <= yImagePosition + IMAGE_WIDTH)
        {
            freeSlot = false;

            if (null != choice)
            switch (choice) {

                case SECOND_BALL:
                                         secondBallActive = true;
                                         break;

                case OBSTACLE:           obstacleActive = true;
                                         break;

                case SPEED_BALL:         speedBallActive = true;
                                         ball.changeBallSpeed();
                                         break;

                case SLOW_PADDLE:        slowPaddleActive = true;
                                         secondPaddle.slowPaddle();
                                         firstPaddle.slowPaddle();
                                         break;

                case INVISIBLE_BALL:     invisibleBallActive = true;
                                         break;                     
            }          
        }
    }

    public void endRandomEvent()
    {
           if (invisibleBallActive == true)
           {
               invisibleBallActive = false;
               freeSlot = true;
           }

           if (randomEventCounter++ == 5)
        {
            randomEventCounter = 0;

            switch(choice)
            {
               case SECOND_BALL:            secondBallActive = false;
                                            freeSlot = true;
                                            break;

               case SPEED_BALL:             speedBallActive = false;
                                            ball.resetBallSpeed();
                                            freeSlot = true;
                                            break;

               case SLOW_PADDLE:            slowPaddleActive = false;
                                            firstPaddle.resetSlowPaddle();
                                            secondPaddle.resetSlowPaddle();
                                            freeSlot = true;
                                            break;

               case OBSTACLE:               obstacleActive = false;
                                            freeSlot = true;
                                            break;
            }
        }
    }
}

Obstacle class

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Obstacle 
{
    public int WIDTH_OBSTACLE = 200;
    public int HEIGHT_OBSTACLE = 18;
    private final int OBSTACLE_MOVE = 3;
    private final Ball ball;
    public  int xObstaclePosition, yObstaclePosition; 
    private final int START_X_OBSTACLE_POSITION;
    public int yDownObstacle;
    public int xObstacleEnd = xObstaclePosition + WIDTH_OBSTACLE;
    private BufferedImage obstacleImage;

    public Obstacle(int xObstaclePosition, int yObstaclePosition, Ball ball)
  {
      this.xObstaclePosition = xObstaclePosition;
      this.yObstaclePosition = yObstaclePosition;
      this.ball = ball;
      START_X_OBSTACLE_POSITION = xObstaclePosition;
      yDownObstacle = yObstaclePosition + HEIGHT_OBSTACLE;

      try 
       {                  
        obstacleImage = ImageIO.read(getClass().getResource
                                             ("/images/obstacle.png"));       
       }         
        catch (IOException e) 
        {
           System.exit(0);
        }
  }

    public void followBall()
    {
        if (ball.xBallPosition > xObstaclePosition + WIDTH_OBSTACLE/2)
        {
            if (xObstaclePosition < GameFrame.WIDTH_GAME_FRAME - WIDTH_OBSTACLE)
            {
                xObstaclePosition += OBSTACLE_MOVE;
                xObstacleEnd = xObstaclePosition + WIDTH_OBSTACLE;
            }
        }

        else 
          {      
              if (xObstaclePosition > 2)
              {
               xObstaclePosition -= OBSTACLE_MOVE;
               xObstacleEnd = xObstaclePosition + WIDTH_OBSTACLE;
              }
          }
    }

    public void resetObstaclePosition()
    {
        xObstaclePosition = START_X_OBSTACLE_POSITION;
    }

    public void paint(Graphics g) 
    {
       g.drawImage(obstacleImage, xObstaclePosition, yObstaclePosition, null);
    } 
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Codereview! I applied proper inline code formatting to your question (+ very minor changes). use ` [BACKTICK] around your inline code so that it appears monospaced and looks like code to differentiate from text. I'm sure you'll enjoy your stay here :) \$\endgroup\$ – Caridorc Aug 27 '16 at 13:03
3
\$\begingroup\$

Do not catch an exception just to call System.exit(0)

I am looking at:

  try 
   {                  
    obstacleImage = ImageIO.read(getClass().getResource
                                         ("/images/obstacle.png"));       
   }         
    catch (IOException e) 
    {
       System.exit(0);
    }

You catch the exception and just exit the program without any error message if the file is not found. This is worse than not catching it, as a normal (non-catch) failure outputs a nice error message.

From StackOverflow:

If you let the exception propagate all the way up to the main() method, the program will end. There's no need to call System.exit, just allow the exception to bubble up the stack naturally (by adding throws IOException) to the necessary methods.

I would add that this destroys any info about the error and terminates the program of the caller.

The caller (The Main class) will never now what problem happened, it will just be terminated.

you may want to catch the IOException in your main method, and call System.exit there instead, supplying a human-readable error message

It should be the Main method to decide how the user should be notified of a failure, either by showing a raw stack-trace or a custom error message.

Avoid repetition

        switch(choice)
      {
       case SECOND_BALL:             g.drawImage(secondBallImage, 
                                     xImagePosition, yImagePosition, null);
                                     break;

       case SPEED_BALL:              g.drawImage(speedBallImage,
                                     xImagePosition, yImagePosition, null);
                                     break;

       case SLOW_PADDLE:             g.drawImage(slowPaddleImage,
                                     xImagePosition, yImagePosition, null);    
                                     break;

       case INVISIBLE_BALL:          g.drawImage(invisibleBallImage,
                                     xImagePosition, yImagePosition, null);                                      
                                     break;

       case OBSTACLE:                g.drawImage(obstacleImage,
                                     xImagePosition, yImagePosition, null);                                         
                                     break;
      }

In each switch case, the method g.drawImage(image, xImagePosition, yImagePosition, null); is called where only image varies, so:

        switch(choice)
      {
       case SECOND_BALL: Image image = secondBallImage; break; 

       case SPEED_BALL:  Image image = speedBallImage;  break;

       case SLOW_PADDLE: Image image = slowPaddleImage; break;

       ...
      }

   g.drawImage(image, xImagePosition, yImagePosition, null);

The reader will immediately understand that the switch only decides which image should be drawn and the code got shorter too.

Changes that benefit both conciseness and readability are best.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.