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);
}
}
1 Answer 1
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.
If you let the exception propagate all the way up to the
main()
method, the program will end. There's no need to callSystem.exit
, just allow the exception to bubble up the stack naturally (by addingthrows 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 callSystem.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.
`
[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\$