
Billiard Balllike angle calculations
I have this ball, right? And it's bouncing. It bounces around the stage without a care in the world... unless! Wait a minute! There's another ball bouncing around! What will happen when they collide?
...not what they should, that's what...
I have the detection of when they hit working fine (I've watched it time and time again; when the edges touch, they change direction)
I have the momentum fine (assuming no spin)
My problem is in the angles calculations. Here's what I have:
PHP Code:
function twoCircleCollision(circle1,circle2,circle1xSpd,circle1ySpd,circle2xSpd,circle2ySpd):void {
xSpdDif_orig = circle2xSpdcircle1xSpd
ySpdDif_orig = circle2ySpdcircle1ySpd
xdif_orig = circle2.xcircle1.x
ydif_orig = circle2.ycircle1.y
angleOfOrigMove2 = Math.atan2(ySpdDif_orig,xSpdDif_orig)
RadiansToDegrees(angleOfOrigMove2)
angleOfOrigMove2 = Angle_out
angleOfOrigMove1 = Math.atan2(ySpdDif_orig,xSpdDif_orig)
RadiansToDegrees(angleOfOrigMove1)
angleOfOrigMove1 = Angle_out
angleOfCentreToCentreFromHoriz2 = Math.atan2(ydif_orig,xdif_orig)
RadiansToDegrees(angleOfCentreToCentreFromHoriz2)
angleOfCentreToCentreFromHoriz2 = Angle_out
angleOfFinalMove2 = 2*angleOfCentreToCentreFromHoriz2  angleOfOrigMove2
angleOfFinalMove1 = 2*angleOfCentreToCentreFromHoriz2  angleOfOrigMove1
DegreesToRadians(angleOfFinalMove2)
angleOfFinalMove2 = Angle_out
DegreesToRadians(angleOfFinalMove1)
angleOfFinalMove1 = Angle_out
magOfDirect1 = Math.sqrt(circle2xSpd*circle2xSpd+circle2ySpd*circle2ySpd)
magOfDirect2 = Math.sqrt(circle1xSpd*circle1xSpd+circle1ySpd*circle1ySpd)
}
function RadiansToDegrees(TheAngle):void {
if (TheAngle < 0) {
TheAngle += 2*Math.PI
}
TheAngle = TheAngle*(180/Math.PI)
Angle_out = TheAngle
}
function DegreesToRadians(theAngle):void {
theAngle = theAngle*(Math.PI/180)
if (theAngle > Math.PI) {
theAngle = 2*Math.PI
}
theAngle = Angle_out
}
I've tested the RadiansToDegrees and DegreesToRadians functions, so don't blame them. I just included them to show how I've got it set up (You can blame how I've used them, however)
After a lot of searching online the only way I have managed to understand calculating the angle after a collision is with the R = 2W  P formula proposed by Ed Mack (yeah, I'm sure all that projection stuff works, but this should work too... right?)
Anyway... I'm a bit sick of trying to work out what has gone wrong when I don't know if I'm even doing it right; so I'm hoping someone will be able to help me here...

how did you derive this code? there's some weird flow going on there with setting Angle_out instead of returning a value from your conversion functionsthat sort of stuff makes determining the state messy. also, DegreesToRadians does nothingI'm assuming you pasted incorrectly.
my suggestion is to let go of the trigonometric approach and switch to a vectorbased solution. it's more intuitive, more computationally efficient and less error prone. for some reason certain people do not welcome this suggestionif you're not one of those people, I'm happy to help you out with switching.

That weird flow is how my brains logic works.
But... Switching is good with me if it works. Care to explain the vectors, 'cause I can't make head nor tail of what I've found. I do know about vectors; but only from a Year 12 Physics view. (So I know that a vector is made up of both an x value and a y value, and a direction)
What's up with the dot product? I've only managed to see it in a strange manner where they have some property of a variable that I don't know; like 2v.vx
EDIT: I liked this website, but I couldn't understand it once it got into the useful stuff...
http://www.tonypa.pri.ee/vectors/start.html
As for why my code is so weird:
I don't know how to use "return" so I never have.
I thought trigonometry was the way to go 'cause I knew something of it, and... well... it makes sense to me... Vectors always seem a very roundabout way to calculate things. More efficient, I'm sure, but like I said. I can't understand it, and trig has managed to get me this far...
I didn't paste incorrectly... And it does do something... it turns an angle thats in degrees into an angle that's in Flash's weird way of radians (where 181 degrees is a little bit more than PI). EDIT: Maybe you haven't scrolled down in the PHP box?
Last edited by Multihunter; 05232010 at 08:48 AM.

Originally Posted by Multihunter
I didn't paste incorrectly... And it does do something... it turns an angle thats in degrees into an angle that's in Flash's weird way of radians (where 181 degrees is a little bit more than PI). EDIT: Maybe you haven't scrolled down in the PHP box?
It does nothing as is. No value that you're using is being set.
There's nothing magical about vectors, they're just a natural way of expressing things in any dimension. Adding 2 vectors together is the equivalent of "moving" by the amount depicted in each. So let's say you're following a treasure map that tells you to walk 10 paces to the right, then 5 paces up, then another 20 paces right, and another 3 paces up. You can write these directions as the vectors <10,5> and <20,3>. You could walk 10 units to the right and 5 up. Then, from that point, walk 20 units right again and 3 more up. What you've done, however, is waste time because you could have just added them together to find the end point relative to the beginning:
<10,5> + <20,3> = <30,8>.
The dot product of 2 vectors is the sum of the products of each corresponding element. For example, using the vectors above, the dot product would be:
10 * 20 + 5 * 3 = 215
To gain some intuition about this, consider the dot product of a vector, <x,y>, and itself: you have x^2 + y^2, which you should know from trigonometry as the squared length of a right triangle's hypotenuse. With this knowledge you can calculate the length of any vector, v:
SquareRoot( DotProduct( v, v ) )
You can always think of a vector as this hypotenuse, where the x and y components are the 2 perpendicular sides of the triangle.
There's also value in investigating the sign of the dot product of 2 vectors. If the dot product is 0, the vectors are perpendicular to each other. If the dot product is less than zero, then they point in opposite directions; and likewise, if it's greater than zero, they point in the same direction.
So vectors are a very natural way of representing the state of your physical system: position, velocity and acceleration are all vectors.
This is something I wrote a little while ago that does elastic collision response.
http://wonderfl.net/c/8RNL/
See the function "resolve" in the ParticleParticlePair class on line 359. This resolves a collision between 2 circles. It solves for an impulse that gets added to the particles' velocities. It is the magnitude of the integrated reaction force. Take a shot at translating your "twoCircleCollision" method into this form, and we'll take it from there.

I notice that I HAVE copied incorrectly. My apologies, the last part of the function is supposed to be reversed. (Angle_out = theAngle)
Also; I understand everything you just said (Mostly because I knew about adding vectors already). But not your code at all. And none of it gives me any clue as to how it helps, and how it is used to calculate collisions.

WAIT A SECOND! Are you using the dot product to calculate where it would be if it collided between frames?

without understanding it, it still should be easy to get working on your end. it's 6 lines of code to replace that whole function you have. but i'll explain the physics anyway.
it's not used to "calculate collisions." the function applies an impulse that will change each ball's velocity appropriately. to explain how i'm solving for the impulse, let's consider the simpler case of 2 particles colliding in a 1dimensional universe1 is traveling to the right and 2 is traveling to the left.
1 O> <O 2
we know from newton's 3rd law that each force is met with an equal and opposite force. it would be much more complicated to model collision response using forces, so we apply an impulsea quantity used to cause an instantaneous change in velocity:
j = ( ( 1 + e ) * ( m1v1  m2v2 ) ) / ( 1 / m1 + 1 / m2 )
where j is impulse, m is mass and v is velocity. e is what's called the coefficient of restitution, which is a fancy way of saying how bouncy or elastic something is. it ranges from 0  1, 0 being inelastic (like putty) and 1 being perfectly elastic (like a super ball). this looks a little scary, but it's really just giving us a scalar value that represents an exchange in momentum in the given direction (chosen by whether we use m1v1  m2v2 or m2v2  m1v1). the change in velocity from this impulse is then scaled by the inverse of each particle's mass:
v1 += j / m1
v2 = j / m2
let's plug a few values in to see if this makes sense. first, let's say the mass of each particle is 1 and both particles are traveling at 10 meters per second (assuming perfect elasticity):
e = 1
v1 = 10
m1 = 1
v2 = 10
m2 = 1
j = ( ( 1 + e ) * ( 10 * 1 ( 10 * 1 ) ) ) / ( 1 + 1 )
j = ( 2 * 20 ) / 2 = 20
v1 += 20 / 1 = 10
v2 = 20 / 1 = 10
we can see that, as expected v1 and v2 have completely flipped around and 1 is now traveling back to the left at 10 meters per second and 2 is traveling back to the right at 10 meters per second. it's easy to see if we change elasticity to 0, the resulting velocities for both particles will be 0.
that is the 1dimensional version of what my method is doing in 2 dimensions. it's only slightly more complicated in 2D, though. basically we don't have the nicety of velocity being a scalar and so we have to find relative velocity along the line of contact (contact normal). the change in velocity also points along this normal, but everything else is the same.
hope that helps
Last edited by newblack; 05242010 at 02:12 PM.

That's a useful formula, it does help, but it doesn't explain how your 6 lines of coding works.
Sorry I'm not understanding; I shouldn't expect you to explain it all, I'm sure I would be able to get it given enough time researching it on the internet.
As a side note; I have made my trig method work. The WALLS angle is PERPENDICULAR to the angle between the two circles.

it explains line by line how it works and the physics behind it. if you don't understand something, you'll have to ask something specific about it.

So what you have in the "resolve" function is:
PHP Code:
var cn:Vec2D = w.normal;
var dv:Vec2D = p.v;
var impulse:Number = cn.dot( dv.times( 2 ) ) / cn.dot( cn.times( 1 / p.mass ) );
p.v.plusEquals( cn.times( impulse / p.mass ) );
EDIT: What does it actually resolve, and what's the output?
What is "w.medium", and how is it calculated?
When is this function called?
How does it tell it which direction it needs to go?
Does your Vec2D class make it so that both the x and y are calculated using these formulae and then each stored as a property of the variables?
EDIT2: Damn you, time zones, making these awkward timings...
Last edited by Multihunter; 05252010 at 08:33 AM.

you're looking at the wrong resolve functionthat handles collision between a particle and a wall. where i link to that, i say line 359, check that function instead.
it sounds like you're having more trouble with the programmatic end of things. every bit of that algorithm is either standard floating point mathematical operations or can be found elsewhere in the application code.
but anyway, i think you probably just need me to put it in the form of your original algorithm:
PHP Code:
function twoCircleCollision( circle1:DisplayObject, circle2:DisplayObject, circle1xSpd:Number, circle1ySpd:Number, circle2xSpd:Number, circle2ySpd:Number ) : void {
var dx:Number = circle1.x  circle2.x; var dy:Number = circle1.y  circle2.y;
var length:Number = Math.sqrt( dx * dx + dy * dy ); dx /= length; dy /= length;
var dvx:Number = circle1xSpd  circle2xSpd; var dvy:Number = circle1ySpd  circle2ySpd;
var impulse:Number = 2 * ( dx * dvx + dy * dvy ); impulse /= ( 1 / mass1 + 1 / mass2 ); //you need to add these mass values
//these are your new velocities var newCircle1xSpd:Number = circle1xSpd + dx * ( impulse / mass1 ); var newCircle1ySpd:Number = circle1ySpd + dy * ( impulse / mass1 );
var newCircle2xSpd:Number = circle2xSpd  dx * ( impulse / mass2 ); var newCircle2ySpd:Number = circle2ySpd  dy * ( impulse / mass2 );
}
obviously, i don't have your application and i have no idea if there are errors in this or not, but it should be right.
Last edited by newblack; 05272010 at 06:30 PM.

Ok, I now have a much better understand of where this is all coming from.
Thank you.
Just... I still can't quite figure out what you've done there...
When you normalised dx and dy, you made it so that the "new" length would be equal to 1?
So... why do you have it multiplying the sum of the inverse masses?
And why do you have newCircle1xSpd = circle1xSpd  dx*(impulse/mass1)? Shouldn't it be plus? As per your v1 += j / m1?
But, yeah, I see where it is all going now, which is awesome, thank you. (I also should have written it out on a piece of paper sooner, too)

When you normalised dx and dy, you made it so that the "new" length would be equal to 1?
yes, the normalization makes the vector's length 1but it still points in the same direction: from circle 1's center to circle 2's.
So... why do you have it multiplying the sum of the inverse masses?
I have no idea why I'm doing thatthat value will always be 1 and so it's a pointless calculation. I'll have to look through the rest of the code in the link I posted and see how I muffed that up!
And why do you have newCircle1xSpd = circle1xSpd  dx*(impulse/mass1)? Shouldn't it be plus? As per your v1 += j / m1?
Yesit was an error as I wasn't able to test anything. Sorry!
I've corrected the post to reflect these issues.

Ok, nearly there (I think).
I worked out that according to that you had there;
Momentum of Circle1  Momentum of Circle2 = dx*dvx + dy*dvy
How does that work?
EDIT2: Maybe that's the dot product? Even so... how does that work?
I also notice that dx and dy don't change... so wouldn't the gradient of the path also not change?
EDIT: I can't see where you use a dot product, either...
Last edited by Multihunter; 05282010 at 03:50 AM.

it is the dot product of the collision normal and the balls' relative velocities. it gives us the signed magnitude of the projection of the relative velocities onto the normal (since the normal has a length of 1).
i'm not exactly following the rest of your replywhat do you mean you can't see where i use the dot product?

Well that last bit was edited in before the "earlier" edit, hence the 2 next to it to indicate it came later.
If you look at the original formula you gave for impulse; j = ( ( 1 + e ) * ( m1v1  m2v2 ) ) / ( 1 / m1 + 1 / m2 )
and the one you used in the code; (2 * ( dx * dvx + dy * dvy ))/( 1 / mass1 + 1 / mass2 )
Assuming that e = 1, and since the dividing by the inverse masses is the same, that would mean that dx*dvx +dy*dvy would have to equal m1v1m2v2.
I want to know how you managed to come up with dx*dvx + dy*dvy...
And I just realised what was confusing me about the dx and dy; because they were in the final velocity calculation, I confused them with the velocities of the circles.
Which leads me to my next question;
Why does the direction between the circles give the direction of each circle?
EDIT: My real problem is (I think), as suggested in the title, and has been for a while, where are you getting the new angle from? And how is it applied?
I get that you normalise to get the original "angles" and the impulse to determine how fast, but how is it that you can get a new "angle" (I use quotation marks so that it's clear that it's not actually an angle, more of a gradient of the path)
EDIT2: Also, I may be clearer in the morning, I have been staying up til 11pm (and getting up at 5:30am) every night this week trying to figure this stuff out. I probably would do better with more rest. But I feel I'm so close...
EDIT3: I was actually online at the same time as you, but I don't think you expected a response. I'll be on pretty much all of my tomorrow. So if you post anything while I'm awake, I will know, and respond as fast as I can.
Last edited by Multihunter; 05282010 at 09:54 AM.
Reason: Tried to be more clear... maybe it has failed...

Ok. We did a lot on graphs last year in Maths, so I decided to try once again to work it out with gradients, see if it looked like what the vectors were and see if I could link them or come up with another method. ('cause, again, I understood what I was doing with gradients)
They seem to be awfully similar to what you are trying to get me to understand with these vectors.
EDIT: Just to let you know that by "psuedo wall", I mean the instantaneous imaginary wall that exists between to colliding circles such that the reflected angle of the ball hitting it is the same as if it were hitting an actual wall at these particular angles.
I ended up working out that the gradient of the reflected balls path is reflected on the graph along the y = (pseudo wall's gradient)x.
So, where the pseudo wall's gradient was 1 (or at 45 degrees), then the xSpeed would become the ySpeed for the ball in question (and vice versa).
So you replaced the x value with the y value. (So if the walls gradient was 2, and the balls path's gradient was 1, the reflected balls gradient would be worked out by (2x)=1(y/2) => y = 2*2x = > y = 4x, so the gradient of the reflected balls path should be 4)
This is what I got for my code using this idea (I run it twice, swapping which one is circle1, and circle2):
PHP Code:
function twoCircleCollision(circle1,circle2,circle1xSpd,circle1ySpd,circle2xSpd,circle2ySpd):Number {
mag = circle2xSpd*circle2xSpd + circle2ySpd*circle2ySpd /*since they swap momentums,
and I am currently not concerned with mass, I used the magnitude of circle2 and apply it to circle1.
Note: I know it's actually the magnitude squared, but if I square rooted it now I would just have to square it again
anyway later, so I kept it as the squared value*/
grad1 = ( (circle1.xcircle2.x) / (circle1.ycircle2.y) ) /*gradient of the line between
them multiplied by 1 and inverted to give the gradient of the perpendicular line I call the pseudo wall*/
grad2 = (circle1ySpdcircle2ySpd) / (circle1xSpdcircle2xSpd) /*circle1's relative
velocities to circle2 are used to make grad2, the gradient of the original path of circle1*/
coE = (grad1*grad1) / grad2 //the coefficient of x for the new path of circle1
NewXspeed = Math.sqrt( mag / (1+coE*coE) ) /*Outside the function I also record
coE, and to get the Yspeed for the circle, I multiply the NewXspeed by coE*/
return NewXspeed
}
I know. I'm crazy.
I think I'm missing a negative and an inverse in there, or vice versa, 'cause usually using that code they will bounce off at right angles to the direction I would have expected...
Yeah... if you can follow that you can tell me if I've gone completely the other way... (btw, I suggest using paper and an example to check it. I used pseudo walls: x = 2, y = 1. And the circle1's: x = 1, y = 2)
EDIT: At this point I would like to point out that if anyone else has any comments on my lack of understanding, I'm sure that newblack wouldn't mind you adding it (Right?). Who knows, it might even help me.
EDIT2: I just want to let you know that the code you gave me is working 100% with the proper momentum. Now I just want to know WHY.
Last edited by Multihunter; 05302010 at 02:49 AM.

Thank you newblack, you helped me so much. I didn't realise that it was so simple; dx was the proportion of the xvelocity that takes part in the collision! My problem was that I over complicated the code you gave me. I kept trying to link it with the website that I posted earlier; until today. I realised that it had nothing to do with projections and dot products...
I'm sure it was obvious to you, and that's why you didn't explain it... but it confused me a lot. It's funny, last year I tried graphing the different resultant xspeeds based on the angle (given an input of 1). I couldn't think how to combine that with pythagoras. But this is how you do it.
Just 1 thing that bugs me still... what happened to the masses in the momentum part of the impulse equation?
EDIT: Oh yes. Please ignore my previous post as ramblings of a madman.
EDIT2: I think you told me equation incorrectly to begin with; according to this website, you only use the mass(es) once.
http://www.euclideanspace.com/physic...ulse/index.htm
Last edited by Multihunter; 06032010 at 03:10 AM.

When in doubt ask
<signature removed by admin>

Nice try, Eager Beaver, but;
That ones collision detection is no better than a simple: "If the distance between them will be the averaged(?) radius next frame, then they have collided".
They also, oddly, have also decided that: "at exactly halfway between the frames they have collided"
The collision calculation is actually exactly the same as the one newblack gave me, except that it doesn't take into account masses. (They just named the variables differently)
Also, @newblack; I see the dot product now! Aren't you proud?
I've also figured out the calculations for an exact collision from circle to a rectangle (I think)!
Posting Permissions
 You may not post new threads
 You may not post replies
 You may not post attachments
 You may not edit your posts

Forum Rules

Click Here to Expand Forum to Full Width
