2d ball deflection, mini golf game

Started by
5 comments, last by frob 18 years ago
Hi, I'm having problems getting the ball to deflect off the walls in a 2D Mini Golf game, in the correct manner. The ball will come off the walls but it won't go in the right direction. Basically I'm sending the current angle of the ball to a calculation class, the class calculates a new angle for the ball and returns it to the main function which controls the balls movement. The problem I'm having though is that I can't work out the equation to alter the angle correctly. I figured I have 8 states of deflection. I.e when the ball hits with the top left, top right, bottom left, bottom right, top, left, bottom and right. As I have 8 different types of wall the ball can collide with. I figured the horizontal and vertical walls would be easy enough to deflect off, so I started with other walls that are not quite at 45degrees, more at 30degrees. My thoughts were that I knew that the deflection of an object is basically 180 -the angle the ball hits the wall. I am working in Radians, so i substitute 180 for 3.14159, but then I notice that the Radians work from -3.14159 to 3.14159, nevertheless I figure a couple of If statements will work around this. So I've got my angle the wall that will hit the ball at the top left corner of the bounding box. And here's my code void CCalculation::SetNewHeading3(){ int done =0; double angCalc=0; if ((angle >= -3.1416 && angle <=-2.03444) && done==0){ done = 1; angCalc = angle + 2.03444; angle = angCalc - 1.10715; } if (( angle <=3.1416 && angle >=2.03444) && done==0){ done = 1; angCalc = angle - 1.10715; angle = angCalc - 2.03444; } done = 0; } This is essentially to deflect the ball off only one wall, I keep the value 3.1416 so as to ensure the full PI value is recognised. With the first If statement the ball bounces off almost perfectly, but its not quite right. And the second If statement deflects the ball straight back the way it had came. Whilst I appreciate that this code is probably quite crude, I could do with some help. Does anyone know of any equations that will make this simpler or easier to do, I'm at my whits end. Thanks

“Be who you are and say what you feel, because those who mind don't matter, and those who matter don't mind.” 
― Bernard M. Baruch

Advertisement
My initial reaction is to point to ODE that handles this sort of thing wonderfully. It will gracefully handle your ball rolling, skidding, slowing down, bouncing, and whatever else you can throw at it.

A simple bounce, with no spin on the ball, no elasticity, or any other funky effects will be a simple reflection: angleOut = -(angleIn). It would be that simple if your surface angle were 0. But since it isn't, you have to include that in your equation, giving ball.angle = surface.angle - ( ball.angle - surface.angle )
which resolves to: ball.angle = 2 * surface.angle - ball.angle

After you do that, you'll want to figure out how far you needed to travel in the pre and post bounce distances for your given time step. If you are having trouble with the simple reflection, you will probably have some serious trouble with it.


Next, a normalization function to convert numbers back to the +/- PI range:

{ if( fabs( angle ) > PI ) { return angle - 2*PI * floor((angle + PI) / (2*PI)); return angle;}

Note that you better have the actual full-precision PI when you do this, since using the constant 3.14159 will lead to nasty rounding errors pretty quick.
Thanks for your help, it is very much appreciated.

What you said was kinda along the lines of my thnking too, only I couldn't quite translate it into code.

I have solved the problem, although not using your ideas. Basically with a little luck and little inspiration.

Here's my revised code:

void CCalculation::SetNewHeading3(){
int done =0;
double angCalc=0;

if ((angle >= -3.1416 && angle <=-2.03444) && done==0){
done = 1;
angCalc = -3.14159 - angle;
angle = angCalc - 1.10715;
}
if (( angle <=3.1416 && angle >=1.10715) && done==0){
done = 1;
angCalc = 3.14159 - angle;
angle = angCalc - 2.03444;
}

done = 0;
}

I suddenly realised that when I crossed between the negative and positive values of the Radians that my surface normal changed.
And I was effectively using the wrong surface normals for each deflection, also not realising that I needed to use the PI value -/+ to calculate the angle the ball was hitting the wall.
Plus I was looking at the wrong angles for the ball coming off the wall, I was reading the angle on the other side of the Radian circle, DOH!
Hence my pencil and paper calculations where not coinciding with my program calculations (this can be very frustrating, heh heh).

I understand that I will have problems with my shortened version of PI. But I noticed you declared it in your code snippet, is there a PI keyword by any chance. I am using <math.h> library file to calculate my angles and I know its not used by this. Is it used by any other header files?

Thanks again for your reply

“Be who you are and say what you feel, because those who mind don't matter, and those who matter don't mind.” 
― Bernard M. Baruch

No, there is no PI keyword in either of the C or C++ languages.

Many implementations, including Visual C++, have PI constants included somewhere. For Visual C++, define _USE_MATH_DEFINES then include <math.h> or <cmath>

This gives you M_PI, M_PI_2 (pi/2), M_1_PI (1/pi), and a few others. These could be substituted in the code I gave, although they are somewhat less readable. There isn't a 2*PI because the compiler will preprocess that one. These definitions are (probably) the full precision supported by the compiler.

Baring that, you can make your own PI constant variable. You might use 2*asin(1), or an asm instruction like fldpi, or some other method that will completely fill out your number.
What's so special about the ranges -3.1416 .. -2.03444 and 1.10715 .. 3.1416 ?

Why aren't you making a general purpose bounce function? Are you intending to hard-code your entire golf course in terms of sines, cosines, and angles as numeric constants in your source?

Just wondering.
The values 3.1416 value is just for the If statement, so the actual PI value is not missed, co s obiviously as you said 3.14159 is not an actual PI value.
So whilst the Radians only go up to +/- PI anything above/below in the If statement will not matter and will not affect the check!

The other two values will be constants. They are basically the angles perpendicular to one of the walls. They will also be used for another of the walls too.

I was planning on creating a specific bounce function, but I was a little unsure about how to go about it, and I had more of an idea of making it work by hard coding it.

Probably once I've got it working properly i'll look into creating that function. Any suggestions of how to achieve it would be cool?


I didn't think there was a PI function, although its always good to ask, and I thought the best way would be to create my own. Although, I hadn't considered doing it the way you suggested. Thanks.

“Be who you are and say what you feel, because those who mind don't matter, and those who matter don't mind.” 
― Bernard M. Baruch

How will your code handle an input angle of 7*PI? Or of 9*PI? or -135*PI?



The reflection formula and angle normalization formula I gave above are both general purpose, and should work nicely even with that type of angle.

Both formulas require a minimum number of math operations, and all optimizing compilers should generate code that won't stall the pipeline. That is not true of your code.


The refletion formula doesn't care which direction they are facing or what way you consider 'forward' or 'back', nor does it care if you feed it angles of 9*PI and -135*PI for your ball and surface angles.


In other words, it is much better to solve the general-purpose math first, so you don't have to rely on luck to find an (incorrect) solution that happens to give you the right result in a small set of situations.

This topic is closed to new replies.

Advertisement