I tried to make a Pong game in Java. It's my first game I have ever programmed, and I would be very pleased if you would take the time to advise me on what I could do better next time. Thank you so much :) .
Here is my code:
Start.java:
import java.awt.EventQueue;
public class Start {
public static void main(String[] args) {
Runnable runner = new Runnable() {
public void run() {
GameFrame gameFrame = new GameFrame();
}
};
EventQueue.invokeLater(runner);
}
}
GameFrame.java:
import javax.swing.JFrame;
public class GameFrame extends JFrame{
public GameFrame() {
initFrame();
}
private void initFrame() {
add(new GameBoard());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("PongGame");
setResizable(false);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
}
GameBoard.java:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class GameBoard extends JPanel implements Runnable{
public static final int WIDTH = 900 ;
public static final int HEIGHT = 2 * WIDTH / 3;
private final int DELAY = 10;
private int scoreL = 0;
private int scoreR = 0;
private boolean inGame = false;
private Paddle rightPaddle, leftPaddle;
private Ball ball;
private Thread game;
public GameBoard() {
initGameBoard();
}
private void initGameBoard() {
setBackground(Color.black);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
addKeyListener(new KAdapter());
ball = new Ball();
rightPaddle = new Paddle("right");
leftPaddle = new Paddle("left");
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(5.0f));
g2d.drawLine(WIDTH/2, 0, WIDTH/2, HEIGHT);
drawBall(g2d);
drawPaddle(g2d);
drawScore(g2d);
if(!inGame) {
drawPressSpace(g2d);
}
Toolkit.getDefaultToolkit().sync();
}
public void addNotify() {
super.addNotify();
game = new Thread(this);
game.start();
}
private void drawPaddle(Graphics2D g2d) {
g2d.drawImage(rightPaddle.getImage(), rightPaddle.getX(), rightPaddle.getY(), this);
g2d.drawImage(leftPaddle.getImage(), leftPaddle.getX(), leftPaddle.getY(), this);
}
private void drawPressSpace(Graphics2D g2d) {
String press = "Press space to begin";
Font font = new Font("Verdana", Font.BOLD , 20);
FontMetrics fm = getFontMetrics(font);
g2d.setFont(font);
g2d.setColor(Color.red);
g2d.drawString(press, (WIDTH - fm.stringWidth(press)) / 2, (HEIGHT - fm.getHeight()) / 2);
}
private void drawScore(Graphics2D g2d) {
Font font = new Font("Verdana", Font.PLAIN , 50);
FontMetrics fm = getFontMetrics(font);
g2d.setColor(Color.gray);
g2d.setFont(font);
g2d.drawString(""+scoreL, 50, fm.stringWidth(""+scoreL) + 40);
g2d.drawString(""+scoreR, WIDTH - fm.stringWidth(""+scoreR) - 50, fm.stringWidth(""+scoreR) + 40);
}
private void drawBall(Graphics2D g2d) {
g2d.drawImage(ball.getImage(), ball.getX(), ball.getY(), this);
}
public void run() {
long beforeT, timeDiff, sleep;
beforeT = System.currentTimeMillis();
while (true) {
updatePaddles();
if(inGame) {
updateBall();
} else {
rightPaddle.resetPos();
leftPaddle.resetPos();
}
repaint();
timeDiff = System.currentTimeMillis() - beforeT;
sleep = DELAY - timeDiff;
if (sleep < 2) {
sleep = 2;
}
try {
Thread.sleep(sleep);
}catch(Exception e) {
e.getStackTrace();
}
beforeT = System.currentTimeMillis();
}
}
private void updatePaddles() {
rightPaddle.move();
leftPaddle.move();
}
private void updateBall() {
boolean b = checkCollision();
int i = ball.move(b);
if(i != 0) {
switch(i) {
case 1: scoreR++; break;
case 2: scoreL++; break;
}
inGame = false;
}
}
private boolean checkCollision() {
Rectangle rb = ball.getBounds();
Rectangle rp = rightPaddle.getBounds();
if(rb.intersects(rp)) {
return true;
}
rp = leftPaddle.getBounds();
if(rb.intersects(rp)) {
return true;
}
return false;
}
private class KAdapter extends KeyAdapter{
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(!inGame && keyCode == KeyEvent.VK_SPACE) {
inGame = true;
ball.start();
return;
}
if(inGame) {
if(rightPaddle.isKey(keyCode)) {
rightPaddle.keyPressed(keyCode);
} else if(leftPaddle.isKey(keyCode)) {
leftPaddle.keyPressed(keyCode);
}
}
}
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(rightPaddle.isKey(keyCode)) {
rightPaddle.keyReleased(keyCode);
} else if(leftPaddle.isKey(keyCode)) {
leftPaddle.keyReleased(keyCode);
}
}
}
}
Sprite.java:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
public class Sprite {
protected int x;
protected int y;
private int width;
private int height;
protected BufferedImage image;
public Sprite(int width, int height) {
this.width = width;
this.height = height;
updateImage();
}
private void updateImage() {
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.white);
g2d.fillRect(0, 0, width, height);
}
public BufferedImage getImage() {
return this.image;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
}
Paddle.java:
import java.awt.event.KeyEvent;
public class Paddle extends Sprite{
public final static int WIDTH = 20;
public final static int HEIGHT = GameBoard.HEIGHT / 5;
private final int SPEED = 8;
private String side;
private int up;
private int down;
private int dy;
public Paddle(String side) {
super(WIDTH, HEIGHT);
this.side = side;
setSide();
resetPos();
}
private void setSide() {
if(side.equals("right")) {
up = KeyEvent.VK_UP;
down = KeyEvent.VK_DOWN;
x = GameBoard.WIDTH - WIDTH;
} else if(side.equals("left")) {
up = KeyEvent.VK_W;
down = KeyEvent.VK_S;
x = 0;
} else {
System.out.println("tato strana neexistuje!");
}
}
public boolean isKey(int keyCode) {
return up == keyCode || down == keyCode;
}
public void move() {
if(checkHeightCol()) {
dy = 0;
}
y+=dy;
}
private boolean checkHeightCol() {
return dy + y < 0 || dy + y > GameBoard.HEIGHT - HEIGHT;
}
public void resetPos() {
y = (GameBoard.HEIGHT - HEIGHT) / 2;
}
public void keyPressed(int keyCode) {
if(keyCode == up) {
dy = -SPEED;
}
if (keyCode == down) {
dy = SPEED;
}
}
public void keyReleased(int keyCode) {
if(keyCode == up) {
dy = 0;
}
if (keyCode == down) {
dy = 0;
}
}
}
Ball.java:
import java.util.Random;
public class Ball extends Sprite{
public static final int SIZE = 20;
private int xSpeed;
private int ySpeed;
private final int MIN_SPEED = 8;
private final int MAX_SPEED = 25;
public Ball() {
super(SIZE, SIZE);
restart();
}
public void start() {
generateRandomDirection();
}
private void generateRandomDirection() {
Random r = new Random();
double randomY = 0.1 + (0.8 - 0.1) * r.nextDouble();
ySpeed = (int) Math.round(randomY * MIN_SPEED);
double randomX = Math.sqrt(MIN_SPEED * MIN_SPEED - ySpeed * ySpeed);
xSpeed = (int) Math.round(randomX);
ySpeed *= (r.nextInt() % 2 == 0) ? 1 : -1;
xSpeed *= (r.nextInt() % 2 == 0) ? 1 : -1;
}
public void restart() {
xSpeed = 0;
ySpeed = 0;
x = (GameBoard.WIDTH - SIZE) / 2;
y = (GameBoard.HEIGHT - SIZE) / 2;
}
public int move(boolean paddleCollision) {
int state = 0;
if(x + xSpeed < 0) {
restart();
state = 1;
} else if(x + xSpeed > GameBoard.WIDTH - SIZE ) {
restart();
state = 2;
}else if(checkHeightCollision()) {
ySpeed *= -1;
} else if(paddleCollision) {
xSpeed *= -1;
}
x+=xSpeed;
y+=ySpeed;
return state;
}
private boolean checkHeightCollision() {
return y + ySpeed < 0 || y + ySpeed > GameBoard.HEIGHT - SIZE;
}
}