5

Well I've searched a lot for this but all I can find is people saying like do pi * direction, direction being the angle that the ball is coming in at I assume. But my problem is, I have no idea how I get the angle the ball is coming in at in the first place so I can't do these. If anyone could explain how I would calculate the angle that the ball has hit the paddle hat, the amount of velocity that the ball should be given after rebound and the angle it should be incremented by then that would be awesome.

Thankyou for any and all responses!

My code works as follows (So you can get an idea of how I'd like to do it):

/* General Paddle Properties */
double PaddleLength = 80;  //Down-wards length of the paddle
double PaddleWidth = 8;  //How thick the paddle is

/* Positioning of user control paddle */
double UserPaddleTop = 0;  //How far away from the top of the screen the paddle is
double UserPaddleLeft = 10;  //How far left from the side of the client rectangle it is

/* Positioning of ai controled paddle */
double AIPaddleTop = 0;
double AIPaddleLeft = 10;

/* Ball properties and position */
double BallSize = 5;
double BallTop = 0; 
double BallLeft = 0;
double BallSpeedY = -0.01, BallSpeedX = -0.03;

Methods:

private void UpdateBall()
        {
            if (((int)(UserPaddleLeft + PaddleWidth) == (int)BallLeft) && !((int)UserPaddleTop > (int)BallTop) && !((int)(UserPaddleTop + PaddleLength) < BallTop) 
                || ((int)(AIPaddleLeft - PaddleWidth) == (int)BallLeft) && !((int)AIPaddleTop > (int)BallTop) && !((int)(AIPaddleTop + PaddleLength) < BallTop)) //Collided
            {
                BallSpeedX = -BallSpeedX; //The height is 800 the balltop is 300
                BallSpeedY = Math.Cos(BallSpeedX
            }

            if ((int)BallTop == 0 || (int)BallTop == ClientRectangle.Height) //Hit the top 
            {
                BallSpeedY = -BallSpeedY;
            }

            if ((int)BallLeft == 0)
            {
                System.Diagnostics.Debug.WriteLine("AI gets one point!");
                BallSpeedX = -0.03; //Goes towards the user AI has scored
                Scores[0]++;
                this.Title = "Pong Testing - Scores: " + Scores[0] + "|" + Scores[1];
                ResetAll();
            }
            else if ((int)BallLeft == ClientRectangle.Width)
            {
                System.Diagnostics.Debug.WriteLine("User gets one point!");
                BallSpeedX = 0.03; //Goes towards the AI user has scored
                Scores[1]++;
                this.Title = "Pong Testing - Scores: " + Scores[0] + "|" + Scores[1];
                ResetAll();
            }

            BallLeft = (BallLeft + BallSpeedX);
            BallTop = (BallTop + BallSpeedY);
        }

        private void UpdateAI()
        {
            if(!((int)(BallTop + PaddleLength) == 0) && !( (int)(BallTop + PaddleLength) >= ClientRectangle.Height ) ) //Make sure updating it pos won't make it go out of bounds
                AIPaddleTop = BallTop; //Change to real ai by using offset
        }

        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);

            if ( (int)UserPaddleTop != 0 && Keyboard[Key.Up])
            {
                UserPaddleTop = UserPaddleTop - MoveSpeed;
            }
            else if (Keyboard[Key.Down] && (int)(UserPaddleTop + PaddleLength) != ClientRectangle.Height)
            {
                UserPaddleTop = UserPaddleTop + MoveSpeed;
            }
        }

UPDATE 1:

Thanks to the help of everyone I have been able to come up with some basic code for it but now this code just sends the ball flying so fast that it's impossible to get it. Could anyone help please?

Code:

        double AngleNormal = Math.Atan2(BallSpeedX,BallSpeedY);
        double AngleBallMovement = Math.Sqrt((BallSpeedX * BallSpeedX) + (BallSpeedY * BallSpeedY));
        double ReflectionAngle = AngleNormal - (AngleBallMovement - AngleNormal);
        BallSpeedY = Math.Sin(ReflectionAngle);
        BallSpeedX = Math.Cos(ReflectionAngle);
user1763295
  • 860
  • 3
  • 16
  • 34
  • 2
    This is a maths question and has nothing to do with programming. – Mitch Wheat Apr 02 '13 at 00:04
  • 3
    I would say it does since I'm programmatically calculating the value but I'm not here to argue. Sorry if it is actually just maths. – user1763295 Apr 02 '13 at 00:07
  • Would you not know the very first angle that the ball is released at? From there you can calculate the angle the ball will hit the paddle at and the angles thereafter. Although I do agree with Mitch, this is more Maths than programming. Nice puzzle though – Steven Marciano Apr 02 '13 at 00:20
  • There is no angle that's my problem, it is released with a value, every time a frame renders the bally is set to ballY+value thus moving it up or down. – user1763295 Apr 02 '13 at 00:22
  • In most versions of Pong, the incident angle doesn't matter, except to determine direction. Hitting the ball close to the center of the paddle returns the ball at a moderate angle from center, while hitting the ball close to the edge of the paddle returns the ball at a more severe angle from the center. – Gilbert Le Blanc Apr 02 '13 at 16:02
  • @GilbertLeBlanc For the specific case of paddle collisions, that might be OK. For wall collisions you still need to work out the angles. – Corey Apr 05 '13 at 05:30

2 Answers2

3

In the simplest sense (ignoring ball spin, friction, paddle movement, etc.) is to work out the angle of incidence relative to the surface normal and invert it. In the context of simple physics collisions, angle of incidence is the angle of movement of the ball relative to the normal of the surface of the paddle at the point of collision. In an arbitrary coordinate space the calculation is something like:

angleReflect = angleNormal - (angleBallMovement - angleNormal)

For a very simple case of a true rectangular paddle the normal is going to be perpendicular to the paddle's axis of motion. This gives you very little control over the ball, since the reflection angle is always going to be purely a function of the direction the ball is moving.

You can simulate a curved paddle surface by varying the normal vector of the paddle's surface based on the distance from the center of the paddle that the ball impacts. This allows the player to change the ball's movement angle by intercepting the ball off center on the paddle to get a steeper or shallower reflection angle.

The real fun is when you start adding friction, spin and paddle motion calculations to the mix. Gets a bit much for most players to keep track of, but allows for some interesting trick shots :)

--

As for how to calculate the angles, the trig function Math.atan2(x, y) will give you an angle (in radians) for a given [x,y] velocity vector, and Math.sqrt(x*x + y*y) gives you the length of the movement vector. This gives you a line that you can intersect with the surface of the paddle (factoring in the radius of the ball, if you're into accuracy) to get the point of impact. The remaining portion of the movement 'line' is reflected using the angle of incidence and whatever other calculations you add, giving a final position of the ball and new velocity vector.

A laser pointer and a mirror are good visualization tools for this :)

Corey
  • 15,524
  • 2
  • 35
  • 68
  • Could you take a look at the way my code works please, While your suggestion is great I'm not sure if it fits with the way my ballY movement is done. It's basically done by an increment, every time a frame is rendered the ballY is set to ballY + increment. So what would angle reflect actually be applied to with that in mind or is there a different way you would do it? – user1763295 Apr 02 '13 at 01:11
  • 1
    @user1763295 Your code uses rectangular coordinates (`BallSpeedX` and `BallSpeedY`) to describe the velocity vector. Converting this to polar coordinates (`angle` and `magnitude`) gives you a simpler way to calculate the reflection. Then you can convert back to rectangular coordinates for updating. They're interchangeable, just two ways of representing the same information, so use the one that is applicable to the particular problem. – Corey Apr 02 '13 at 03:07
  • Sorry to but you but I've done what as you said and then combined that angle maths with ideas I've found in other post and now when a paddle hits the ball it just goes flying away and the person that didn't hit the ball gets a point because it goes so quick and just goes out of bounds. I've updated the original post to show the code I have now. – user1763295 Apr 02 '13 at 15:53
  • @user1763295 Your conversion back to rectangular coordinates will give a unit vector. You need to scale the X and Y values by `AngleBallMovement` to keep the speed the same. You should test your conversions to see the effects - convert rectangular to polar and back again and see how different the output is from the input. – Corey Apr 03 '13 at 00:55
2

In order to calculate an angle, you have to know what direction the ball is moving in. You have that information in your BallSpeedX and BallSpeedY values. Say your original position is (0, 0), BallSpeedX is 2, and BallSpeedY is 3. So you have a right triangle with one side being 2 and the other being 3, and you can use simple trigonometry to figure out the angle.

Now, the paddle is probably parallel with the X axis, so you have to compute the angle relative to that axis. But that shouldn't be too tough.

Once you know the angle that the ball hits the paddle, you just subtract that value from 180 degrees (or pi radians), and that's new angle. So if the ball hits the paddle at 60 degrees, it's going to bounce off at 120 degrees. That's assuming no spin, perfect elasticity, no paddle movement, etc.

The ball's speed when it comes off the paddle is up to you. You can assume no energy loss and give the ball the same speed coming off the paddle as going on. Or you can say that a bounce absorbs 10% of the ball's energy, in which case you'd want to reduce the ball's velocity by 10% (but don't just subtract 10% from the X and Y speed values, or you'll change the angle).

Clear as mud now?

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351