6 Replies - 5335 Views - Last Post: 21 August 2012 - 11:04 AM

#1 rgfirefly24  Icon User is online

  • D.I.C Lover
  • member icon


Reputation: 262
  • View blog
  • Posts: 1,460
  • Joined: 07-April 08

Paddle collision

Posted 20 August 2012 - 07:50 PM

First, The code as it is works as it should; however, the movement of the ball is not exactly what I would expect from playing a pong game. Basically here is what I want:

When the ball collides with the "face" of the paddle it reflects back at an angle. Where I'm falling short is exactly how to determine the reflection angle. I've looked over SixOfEleven's breakout tutorial, and he suggested using line segment math, but I really don't understand it.(I am currently researching it and will update this thread if/when I come up with an attempt).

I have implemented a piece where I split the paddle into the top and bottom half, then based off where in each segment the ball hits, I change the Y of motion to 60 degrees * the percent "sector" of the paddle. I did this based off reading this thread: Pong Collision Help in C#
int degree = -60;

                if (motion.Y > 0)
                {
                    degree = 60;
                }

                if (ballLocation.Y < player.paddle.GetBounds().Height / 2)
                {
                    float percent = ballLocation.Y / ((float)(player.paddle.GetBounds().Height) / 2);

                    motion.Y = degree * (percent / 100);
                }
                else
                {
                    float percent = ballLocation.Y / (float)player.paddle.GetBounds().Height;
                    motion.Y = degree * (percent / 100);
                }



While this does work somewhat, it is very sporadic and the angles just don't seem like they are "real". Depending on where the ball hits the speed will be either extremely slow, or extremely fast.

I've looked through google using this search, but have not been able to figure out a good way to do paddle collision. My questions is this, beyond doing the basic .Intersects(), what would be the most efficient way of doing the collision.

Here is the full PaddleCollision method:
 public void PaddleCollision(Player player)
        {
            Rectangle ballLocation = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);

            if (player.paddle.GetBounds().Intersects(ballLocation))
            {
                if (player.playerNumber == 1)
                {
                    position.X = player.paddle.GetBounds().X + texture.Width;
                }
                else
                {
                    position.X = player.paddle.GetBounds().X - texture.Width;
                }

                int degree = -60;

                if (motion.Y > 0)
                {
                    degree = 60;
                }

                if (ballLocation.Y < player.paddle.GetBounds().Height / 2)
                {
                    float percent = ballLocation.Y / ((float)(player.paddle.GetBounds().Height) / 2);

                    motion.Y = degree * (percent / 100);
                }
                else
                {
                    float percent = ballLocation.Y / (float)player.paddle.GetBounds().Height;
                    motion.Y = degree * (percent / 100);
                }
                motion.X *= -1;
            }
        }



Is This A Good Question/Topic? 0
  • +

Replies To: Paddle collision

#2 MrShoes  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 312
  • View blog
  • Posts: 488
  • Joined: 13-June 12

Re: Paddle collision

Posted 21 August 2012 - 12:55 AM

In 2D XNA Gaming, I've never experienced any issues with .Intersects(), however sometimes it's better to foreshadow the intersection: what I mean is, calculate where the ball and paddle should be in the next Update() loop, and check for a collision there.

At the point of collision, the ball's new angle should be reflected around the normal. This is a good Stack Overflow question on the subject.
Was This Post Helpful? 0
  • +
  • -

#3 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 560
  • View blog
  • Posts: 1,263
  • Joined: 24-April 12

Re: Paddle collision

Posted 21 August 2012 - 07:44 AM

Do you really need to worry about the angle? Or do you just need to make the ball reflect? I'll assume that you just need the ball to reflect. So, there's a simple answer to this question and a complex one.

The simple answer (assuming that the paddle moves up and down across the Y axis) is this:

motion.Y *= -1;



Assuming that you have position as a seperate object and that you're adding motion to that, you will be reversing the Y component of the motion while maintaining the exact same motion.X movement. So, the X motion will remain the same while the Y motion will remain the same but reverse directions. The result is a reflection from the point that this code occured at. Just make sure it happens at the surface of the paddle.

The problem with this answer is that it's "axis aligned". It's amazing how well it works as long as all the surfaces that you're reflecting off of are aligned with the axes. But what if the surface is not perfectly aligned with the X or Y axis? Then the answer becomes more complex.

For Pong, the simple answer will generally do. The walls and the paddles tend to all be perfectly axis aligned and so this math "just works". But what if you made the game more complex? What if you made it more like Air Hockey where you have just a small hole that the ball has to go through? Everything would be the same at this point. But what if you turn the paddle into a V shape or allow the player to angle the paddle, so that the ball will reflect at different angles?

Then you need the complex answer.

First of all, it's probably time to start learning about vectors. In 2D they get pretty lazy with vectors and usually use them wrong. Then when you really need to understand them in 3D you're lost because they didn't teach them in 2D.

For more information on vectors I'll direct you to my vector tutorial:
http://xna-3d-101.co...ls/Vectors.html

Basically, you have three vectors for this problem. Let's say that you have a paddle that can be rotated to face different angles. The first vector will be called the "paddle's normal". A normalized vector is a vector who's length has been set to one unit. When you do that you throw away any "amount" information in the vector and just set the amount to one. At that point the vector only has direction information. And that's what we want here, because we just want a vector that faces whatever direction the paddle faces.

You should be thinking of vectors (other than positions which are not really vectors) as arrows. And you should be thinking of the X and Y coordinates as the position of the head of the arrow where the tail is always attached at 0,0 (the origin). The "paddle's normal" vector is not attached to the paddle itself but points in the same direction as the paddle. You might think of it as an arrow coming out of the paddle's face, but it's really attached to the origin and not the paddle. But that doesn't matter because it still points in the same direction no matter what it's attached to. And the direction is all that matters here.

So we define our "paddle's normal" vector as:

Vector2 PaddlesNormal = new Vector2(1f,0f);

I believe that points horizontally to the right.

It's easy to see that that arrow/vector has a length of one. It will be difficult to see that once you rotate it.

To rotate the facing of the paddle, you need to use the rotation formula because XNA doesn't have vector rotation for 2D vectors built in:

x = X * (float)Math.Cos(TurnAngle) - Y * (float)Math.Sin(TurnAngle);

y = X * (float)Math.Sin(TurnAngle) + Y * (float)Math.Cos(TurnAngle);

So now you have a paddle, it's facing direction/vector, and a way to rotate it. Time to put the ball into play.

You'll probably have the ball's position represented as a vector (it's not a vector, but it makes the math easier to store it that way). And you'll probably have a vector for the ball's velocity(movement per frame).

So maybe the code looks something like this now.

Vector2 PaddlesNormal = new Vector2(1f,0f);
Vector2 BallsPosition = new Vector2(23f,28f);
Vector2 BallsVelocity = new Vector2(-1f,0f);

BallsVelocity = BallsVelocity/60f; //Divide by 60 frames per second to get motion per frame.



I set the ball's initial position to whatever. And I set the ball's initial velocity to be towards the paddle, but that could be anything starting out. The longer the BallsVelocity vector, the faster that it will move. You increase the vector length by multiplying it by a number. You set it back to a length of 1 by normalizing it. You decrease the vector's length by dividing it by a number. So, if the length (or magnitude) of the vector is 9, then dividing the whole vector by 3 will set it's length to 3 while maintaining the same direction.

Now the math of reflection here is a little tricky, especially if you're new to vectors. Fortunately, XNA does the math for you.

Vector2 PaddlesNormal = new Vector2(1f,0f);
Vector2 BallsPosition = new Vector2(23f,28f);
Vector2 BallsVelocity = new Vector2(-1f,0f);

BallsVelocity = BallsVelocity/60f; //Divide by 60 frames per second to get motion per frame.

if (CollisionOccured)
{
  BallsVelocity = Vector2.Reflect(BalsVelocity, PaddlesNormal);
}

BallsPosition += BallsVelocity;



I haven't tested this code, but mathematically it's all correct. It should get you started thinking in the right direction anyway. Notice that I didn't mention X and Y here anywhere. Other then setting them initially, they shouldn't matter. Unfortunately, XNA doesn't do 2D rotations, so you have to handle that with X and Y components, but that's probably the exception. And I would probably just go ahead and make a RotateVector method that accepts a Vector2 and an angle in radians and returns a new Vector2 with the rotated vector. Then you wouldn't have to worry about X and Y.

If you're using vectors correctly, the values of X and Y are too complicated to think about without a pen and paper. For example, if BallsVelocity is new Vector2(0.2894848467f, -0.0133546f) how fast is it moving? The answer is the length, or magnitude, of that vector but no one can tell you how long that vector is just by looking at that. But the answer is easy in XNA, it's BallsVelocity.Length(). Notice, you don't mess with X or Y there.

Basically, you have to use X and Y for the initial setup, but after you define X and Y in the initial setup, if you are using X and Y after that you are almost certainly not using vectors correctly. And there will come a time in game programming where you really need to understand them. So the sooner you can start using them correctly, the better. (Sorry for the lecture, but it really will be better off the sooner you learn to use vectors correctly.)

Also, you "could" solve this as a trig problem without vectors, but that just makes it more difficult on you as the programmer, probably makes the code more confusing to read, and probably offers little to no performance advantage. There's a reason that they built Vector classes into XNA. They're extremly handy in game programming and get used a LOT.

Anyway, I hope that helps.

This post has been edited by BBeck: 21 August 2012 - 07:55 AM

Was This Post Helpful? 2
  • +
  • -

#4 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 560
  • View blog
  • Posts: 1,263
  • Joined: 24-April 12

Re: Paddle collision

Posted 21 August 2012 - 08:38 AM

You know, it's driving me a little crazy as to why Microsoft didn't include 2D rotations in XNA. It seems obvious to me that that would be one of the most common things you could possibly face in a 2D problem. It kind of occured to me that you could translate the vector2 into a vector3, rotate it, and translate it back. But that seemed more like a work around then a solution.

So, I started digging into XNA, trying to find a rotation formula and wondering what the creators of XNA were expecting you to do. And this is what I found.

It looks to me that Microsoft intended for you to do rotations like this:

Vector2 BallsPosition = new Vector2(10f,10f);
Vector2 BallsVelocity = new Vector2(-0.01f, 0f);
float AngleToTurn = MathHelper.ToRadians(26f);
Matrix RotationMatrix = new Matrix.CreateRotationZ(AngleToTurn);


BallsVelocity = Vector2.Transform(BallsVelocity, RotationMatrix);




Notice that it's a 3D rotation, but it's happening in 2D. If you understand the math behind it, it will obviously work, but it seems a bit odd. I would expect Z is the only axis you can rotate around in 2D because none of the others make sense.

This also makes me wonder whether you can't handle everything here as matrices. Although, that seem to make less sense to me in 2D as it does in 3D (in 3D your final result has to be a matrix anyway, so it makes a lot more sense to work in matrices as much as possible).

Anyway, food for thought. It appears that is built in functionality you can use to rotate in 2D. You could also rotate the BallsPosition using that, but you have to realize that it's always rotating around the origin. So you have to manipulate the math a bit to make it rotate around something other than the origin (translate the position by the offset of the rotation point to the origin).
Was This Post Helpful? 0
  • +
  • -

#5 lordofduct  Icon User is offline

  • I'm a cheeseburger
  • member icon


Reputation: 2531
  • View blog
  • Posts: 4,631
  • Joined: 24-September 10

Re: Paddle collision

Posted 21 August 2012 - 09:27 AM

You need to decide what kind of 'reflection' you want.

Pong/Breakout/etc games have used various bounce effects to manipulate the gameplay, and they were seldom "accurate" to real-world physics.

Some include:

#
Basic vector reflection following the formula:
Posted Image
(src: http://mathworld.wol...eflection.html)

where n is the normal vector of the surface you're reflecting off of (probably <1,0> or <-1,0> depending on the left or right paddle respectively)

This is usually calculated with normalized vectors, to keep a constant velocity. Though it can also have a speed adjustment applied based of the angle of the vector to change gameplay.


#
Position determinant:

This technique is based of WHERE on the paddle the ball struck. If it struck near the middle it'll bounce back more along the x axis. Where as if it's at the edge it's bounced more towards the y-axis.

It can be seen as if the paddles physics is shaped more like a crescent (while still actually being a rectangle).

Speeds can again be adjusted like in previous. Sometimes where the side shots slow the ball, and the middle shots speed the ball incremently. The more times you hit the middle, the faster it goes. The more times the sides, the slower.

To do this you have a determinant formula. Calculate the position relative to the middle of the paddle (middle being 0, -1 being top, 1 being bottom). Then take the straight vector <1,0> (or <-1,0> for right paddle) and rotate left or right to some max angle theta * x, where x is the scalar position on the paddle. Lastly set OR increment velocity based on position again.


#
Real physics:
This may set some mass, friction, and sometimes even springiness to both the paddle and ball. And allow realistic newtonian physics calculations to occur.




You need to decide which you'll use. Which will give the outcome you consider "correct". Personally I like incrementing velocity based on position, combined with simple vector reflection (the wolfram link).

Implement that, and if it doesn't act the way that said model is supposed to act. Then you can come and ask us why.

Otherwise my answer to your OP is:

"It works within the model you chose. It's just your model you chose doesn't create the outcome you believe to be normal pong style."

This post has been edited by lordofduct: 21 August 2012 - 09:34 AM

Was This Post Helpful? 3
  • +
  • -

#6 rgfirefly24  Icon User is online

  • D.I.C Lover
  • member icon


Reputation: 262
  • View blog
  • Posts: 1,460
  • Joined: 07-April 08

Re: Paddle collision

Posted 21 August 2012 - 10:36 AM

Up till this point I've been trying to implement Position determinant, although the reason why I say it doesn't seem to be correct is because the ball will speed up/slow down drastically, and when the ball hits off the bottom or the top sections of the paddle (but still on the "face") it reverses both the X and Y motion so it acts like it bounced off the corner itself. Maybe my implementation of it was what is causing me to not think it is correct. I can post my full code once I get back home so that you can see how it runs, but for now all I have to offer is the PaddleCollision method.

Where I think i'm going wrong is that i'm taking the position of the ball at the point in time it intersects the paddle and using Y of the ball's position vector to do the calculation for the reflection. I'm not 100% sure, but I'm pretty sure that doing it that way is what is causing the drastic speed up/slow down of the ball.

This post has been edited by rgfirefly24: 21 August 2012 - 10:37 AM

Was This Post Helpful? 0
  • +
  • -

#7 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 560
  • View blog
  • Posts: 1,263
  • Joined: 24-April 12

Re: Paddle collision

Posted 21 August 2012 - 11:04 AM

I would have never guessed what you were trying to do there, if LordOfDuct hadn't pointed it out.

The visible shape doesn't match the mathematical shape, but hey that's fun.

So, really it's the same thing, you're just rotating the paddle's normal by a percentage of an angle. Full rotation would be +90 degrees or -90 degrees. In your case, it looks like you want to use 60 degrees, which is a more shallow arc.

So mathematically, you're turning it into an arc that's maybe as much as a full half circle (at 90 degrees). Or more shallow the less the angle.

Depending on whether you make one the center or make zero the center, you can control whether the arc faces inward or outward.

It looks like you're already calculating the percentage. You just need to use that percentage to apply that percentage of degrees (or radians) to the rotation of the paddle's normal.

Then you can use the Vector2.Reflection method with the normal that you put in as the rotated normal.

I haven't used the Reflection method, but I think it should do that exact equation that LordOfDuct just gave you there. Except it does all the "ugly" vector math for you.

Anyway, I always like to see code examples, or at least pseudo-code examples. So:

Vector2 BallsPosition = new Vector2(10f,10f); //Just an X,Y coordinate.
Vector2 BallsVelocity = new Vector2(-0.5f, 0f); //Speed and direction info combined.
Vector2 PaddlesNormal = new Vector2(1f,0f); //Points straight down the X axis out from the paddle.
Vector2 PaddleDeflectionNormal;
float FullDeflection = MathHelper.ToRadians(60f); //Maximum deflection is 60 degrees
float PercentageOfDeflection = 1.0f; //100%
float AngleOfDeflection = FullDeflection * PercentageOfDeflection;
Matrix RotationMatrix = new Matrix.CreateRotationZ(AngleOfDeflection); 

BallsVelocity = BallsVelocity/60f; //Divide by 60 frames per second to get motion per frame.
PaddleDeflectionNormal = Vector2.Transform(PaddlesNormal, RotationMatrix);

if (CollisionOccured)
{
  BallsVelocity = Vector2.Reflect(BallsVelocity, PaddleDeflectionNormal);
}

BallsPosition += BallsVelocity;




I think something like that should get it.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1