Pong 2020 - Pt.2
New classes are added for the ball and paddle leveraging object oriented code structure more effectively. Keyboard input detection is added to allow the movement of the paddles. There is not yet any collision detection except for the ball bouncing on the boundaries of the window.
The Pong Pt.2 video lesson documents the writing of this code and explains its structure.
Pong.java
package ceccs;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Pong extends Application {
double gameHeight = 500;
double gameWidth = 1000;
double padOffset = 5;
Ball ball;
Paddle padL, padR;
boolean downPressedL, upPressedL, downPressedR, upPressedR;
@Override
public void start(Stage primaryStage) throws Exception {
ball = new Ball(490, 240, -1, 0);
padL = new Paddle(padOffset, gameHeight/2 - padL.height/2);
padR = new Paddle(gameWidth - padR.width - padOffset, gameHeight/2 - padL.height/2);
Pane pane = new Pane();
pane.getChildren().addAll(ball.rectangle, padL.rectangle, padR.rectangle);
Scene scene = new Scene(pane, gameWidth, gameHeight);
primaryStage.setScene(scene);
primaryStage.setTitle("PONG");
primaryStage.setResizable(false);
primaryStage.show();
ball.updateGraphics();
padL.updateGraphics();
padR.updateGraphics();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch(event.getCode()){
case W:
upPressedL = true;
break;
case S:
downPressedL = true;
break;
case DOWN:
downPressedR = true;
break;
case UP:
upPressedR = true;
break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch(event.getCode()){
case W:
upPressedL = false;
break;
case S:
downPressedL = false;
break;
case DOWN:
downPressedR = false;
break;
case UP:
upPressedR = false;
break;
}
}
});
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
//input updates
checkInput();
//physics updates
padL.updatePosition();
padR.updatePosition();
ball.updatePosition();
checkGameBounds();
//graphics updates
ball.updateGraphics();
padL.updateGraphics();
padR.updateGraphics();
}
};
timer.start();
}
public static void main(String[] args){
launch(args);
}
void checkGameBounds(){
if (ball.y >= (gameHeight - ball.size) || (ball.y < 0)){
ball.reflectY();
}
/*
if (ball.x >= (gameWidth - ball.size) || (ball.x < 0)) {
ball.reflectX();
}
*/
}
void checkInput(){
// left paddle
if(downPressedL && !upPressedL){
padL.vy = padL.speed;
}else if(upPressedL && !downPressedL){
padL.vy = -padL.speed;
} else {
padL.vy = 0;
}
// right paddle
if(downPressedR && !upPressedR){
padR.vy = padR.speed;
}else if(upPressedR && !downPressedR){
padR.vy = -padR.speed;
} else {
padR.vy = 0;
}
}
}
Ball.java
package ceccs;
import javafx.scene.shape.Rectangle;
public class Ball {
double x, y, vx, vy, size;
Rectangle rectangle;
Ball(double startX, double startY, double startVx, double startVy){
x = startX;
y = startY;
vx = startVx;
vy = startVy;
size = 20;
rectangle = new Rectangle(size, size);
}
void updateGraphics(){
rectangle.setX(x);
rectangle.setY(y);
}
void updatePosition(){
x = x + vx;
y = y + vy;
}
void reflectX(){
x = x - vx;
vx = -1 * vx;
}
void reflectY(){
y = y - vy;
vy = -1 * vy;
}
}
Paddle.java
package ceccs;
import javafx.scene.shape.Rectangle;
public class Paddle {
double x, y, vy;
Rectangle rectangle;
static double speed = 2;
static double width = 20;
static double height = 100;
Paddle(double startX, double startY){
x = startX;
y = startY;
rectangle = new Rectangle(startX, startX, width, height);
}
void updateGraphics(){
rectangle.setX(x);
rectangle.setY(y);
}
void updatePosition(){
y = y + vy;
}
}