HIDE NAV

Pong 2020 - Pt.3

Hitbox based calculations are leveraged to detect when the ball touches the paddle. The left paddle now turns red when collision is detected.
The Pong Pt.3 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.scene.paint.Color;
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, -.5, 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();
                checkLeftPaddle();

                //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();
        }

        // Left and Right side reflections disabled
        /*
            if (ball.x >= (gameWidth - ball.size) || (ball.x < 0)) {
            ball.reflectX();
            }
         */
    }

    void checkLeftPaddle(){
        double ballLeft = ball.x;
        double ballRight = ball.x + ball.size;
        double ballTop = ball.y;
        double ballBottom = ball.y + ball.size;

        double padLeft = padL.x;
        double padRight = padL.x + padL.width;
        double padTop = padL.y;
        double padBottom = padL.y + padL.height;

        double xOverlap = Math.min(ballRight, padRight) - Math.max(ballLeft, padLeft);
        double yOverlap = Math.min(ballBottom, padBottom) - Math.max(ballTop, padTop);

        if (xOverlap > 0 && yOverlap > 0) {
            // Collision Detected!
            padL.rectangle.setFill(Color.RED);
        } else {
            padL.rectangle.setFill(Color.BLACK);
        }
    }

    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;
    }
}