Search code examples
javamathpong

Pong Ball Leaving Padel


I am making Pong in Java right now using Eclipse. I am trying to get the balls to bounce off the padels proportionally to where they hit the padel. If they hit at the top or bottom, I would like them to bounce off at 75 degrees up at the top or 75 degrees down at the bottom. If they hit near the center, then I would like them to bounce off closer to horizontal.

I am calculating the angle in the ball class with this math:

 double speed = getSpeed() + ballIncrease;
 yPos = Math.abs(yPos);
 double angle = multiplier * yPos;
 double ratio = Math.tan(angle);
 xSpeed = ratio * (speed/(ratio + 1));
 ySpeed = Math.sqrt((speed * speed) - (xSpeed * xSpeed));

I think that it should be correct, but the balls don't behave like I expect them to. I was wondering if anyone can help me solve this problem.

package Pong;

/*Place cursor here to start
* 
*/

//Import Libraries
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

@SuppressWarnings("serial")
public class Pong extends JPanel implements KeyListener{

//Create random instances
Random r2 =new Random();

public final static int padelStart = 150;
public final static int padelSpace = 10;

final static int BOX_WIDTH = 1200;
public final static int BOX_HEIGHT = 800;

double ballX = BOX_WIDTH/2;
double ballY = BOX_HEIGHT/2;

public static Padel padel1 = new Padel(padelSpace,padelStart,true);
public static Padel padel2 = new Padel(BOX_WIDTH-padelSpace-padel1.getWidth(),padelStart,false);

Ball ball1 = new Ball(ballX,ballY);
Ball ball2 = new Ball(300,300);

public static int padel1y1;
public static int padel1y2;
public static int padel2y1;
public static int padel2y2;

//Constants
public final static int UPDATE_RATE = 200;

//Main game class
public Pong () {

    //Set window size
    setPreferredSize(new Dimension(BOX_WIDTH,BOX_HEIGHT));

    //Start game thread
    Thread gameThread = new Thread() {

        public void run(){

            while(true){

                //Draw objects

                padel1y1 = padel1.getY();
                padel1y2 = padel1.getY() + Padel.padelLength;
                padel2y1 = padel2.getY();
                padel2y2 = padel2.getY() + Padel.padelLength;

                padel1.update();
                padel2.update();

                ball1.update();
                ball2.update();
                repaint();

                //Wait
                try {Thread.sleep(1000 / UPDATE_RATE);} 
                catch (InterruptedException ex) {}

            }

        }

    };

gameThread.start();

}

@Override
public void paintComponent(Graphics g) {

    super.paintComponent(g);

    g.setColor(Color.white);
    g.fillRect(0,0,BOX_WIDTH,BOX_HEIGHT);

    padel1.draw(g);
    padel2.draw(g);
    ball1.draw(g);
    ball2.draw(g);

}

public void keyPressed(KeyEvent e){

    if(e.getKeyCode() == KeyEvent.VK_UP){padel2.setSpeed(-Padel.padelSpeed);}
    if(e.getKeyCode() == KeyEvent.VK_DOWN){padel2.setSpeed(Padel.padelSpeed);}

    if(e.getKeyCode() == KeyEvent.VK_W){padel1.setSpeed(-Padel.padelSpeed);}
    if(e.getKeyCode() == KeyEvent.VK_S){padel1.setSpeed(Padel.padelSpeed);}

}

public void keyReleased(KeyEvent e) {

    if(e.getKeyCode() == KeyEvent.VK_UP){padel2.setSpeed(0);}
    if(e.getKeyCode() == KeyEvent.VK_DOWN){padel2.setSpeed(0);}

    if(e.getKeyCode() == KeyEvent.VK_W){padel1.setSpeed(0);}
    if(e.getKeyCode() == KeyEvent.VK_S){padel1.setSpeed(0);}


}

public void keyTyped(KeyEvent e) {}

public static void main(String[] args) {

    javax.swing.SwingUtilities.invokeLater(new Runnable() {

        public void run() {

            //Create Frame
            JFrame frame = new JFrame("PONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONG");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            Pong pong = new Pong();
            frame.setContentPane(pong); 
            frame.setSize(BOX_WIDTH,BOX_HEIGHT);
            frame.pack();
            frame.addKeyListener(pong);
            frame.setVisible(true);

        }

    });

}

}

Padel Class:

package Pong;

import java.awt.*;
import java.util.Random;

public class Padel {

public int y;
public int x;

public boolean ws;

public int speed = 0;

public final static int padelSpeed = 3;
public final static int padelWidth = 30;
public final static int padelLength = 200;

Random rng = new Random();

int r = rng.nextInt(256);
int g = rng.nextInt(256);
int b = rng.nextInt(256);

Color color = new Color(r,g,b);

public Padel(int xPos, int yPos, boolean wands){

    y = yPos;
    x = xPos;

    ws = wands;

}

public void update(){

    if(speed > 0 && y + padelLength < Pong.BOX_HEIGHT){

        y = y + speed;

    }

    if(speed < 0 && y > 0){

        y = y + speed;

    }

}

public void draw(Graphics g) {

    g.setColor(color);
    g.fillRoundRect(x, y, padelWidth, padelLength, 25, 25);

}

public int getX(){

    return x;

}

public int getY(){

    return y;

}

public int getWidth(){

    return padelWidth;

}

public int getLength(){

    return padelLength;

}

public int getSpeed(){

    return speed;

}

public void setSpeed(int speed1){

    speed = speed1;


}

public int getPadelSpeed(){

    return padelSpeed;

}

}

Ball Class:

package Pong;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class Ball {

Random rng = new Random();

int r = rng.nextInt(256);
int g = rng.nextInt(256);
int b = rng.nextInt(256);

Color color = new Color(r,g,b);

public final static double ballSpeedMin = -2.0;
public final static double ballSpeedMax = 2.0;
public final static double middleSpeedCutoff = 1.0;

public final static double ballIncrease = .2;

public final int ballRadiusMin = 10;
public final int ballRadiusMax = 40;

double x;
double y;

double xSpeed;
double ySpeed;

int ballRadius;

public Ball(double xPos,double yPos){

    x = xPos;
    y = yPos;

    xSpeed = getRandomSpeed();
    ySpeed = getRandomSpeed();

    ballRadius = getRandomRadius();

}

public double getRandomSpeed(){

    Random r =new Random();

    return ballSpeedMin + (ballSpeedMax - ballSpeedMin) * r.nextDouble();

}

public int getRandomRadius(){

    Random r = new Random();

    return r.nextInt((ballRadiusMax - ballRadiusMin) + 1) +    ballRadiusMin;

}

public void update(){

    x = x + xSpeed;
    y = y + ySpeed;

    ySpeed = verticalBounce();

    double multiplier = .75;

    if(getLowX() < Pong.padelSpace + Padel.padelWidth){

        if(y>=Pong.padel1y1 && y<=Pong.padel1y2){

            double yPos = y - Pong.padel1y1 - (Padel.padelLength/2);

            if(yPos<0){
                double speed = getSpeed() + ballIncrease;
                yPos = Math.abs(yPos);
                double angle = multiplier * yPos;
                double ratio = Math.tan(angle);
                xSpeed = ratio * (speed/(ratio + 1));
                ySpeed = -Math.sqrt((speed * speed) - (xSpeed * xSpeed));
            }

            else if(yPos>0){
                double speed = getSpeed() + ballIncrease;
                yPos = Math.abs(yPos);
                double angle = multiplier * yPos;
                double ratio = Math.tan(angle);
                xSpeed = ratio * (speed/(ratio + 1));
                ySpeed = Math.sqrt((speed * speed) - (xSpeed * xSpeed));
            }

            else{
                double speed = getSpeed();

                xSpeed = speed;
                ySpeed = 0;

            }

        }

        else{

            System.exit(0);

        }

    }

    if(getHighX() > Pong.BOX_WIDTH - Pong.padelSpace - Padel.padelWidth){

        if(y>Pong.padel2y1 && y<Pong.padel2y2){

            double yPos = y - Pong.padel2y1 - (Padel.padelLength/2);

            if(yPos<0){
                double speed = getSpeed() + ballIncrease;
                yPos = Math.abs(yPos);
                double angle = multiplier * yPos;
                double ratio = Math.tan(angle);
                xSpeed = - ratio * (speed/(ratio + 1));
                ySpeed = -Math.sqrt((speed * speed) - (xSpeed * xSpeed));
            }

            else if(yPos>0){
                double speed = getSpeed() + ballIncrease;
                yPos = Math.abs(yPos);
                double angle = multiplier * yPos;
                double ratio = Math.tan(angle);
                xSpeed = - ratio * (speed/(ratio + 1));
                ySpeed = Math.sqrt((speed * speed) - (xSpeed * xSpeed));
            }

            else{
                double speed = getSpeed();

                xSpeed = -speed;
                ySpeed = 0;

            }

        }

        else{

            System.exit(0);

        }

    }

}

public void draw(Graphics g) {

    g.setColor(color);

    int xPos = (int) Math.round(x) - ballRadius;
    int yPos = (int) Math.round(y) - ballRadius;

    g.fillOval(xPos,yPos,ballRadius*2,ballRadius*2);

}

public double verticalBounce(){

    if(y - ballRadius<0 || y + ballRadius > Pong.BOX_HEIGHT){

        return -ySpeed;

    }

    else{

        return ySpeed;

    }
}

public double getY(){

    return y;

}

public double getX(){

    return x;

}

public double getYSpeed(){

    return ySpeed;

}

public double getXSpeed(){

    return xSpeed;

}

public void setYSpeed(double y){

    ySpeed = y;

}

public void setXSpeed(double x){

    xSpeed = x;

}

public double getLowX(){

    return x - ballRadius;

}

public double getLowY(){

    return y - ballRadius;

}

public double getHighX(){

    return x + ballRadius;

}

public double getHighY(){

    return y + ballRadius;

}

public double getSpeed(){

    return Math.sqrt((xSpeed*xSpeed)+(ySpeed*ySpeed));

}

}

Solution

  •     double multiplier = .75;
        //...
    
               double yPos = y - Pong.padel1y1 - (Padel.padelLength/2);
               //...
               double angle = multiplier * yPos;
    

    Are you aware that the angles you pass in trigonometric functions are expressed in radians?
    Assuming your paddle length is 20, with yPos varying between [-10, 10] your angle will vary between [-7.5, 7.5]. Translate this in radians and you'll see your angle rotates around the circle a bit more than 2 times. Is really this what you want?