dcsimg
A Flash Developer Resource Site

Results 1 to 20 of 20

Thread: Billiard Ball-like angle calculations

  1. #1
    Member
    Join Date
    Dec 2009
    Posts
    50

    Billiard Ball-like 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 circle2xSpd-circle1xSpd
        ySpdDif_orig 
    circle2ySpd-circle1ySpd
        xdif_orig 
    circle2.x-circle1.x
        ydif_orig 
    circle2.y-circle1.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...

  2. #2
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    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 functions--that sort of stuff makes determining the state messy. also, DegreesToRadians does nothing--I'm assuming you pasted incorrectly.

    my suggestion is to let go of the trigonometric approach and switch to a vector-based solution. it's more intuitive, more computationally efficient and less error prone. for some reason certain people do not welcome this suggestion--if you're not one of those people, I'm happy to help you out with switching.

  3. #3
    Member
    Join Date
    Dec 2009
    Posts
    50
    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 round-about 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; 05-23-2010 at 08:48 AM.

  4. #4
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    Quote Originally Posted by Multihunter View Post
    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.

  5. #5
    Member
    Join Date
    Dec 2009
    Posts
    50
    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.

  6. #6
    Member
    Join Date
    Dec 2009
    Posts
    50
    WAIT A SECOND! Are you using the dot product to calculate where it would be if it collided between frames?

  7. #7
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    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 1-dimensional universe--1 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 impulse--a 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 1-dimensional 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; 05-24-2010 at 02:12 PM.

  8. #8
    Member
    Join Date
    Dec 2009
    Posts
    50
    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.

  9. #9
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    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.

  10. #10
    Member
    Join Date
    Dec 2009
    Posts
    50
    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.dotdv.times( -) ) / cn.dotcn.timesp.mass ) );
    p.v.plusEqualscn.timesimpulse 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; 05-25-2010 at 08:33 AM.

  11. #11
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    you're looking at the wrong resolve function--that 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.circle2.x;
       var 
    dy:Number circle1.circle2.y;

       var 
    length:Number Math.sqrtdx dx dy dy );
       
    dx /= length;
       
    dy /= length;

       var 
    dvx:Number circle1xSpd circle2xSpd;
       var 
    dvy:Number circle1ySpd circle2ySpd;

       var 
    impulse:Number = -* ( dx dvx dy dvy );
       
    impulse /= ( mass1 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; 05-27-2010 at 06:30 PM.

  12. #12
    Member
    Join Date
    Dec 2009
    Posts
    50
    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)

  13. #13
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    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 1--but 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 that--that 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?
    Yes--it was an error as I wasn't able to test anything. Sorry!

    I've corrected the post to reflect these issues.

  14. #14
    Member
    Join Date
    Dec 2009
    Posts
    50
    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; 05-28-2010 at 03:50 AM.

  15. #15
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    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 reply--what do you mean you can't see where i use the dot product?

  16. #16
    Member
    Join Date
    Dec 2009
    Posts
    50
    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 m1v1-m2v2.

    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; 05-28-2010 at 09:54 AM. Reason: Tried to be more clear... maybe it has failed...

  17. #17
    Member
    Join Date
    Dec 2009
    Posts
    50
    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.x-circle2.x) / (circle1.y-circle2.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 = (circle1ySpd-circle2ySpd) / (circle1xSpd-circle2xSpd/*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; 05-30-2010 at 02:49 AM.

  18. #18
    Member
    Join Date
    Dec 2009
    Posts
    50
    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; 06-03-2010 at 03:10 AM.

  19. #19
    When in doubt ask Eager Beaver's Avatar
    Join Date
    Feb 2007
    Location
    Planet Earth
    Posts
    911
    Here is a good billards game tutorial:
    http://www.bezzmedia.com/swfspot/tut...h8/8_Ball_Pool
    <signature removed by admin>

  20. #20
    Member
    Join Date
    Dec 2009
    Posts
    50
    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
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center