Hey, so I'm making a Breakout game in C++ w/ DirectX, and I'm having some trouble thinking of the ball bouncing physics. The way I've made breakout games before was to have the ball only move at 45 degree angles. This was fairly simple. Just reverse the x or y movement everytime you hit something. But now I want to make a game where the ball moves not just at 45 degree angles. The way I see it, bouncing against non-moving blocks will not change the direction that the ball is moving (that is angle-wise, obviously it will bounce off, but the angle that the ball is moving won't ever change to anything other than 45, 135, 225, or 315 degrees. So I came to the conclusion that the only way to change the angle is when the ball collides with a moving object, i.e., the paddle. But I'm not sure how this works exactly. How do I calculate the change in angle based on the movement of the paddle, the place the ball hits the paddle, and the angle the ball is currently traveling at. I look online for some tips but I couldn't find much that gave an algorithm and explained it. So anyone have what I'm looking for. How do I use the factors I just mentioned along with any others I might need to take into consideration to write the code for this?

Any and all help is appreciated. :)

Recommended Answers

All 13 Replies

You use simple vectors. You can rotate vectors with minimal calculations.

So when the ball hits the paddle, based on the distance from the center, rotate the directional vector of the ball by a certain amount of degrees.

http://chortle.ccsu.edu/VectorLessons/vectorIndex.html

The above link contains a pretty good coverage of vector math. Vectors are very simple to use and make thing very easy once you get the hang of them.

Try them out. :), come back if your run into trouble or if you figure it out post your discoveries here ;)

commented: Yep, that's about it! +2

I didn't have time to read through that yet, but I've heard that distance from center thing before, and I don't necessarily get it. If the paddle isn't moving, the distance from the center of the paddle shouldn't affect the angle of the ball's path of motion (correct me if I'm wrong). And if the paddle is moving, I don't see the distance from the center playing as big a role in the change of direction as I do the direction the paddle is moving relative to the horizontal direction of the ball.

The position of the paddle when the ball hits it is wholely irrelevant - the paddle is the same all over, flat, and moves in a constrained direction ( in its own plane ), so any moving point on the paddle is 'identical' to any other point in terms of any calculation you perform. The only areas of the paddle that ARE different are the corners, do you model that accurately?

The quick trick you describe ( inverting one of the components of the moving object's velocity on a bounce with a plane ) works irrespective of the initial angle that the ball is travelling at; if you start the ball moving at any angle other than 45 deg, then bounce angles will be a little more 'varied', because only 45 deg will invert as itself. Any other angle will have slightly more possible results.

But.. I get what you're saying. Given any initial starting angle, and assuming that the player is 'perfect', and assuming that you don't handle corners of the paddle in any special way; the movement of the ball will always be exactly the same; the game is deterministic with a perfect player.

I am not sure if that's how breakout always is.. Alot of basic collision detection code assumes that a collision happens instantanously, and I believe ( although I may be completely wrong on this! ) that if a perfect sphere bounces off a perfect plane, that the velocity of the plane that is in the plane doesn't affect the bounce angle of the sphere. Like I say, I may be wrong :P

For a quick solution, instead of doing this with the ball velocity after a bounce:

velocity2[x] = velocity1[x];
velocity2[y] = velocity1[y] * -1;

try this:

velocity2[x] = velocity1[x] + ( paddle_velocity[x] * some_constant );
velocity2[y] = velocity1[y] * -1;

[[ some_constant should be between 0 = original behaviour and 1 = lots of sideways effect ]]

the effect here, is that if the paddle moves in the horizontal direction that the ball is moving, the ball will bounce 'flatter', if the paddle moves in the opposite horizontal direction, the ball bounces upwards more sharply. this is sorta like the paddle being rough, the collision being non-instanteanous, and 'pushing' the ball sideways slightly if the paddle moves fast enough.

bear in mind, that this will add energy to your system ( or remove it ) over time. normalize the post-collision velocity and multiply it by the length of the pre-collision velocity to prevent that.. [[ in a system that doesnt have a player adding forces, you'd normally conserve the energy by pushing the paddle backwards ( or starting it spinning ) after the bounce.. but.. that just wouldn't be breakout would it. ]]

Yes, I like this:

velocity2[x] = velocity1[x] + ( paddle_velocity[x] * some_constant );
velocity2[y] = velocity1[y] * -1;

solution a lot. I had thought of something like that before, but I thought that the code was just affecting the speed of the ball (which I didn't want to worry about yet). I didn't think of that fact that changing the x movement while not changing the y movement will result in a change of angle. I especially like this solution because it avoids trig (which I hear really taxes the proccesor) as well as keeping track of the angle of movement.

Now, the one thing I'm thinking about is that there should be some sort of gradule friction, as well as a maximum ball speed, otherwise the ball speed would get out of hand. I'm thinking that figuring out the maximum ball speed might require some inverse trig functions. Is there another way to figure out the ball's speed w/o trig?

Edit: O, well I just thought of simply putting upper and lower limits (and friction) on the x and y velocities seperately. This would avoid trig, but the friction would be a bit unrealistic. But, hey, games are supposed to be fun, not realistic.

The magnitude/speed of a velocity is just the length of the vector; in components: speed = sqrt( ( velocity[x] * velocity[x] ) + ( velocity[y] * velocity[y] ) ); ( good ol' pythagorus theorem:'square of the hypotenuse = the sum of the squares of the other two sides. )

I wouldn't worry too much about the speed of trig / speed of sqrt on processors in this day and age, not unless you're dealing with 1000s of trigs/sqrts/etc every frame.

Edit: And, to 'rescale a vector' to some new length:

vector2[x] = ( vector1[x] / old_length ) * new_length;
vector2[y] = ( vector1[y] / old_length ) * new_length;

It become alot easier to work with math/vector classes than to work entirely in components after a point..

So, wait - what exactly is a velocity vector? A point that the object will move to every frame, and then is updated? Or is it always relative to the current position of the object (I'm guessing its this one). So if you were moving to the left at 5 pixels per frame, the velocity would be (-5,0)?

Yes, the second interpretation is correct.

> Velocity is change in position w/ respect to time ( a vector )
> Acceleration is change in velocity w/ respect to time ( a vector )
> Speed is distance travelled w/ respect to time ( a scalar, equal to length of velocity )

Erm, the same exists for rotation, except velocity = angular momentum, and acceleration = torque. But err.. don't worry about rotation, it's evil.

Yes, the second interpretation is correct.
the same exists for rotation, except velocity = angular momentum, and acceleration = torque. But err.. don't worry about rotation, it's evil.

Uhh... I think I'll stick to degrees for rotation.

Hey,

I have some code for bouncing. It works well most of the time but there are some issues at times. Does this look good?

if(m_position.y+m_height >= paddle->GetY() && m_position.y <= paddle->GetY() + paddle->GetHeight() && m_position.x+m_width/2 > paddle->GetX() && m_position.x+m_width/2 < paddle->GetX() + paddle->GetWidth())
	{
		m_velocity.x += paddle->GetMoveX()*(0.25);
		m_velocity.y *= (-1);
	}
	else if(m_position.x+m_width >= paddle->GetX() && m_position.x <= paddle->GetX() + paddle->GetWidth() && m_position.y+m_height/2 > paddle->GetY() && m_position.y+m_height/2 < paddle->GetY() + paddle->GetWidth())
	{
		m_velocity.x *= (-1);
		m_velocity.y -= paddle->GetSpeed()*(0.15);
	}

The code's in C++, and the scope is within the ball class. So things like m_position and m_width refer to the ball, and paddle->GetX() and paddle->GetWidth() refer to the paddle. if you'd like me to give it in more basic pseudo code let me know.

Where and what are the issues? Do they occur at the 'corners and sides' of the paddle, or at the flat, upwards pointing, part? What exactly doesn't seem right when you test?

Wthe ball hits the side of the paddle, it ussualy just goes through the paddle and starts spazing, and then comes out when I move the paddle away. Bouncing on the top side works well, but I have some issues with bottom bouncing as well (when the ball moves below the paddle it starts moving straight until it moves out from under the paddle).

Hi, sorry I didn't reply sooner, been abit busy.

With movement and collision, you have a couple of pitfalls. One is that the speed/velocity of a moving object can exceed the width of objects being tested against, a symptom of this is moving objects 'tunneling through' other objects. This occurs when you use 'static collision testing', which is testing the current position of objects in each iteration as opposed to testing the positions and trajectories of objects. With static tests, two collision tests ( in two frames/iterations ) can report a non-collision even though the trajectory of an object may have passed right through another object.

You can often get away with static tests by increasing the number of iterations and decreasing the maximum velocities involved, this means you can keep the same 'visual speed', but objects are actually moving much less between frames and being collision-tested much more frequently.

Another specific problem with the bounce method you're using is that the ball can be collision-tested as being below paddle.top( ), your code will flip the velocity of the ball; in the next frame, the ball might not escape the collision between paddle.top( ), meaning the ball trajectory gets flipped again, and again, and so on. The ball would indeed 'spaz about' in that case, the ball never actually escapes the top of the paddle.

Two viable fixes:

if(m_position.y+m_height >= paddle->GetY() && m_position.y <= paddle->GetY() + paddle->GetHeight() && m_position.x+m_width/2 > paddle->GetX() && m_position.x+m_width/2 < paddle->GetX() + paddle->GetWidth())
	{
		m_velocity.x += paddle->GetMoveX()*(0.25);
		m_velocity.y *= (-1);
		m_position.y -= [a small number];
	}

This assumes that y=0 is the top of the screen, effect is slightly displacing ( separating ) the ball position from the collision, so that the ball can start moving away without getting stuck in this test. Another solution:

if(m_position.y+m_height >= paddle->GetY() && m_position.y <= paddle->GetY() + paddle->GetHeight() && m_position.x+m_width/2 > paddle->GetX() && m_position.x+m_width/2 < paddle->GetX() + paddle->GetWidth())
	{
		m_velocity.x += paddle->GetMoveX()*(0.25);
		m_velocity.y = fabs( m_velocity.y ) * -1;
	}

( again assuming that negative velocity in Y goes upwards, if not the case, remove the *-1 ). Need to #include <cmath> to get fabs, and fabs just takes the absolute of a floating point number ( i.e. without the sign ). This way, you can always push the ball 'upwards'.

I said two viable solutions.. there's actually three, the last is to use vector math to calculate the reflection against the surface based on the normal of the surface.. equation for which is something like:

velocity2 = ( 2 * surface_normal * surface_normal.dot( velocity1 ) ) - velocity1;

( not tested )

Based on a quick test in something I've got running ATM, that last bit of code I posted:

velocity2 = ( 2 * surface_normal * surface_normal.dot( velocity1 ) ) - velocity1;

Should probably be:

velocity2 = velocity1 - ( 2 * surface_normal * surface_normal.dot( velocity1 ) );

!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.