## Ball collisions

General FreeBASIC programming questions.
exige
Posts: 3
Joined: Jul 15, 2007 20:52

### Ball collisions

Hello, I am trying to do a program with bouncing balls that can collide with each other.

The problem is that I don't know how to calculate the collisions in a correct way, so that it would be realistic. If someone could explain it, I would be very happy. I have searched the forum, and found solutions, but I can't understand them, and I don't like having code that I don't understand.

I am also having problem with grabbing one of the set number of balls. The mouse will not get stuck where I click, instead it sticks to the corners when you drag that ball. I can't figure out what's causing it.

If you find any else error or slow/bad code in my program I would be happy to know.

Sorry for my bad English, I come from Sweden. Feel free to correct spelling mistakes as well.

Code: Select all

`' Anders Reinholdsson 2007-07-05option explicit' Declare variablesdim fps, frames,n, n2, balls = 10, radius(balls), colour(balls), mx, mx2, my, my2, mb, grabdim as double x(balls), y(balls), vy(balls), vx(balls), time1, time2, g = .01, temprandomize timerfor n = 0 to balls - 1 ' Randomize things    x(n) = 640 * rnd    y(n) = 200 * rnd    vx(n) = 20 * rnd - 10    radius(n) = 10 ' rnd * 10 + 10    colour(n) = rnd * 14 + 1nextscreenres 640,400, 8, 2' Main loopdo while inkey\$ = ""    getmouse mx, my,, mb    screenset 1:cls        print "Version 0.017"    print "FPS:"; fps    print "Frames:"; frames    print "Balls:"; balls        for n = 0 to balls - 1        vy(n) += g ' Changes in y-way        vy(n) = .999 * vy(n) ' To simulate air-friction        y(n) += vy(n)        if y(n) >= 400 - radius(n) then            vy(n) = -.9 * vy(n)            y(n) = 400 - radius(n)        end if        if y(n) <= 0 + radius(n) then            vy(n) = -.9 * vy(n)            y(n) = 0 + radius(n)        end if            if x(n) >= 640 - radius(n) then ' Changes in x-way            vx(n) = .9 * -vx(n)            x(n) = 640 - radius(n)        end if        if x(n) <= 0 + radius(n) then             vx(n) = .9 * -vx(n)            x(n) = 0 + radius(n)        end if        vx(n) = .999 * vx(n) ' To simulate air-friction        x(n) += vx(n)                ' To grab balls        if mb = 1 then            if sqr((x(n)-mx)^2+(y(n)-my)^2) < radius(n) then                grab = n                mx2 = mx - x(n)                my2 = my - y(n)            end if        else            grab = -1        end if        if grab <> -1 then            x(grab) = mx - mx2            y(grab) = my - my2            vx(grab) = 0            vy(grab) = 0        end if                ' Detect collisions        for n2 = 0 to balls - 1            if n <> n2 and sqr((x(n)-x(n2))^2+(y(n)-y(n2))^2) < radius(n)+radius(n2) then                temp = vx(n)                vx(n) = vx(n2)                vx(n2) = temp                temp = vy(n)                vy(n) = vy(n2)                vy(n2) = temp            end if        next                circle (x(n), y(n)),radius(n),colour(n),,,,F    next    if timer - time2 > 1 then ' FPS counter        fps = 1/(timer-time1)        time2 = timer    end if    time1 = timer        flip    frames += 1    sleep 9 ' To get about 100 fpsloop`

Thanks for any help! :)
Merick
Posts: 1038
Joined: May 28, 2007 1:52
I haven't really tested it with freebasic, but this function was edited from one I used with another language and it should work for your collisions:

Code: Select all

`function Circle_Collision(byval obj1x as integer,_                          byval obj1y as integer,_                          byval obj1radius as integer,_                          byval obj2x as integer,_                          byval obj2y as integer,_                          byval obj2radius as integer) as integer    var distanceSquared = (obj2x - obj1x) * (obj2x - obj1x) + (obj2y - obj1y) * (obj2y - obj1y)    var radiusSquared = (obj2radius + obj1radius) * (obj2radius + obj1radius)    if (distanceSquared < radiusSquared) then        return true    else        return false    endifend function`

obj1x, obj1y, and obj1radius are the x,y position and the radius of the first ball, obj2x, obj2y, and obj2radius are the x,y position and radius of the ball you want to check it against.
h4tt3n
Posts: 659
Joined: Oct 22, 2005 21:12
Location: Denmark
@ Merick,

I think what exige means is that he's having trouble figuring out how the balls should interact on collision, not the actual collision detection itself (which is fairly straightforward).

@ exige,

I know for sure that there is a plane and simple tutorial about this subject on the net somewhere. I'll take a look for it and post a link if I find anything.
Richard
Posts: 2766
Joined: Jan 15, 2007 20:44
Location: Australia
You have two laws of physics, conservation of energy and conservation of momentum. The total energy after collision is equal to the total energy before collision. The total momentum after collision is equal to the total momentum before collision.
Momentum = mass * velocity
Kinetic energy = 0.5 * mass * velocity * velocity
Solve the simultaneous equations which will probably have a quadratic equation. Since velocity is a vector you need to consider these conservation laws in both the x and y directions.
This is a particularly difficult problem if the balls do not hit head-on. Also if the balls roll up to each other or spin as a result of an off-centre collision it is harder still. Rolling or spinning are conserved as angular energy and angular momentum.
Look for the sticky link at the top of Libraries on this forum because you might be better using the ODE library http://ode.org/ Or Newton http://www.physicsengine.com/

Here is some code to handle the general case, in C or Fortran.
http://www.plasmaphysics.org.uk/programs/coll2d_cpp.htm
http://www.plasmaphysics.org.uk/collision2d.htm
Here is an UNtested translation to FB from Fortran. No warranty.

Code: Select all

`' ******************************************************************************' This program is a 'remote' 2D-collision detector for two balls on linear' trajectories and returns, if applicable, the location of the collision for' both balls as well as the new velocity vectors (assuming a fully elastic' collision).' All variables apart from 'ErrorCode' are of Double Precision Floating Point type.' In 'free' mode no positions but only the initial velocities and an impact' angle are required.' All variables apart from 'mode' and 'ErrorCode' are of Double Precision' Floating Point type.'' The Parameters are:'' mode  (character*4) (if='free' alpha must be supplied; otherwise arbitrary)' alpha (impact angle) only required in mode='free';' should be between -PI/2 and PI/2 (0 = head-on collision))' m1    (mass of ball 1)' m2    (mass of ball 2)' r1    (radius of ball 1)       not needed for 'free' mode' r2    (radius of ball 2)                "' * x1    (x-coordinate of ball 1)          "' * y1    (y-coordinate of ball 1)          "' * x2    (x-coordinate of ball 2)          "' * y2    (y-coordinate of ball 2)          "' * vx1   (velocity x-component of ball 1)' * vy1   (velocity y-component of ball 1)' * vx2   (velocity x-component of ball 2)' * vy2   (velocity y-component of ball 2)' * ErrorCode (Integer*2) (0: no error' 1: balls do not collide' 2: initial positions impossible (balls overlap)'' In the calling program, the arguments corresponding to the parameters' with an asterisk (*) will be updated (the positions and velocities however' only if 'ErrorCode'=0).' All variables should have the same data types in the calling program' and all should be initialized before calling the subroutine.'' This program is free to use for everybody. However, you use it at your own' risk and I do not accept any liability resulting from incorrect behaviour.' I have tested the program for numerous cases and I could not see anything' wrong with it but I can not guarantee that it is bug-free under any' circumstances.' I do in general not recommend the use of single precision because for' iterative computations the rounding errors can accumulate and render the' result useless if there are not enough decimal places; however for uncritical' applications or if speed is of paramount importance, you can change the' program to single precision by changing the variable declaration to REAL*4' and remove the 'D' in front of the mathematical function names.''' I would appreciate if you could report any problems to me' (for contact details see  http://www.plasmaphysics.org.uk/feedback.htm ).'' Thomas Smid, January  2004' December 2005 (corrected faulty collision detection;' a few minor changes to improve speed;' added simplified code without collision detection)' **********************************************************************************Sub collision2D(_    Byref mode As String,_    Byref alpha As Double,_    Byref m1 As Double,_    Byref m2 As Double,_    Byref r1 As Double,_    Byref r2 As Double,_    Byref x1 As Double,_    Byref y1 As Double,_    Byref x2 As Double,_    Byref y2 As Double,_    Byref vx1 As Double,_    Byref vy1 As Double,_    Byref vx2 As Double,_    Byref vy2 As Double,_    Byref ErrorCode As Integer)        ' **** initialize some additional variables ****    Dim As Double PI2, R12, M21, X21, Y21, VX21, VY21, GAMMAV, D    Dim As Double GAMMAXY, DGAMMA, DDGAMMA, DR, DC, SQS, T, A, DVX2    PI2 = 2.0D0*Atn(-1.0D0)    ErrorCode = 0    R12 = r1+r2    M21 = m2/m1    X21 = x2-x1    Y21 = y2-y1    VX21 = vx2-vx1    VY21 = vy2-vy1        ' **** return if relative velocity =0  ****    If (vx21  =  0  And  vy21  =  0) Then        ErrorCode = 1        Exit Sub    End If         ' *** calculate relative velocity angle    GAMMAV = Atan2(-vy21,-vx21)        ' ******** this block only if initial positions are given ***        If (mode  <>  "free") Then                D = Sqr(x21*x21+y21*y21)                ' **** return if distance between balls smaller than sum of radii ***        If (d  <  r12) Then            ErrorCode = 2            Exit Sub        End If                 ' **** calculate relative position angle and normalized impact parameter ***        GAMMAXY = Atan2(y21,x21)        DGAMMA = gammaxy-gammav        If (dgamma  >  pi2) Then            DGAMMA = dgamma-pi2        Else            If (dgamma  <  -pi2) Then                DGAMMA = dgamma+pi2            End If         End If         DR = d*Sin(dgamma)/r12                ' **** return old positions and velocities if balls do not collide ***        If ((dgamma > pi2/4.0D0 And ddgamma < 0.75D0*pi2 ) Or Abs(dr) > 1.0D0 ) Then            ErrorCode = 1            Exit Sub        End If         ' **** calculate impact angle if balls do collide ***        ALPHA = Asin(dr)                ' **** calculate time to collision ***        DC = d*Cos(dgamma)        If (dc  >  0) Then            SQS = 1.0D0        Else            SQS = -1.0D0        End If         T = (dc-sqs*r12*Sqr(1-dr*dr))/Sqr(vx21*vx21+vy21*vy21)                ' **** update positions ***        X1 = x1+vx1*t        Y1 = y1+vy1*t        X2 = x2+vx2*t        Y2 = y2+vy2*t            End If         ' ******** END 'this block only if initial positions are given' ***        ' ***  update velocities ***        A = Tan(gammav+alpha)        DVX2 = -2*(vx21+a*vy21)/((1+a*a)*(1+m21))        VX2 = vx2+dvx2    VY2 = vy2+a*dvx2    VX1 = vx1-m21*dvx2    VY1 = vy1-a*m21*dvx2    End Sub ' ******************************************************************************' Simplified Version' The advantage of the 'remote' collision detection in the program above is' that one does not have to continuously track the balls to detect a collision.' The program needs only to be called once for any two balls unless their' velocity changes. However, if somebody wants to use a separate collision' detection routine for whatever reason, below is a simplified version of the' code which just calculates the new velocities, assuming that the balls are' already touching and approaching each other (these two conditions are' important as otherwise the results will be incorrect)' ****************************************************************************Sub collision2Ds(_    Byref m1 As Double,_    Byref m2 As Double,_    Byref x1 As Double,_    Byref y1 As Double,_    Byref x2 As Double,_    Byref y2 As Double,_    Byref vx1 As Double,_    Byref vy1 As Double,_    Byref vx2 As Double,_    Byref vy2 As Double)        Dim As Double M21, X21, Y21, VX21, VY21, FY21, Sign, A, DVX2        M21 = m2/m1    X21 = x2-x1    Y21 = y2-y1    VX21 = vx2-vx1    VY21 = vy2-vy1        ' *** I have inserted the following statements to avoid a zero divide;    ' *** (for single precision calculations,    ' ***         1.0D-12 should be replaced by a larger value). **********        FY21 = 1.0D-12*Abs(y21)    If ( Abs(x21)  <  fy21 ) Then        If (x21  <  0) Then            SIGN = -1.0D0        Else            SIGN = 1.0D0        End If         X21 = fy21*sign    End If         ' ***  update velocities ***        A = y21/x21        DVX2 = -2*(vx21+a*vy21)/((1+a*a)*(1+m21))        VX2 = vx2+dvx2    VY2 = vy2+a*dvx2    VX1 = vx1-m21*dvx2    VY1 = vy1-a*m21*dvx2    End Sub `
exige
Posts: 3
Joined: Jul 15, 2007 20:52

h4tt3n: You are right. I am very interested if you find that tutorial.

Richard: Yes, I know about the laws. But my real problem is to make the code, and perhaps to make the math general (being able to solve ball collisions for different angels, speeds and masses). Tomorrow I will take a look in my physics books. I am interested in doing the physics calculations on my own, so I don't want to use any external library. The goal with this program was not to make it very advanced, instead simple but still realistic. So therefor I will ignore friction on the balls, as well as rotations.

Anyone figured out my problem with grabbing one ball?
Lachie Dazdarian
Posts: 2230
Joined: May 31, 2005 9:59
Location: Croatia
Contact:
I'm not sure if you are aware of this tutorial:

http://www.petesqbsite.com/sections/express/issue21/index.html#bounce

It contains this demo of ball to ball collison:

Code: Select all

`'Snooker balls bouncing like they should be. ;*)'Relsoft 2003'http://rel.betterwebber.com'thanks to: Hugo Elias for writting that lil tute. Very *vague* I mght add. ;*)''Notes: No friction is implemented as my daughter is... well, I have to cook'       her breakfast. ;*)'Ported to FB June 20, 2006'Keys:'LEFT and RIGHT arrows = change direction'SPACE = shoot'ESC = QUITDEFINT A-ZTYPE ballType    x       AS SINGLE               'the x coord    y       AS SINGLE    xv      AS SINGLE    yv      AS SINGLE    speed   AS SINGLE               '???    mass    AS SINGLE               'the mass    angle   AS INTEGER              'angle of directionEND TYPEDECLARE SUB Normalize (nx!, ny!, X1!, Y1!, X2!, Y2!)DECLARE FUNCTION Collide% (Ball() AS balltype)DECLARE FUNCTION Dot! (ax!, ay!, bx!, by!)CONST FALSE = 0, TRUE = NOT FALSECONST PI = 3.141593                 'wanna eat pie?CONST FRICTION = .001DIM balls(1) AS ballType'Initialise ballsballs(0).x = 200balls(0).y = 170balls(0).xv = 0balls(0).yv = 0balls(0).speed = 2.6balls(0).mass = 1.5balls(0).angle = 218balls(1).x = 100balls(1).y = 80balls(1).xv = 0balls(1).yv = 0balls(1).speed = 0balls(1).mass = 2.5balls(1).angle = 30CLSSCREEN 13,8,2screenset 1,0'Target the ballDO               LINE (0, 0)-(319, 199), 0, BF       'cls        FOR i% = 0 TO 1                     'draw em ballz            x = balls(i%).x            y = balls(i%).y            CIRCLE (x, y), 10, i% + 5            PAINT (x, y), i% + 5        NEXT i%        tx% = COS(balls(0).angle * PI / 180) * 50       'Line of target        ty% = SIN(balls(0).angle * PI / 180) * 50        LINE (balls(0).x, balls(0).y)-(balls(0).x + tx%, balls(0).y + ty%), 15, , &HFAFA                screensync        screencopy                IF MULTIKEY(&h4B) then balls(0).angle = (balls(0).angle - 1) MOD 360        IF MULTIKEY(&h4D) then balls(0).angle = balls(0).angle + 1 MOD 360        LOOP WHILE NOT MULTIKEY(&h39)    'Set initial ball vectors    balls(0).xv = COS(balls(0).angle * PI / 180) * balls(0).speed    balls(0).yv = SIN(balls(0).angle * PI / 180) * balls(0).speed'Bouncy!!!!dim xva!,xvb!,yva!,yvb!,impulsex!,impulsey!DO    LINE (0, 0)-(319, 199), 0, BF           'cls    FOR i% = 0 TO 1                         'move the balls        balls(i%).x = balls(i%).x + balls(i%).xv        'x move        balls(i%).y = balls(i%).y + balls(i%).yv        'y move        'the next if then else clause checks to see if the balls are        'inside the screen of out of bounds, they bounce        IF balls(i%).x < 10 THEN            balls(i%).xv = -balls(i%).xv        ELSEIF balls(i%).x > 310 THEN            balls(i%).xv = -balls(i%).xv        ELSE        END IF        IF balls(i%).y < 10 THEN            balls(i%).yv = -balls(i%).yv        ELSEIF balls(i%).y > 190 THEN            balls(i%).yv = -balls(i%).yv        ELSE        END IF        balls(i%).xv = balls(i%).xv - balls(i%).xv * FRICTION        balls(i%).yv = balls(i%).yv - balls(i%).yv * FRICTION        x = balls(i%).x        y = balls(i%).y        CIRCLE (x, y), 10, i% + 5       'Draw the balls        PAINT (x, y), i% + 5    NEXT i%    IF Collide(balls()) = -1 THEN            GOSUB calcVectors           'The ball to ball algo            balls(0).xv = xva!          'set new velocities/vectors            balls(0).yv = yva!            balls(1).xv = xvb!            balls(1).yv = yvb!    END IF    screensync    screencopy    LOOP WHILE NOT MULTIKEY(&h1)ENDcalcVectors:    'Notes:    'vectors: Impact,Impulse,    '           balla,ballb,newa,newb    'Points:    p1,p2    'Real Floats: Mass1,Mass2,Impactspeed    'Formula:    '1. Impact= balla-ballb         'vector subtaction    '2. impulse = Normalize(p1,p2)  'see normalize sub    '3. impactspeed = Dot!(impact,impulse)    '4. newimpulse=impulse*impactspeed*mass1*mass2    '5. newa=balla+newimpulse/mass1    '6. newb=ballb-newimpulse/mass2    'PS the divide by 2 is for the frictionless model. ;*)    impactx! = balls(1).xv - balls(0).xv    impacty! = balls(1).yv - balls(0).yv    Normalize impulsex!, impulsey!, balls(0).x, balls(0).y, balls(1).x, balls(1).y    impactSpeed! = Dot!(impactx!, impacty!, impulsex!, impulsey!)    impulsex! = impulsex! * impactSpeed! * balls(0).mass * balls(1).mass / 2    impulsey! = impulsey! * impactSpeed! * balls(0).mass * balls(1).mass / 2    xva! = balls(0).xv + impulsex! / balls(0).mass    yva! = balls(0).yv + impulsey! / balls(0).mass    xvb! = balls(1).xv - impulsex! / balls(1).mass    yvb! = balls(1).yv - impulsey! / balls(1).massRETURNFUNCTION Collide (Ball() AS ballType)'returns id the ball collided using the distance formula.'can be optimized a lot!!!    Collide = 0    dx! = Ball(1).x - Ball(0).x    dy! = Ball(1).y - Ball(0).y    dist! = SQR(dx! ^ 2 + dy! ^ 2)    IF dist! <= 20 THEN        Collide = -1    END IFEND FUNCTIONFUNCTION Dot! (ax!, ay!, bx!, by!)'returns the dot product between 2 vectors a and b.    Dot! = (ax! * bx!) + (ay! * by!)END FUNCTIONSUB Normalize (nx!, ny!, X1!, Y1!, X2!, Y2!)'normalizes the components of a vector derived from 2 points (x1,y1) and'(x2,y2)    dx! = X2! - X1!    dy! = Y2! - Y1!    dist! = SQR(dx! ^ 2 + dy! ^ 2)    nx! = dx! / dist!    ny! = dy! / dist!END SUB`

Compiles with -lang qb. You'll have to do the usual changes to compile it with -lang fb (declare all variables, no variable suffixes, etc.).

Personally, this code is all I need in ball to ball collision. Relsoft is God! :P
integer
Posts: 362
Joined: Feb 01, 2007 16:54
Location: usa
commented out: OPTION EXPLICIT
added "AS INTEGER" after the first DIM

results:

Code: Select all

`Command executed:"C:\FreeBASIC\fbc.exe" "C:\FB\bounce1.bas"Compiler output:C:\FB\bounce1.o:fake:(.text+0x43a): undefined reference to `fb_GetMouse@20'Results:Compilation failedSystem:FBIde: 0.4.6fbc:   FreeBASIC Compiler - Version 0.18 (06-28-2007) for win32 (target:win32)OS:    Windows XP (build 2600, Service Pack 2)`
'/

At the moment can't investigate.
cha0s
Posts: 5317
Joined: May 27, 2005 6:42
Location: Illinois
Contact:
Integer: That means you've mismatched compiler and rtlib versions in linked objects.
Basic Coder
Posts: 180
Joined: Aug 02, 2006 23:37
Location: Australia
exige wrote:
from previous post:
"I am also having problem with grabbing one of the set
number of balls. The mouse will not get stuck where I
click, instead it sticks to the corners when you drag
that ball. I can't figure out what's causing it."

Anyone figured out my problem with grabbing one ball?

It seems to work ok for me unless I misunderstand the
problem? If the mouse-held ball is moved passed another
it often swaps balls, perhaps something to do with
the order of the balls in the ball list. I haven't had
time to study your code yet.

One neat feature might be to pick up a ball and when
you release the ball have it retain the velocity
(speed and direction) of the mouse before release?
So you can throw the balls using the mouse?

--
JC
h4tt3n
Posts: 659
Joined: Oct 22, 2005 21:12
Location: Denmark
Lachie Dazdarian wrote:I'm not sure if you are aware of this tutorial:

http://www.petesqbsite.com/sections/express/issue21/index.html#bounce

It contains this demo of ball to ball collison:

Code: Select all

`'Snooker balls bouncing like they should be. ;*)'Relsoft 2003'http://rel.betterwebber.com'thanks to: Hugo Elias for writting that lil tute. Very *vague* I mght add. ;*)''Notes: No friction is implemented as my daughter is... well, I have to cook'       her breakfast. ;*)'Ported to FB June 20, 2006'Keys:'LEFT and RIGHT arrows = change direction'SPACE = shoot'ESC = QUITDEFINT A-ZTYPE ballType    x       AS SINGLE               'the x coord    y       AS SINGLE    xv      AS SINGLE    yv      AS SINGLE    speed   AS SINGLE               '???    mass    AS SINGLE               'the mass    angle   AS INTEGER              'angle of directionEND TYPEDECLARE SUB Normalize (nx!, ny!, X1!, Y1!, X2!, Y2!)DECLARE FUNCTION Collide% (Ball() AS balltype)DECLARE FUNCTION Dot! (ax!, ay!, bx!, by!)CONST FALSE = 0, TRUE = NOT FALSECONST PI = 3.141593                 'wanna eat pie?CONST FRICTION = .001DIM balls(1) AS ballType'Initialise ballsballs(0).x = 200balls(0).y = 170balls(0).xv = 0balls(0).yv = 0balls(0).speed = 2.6balls(0).mass = 1.5balls(0).angle = 218balls(1).x = 100balls(1).y = 80balls(1).xv = 0balls(1).yv = 0balls(1).speed = 0balls(1).mass = 2.5balls(1).angle = 30CLSSCREEN 13,8,2screenset 1,0'Target the ballDO               LINE (0, 0)-(319, 199), 0, BF       'cls        FOR i% = 0 TO 1                     'draw em ballz            x = balls(i%).x            y = balls(i%).y            CIRCLE (x, y), 10, i% + 5            PAINT (x, y), i% + 5        NEXT i%        tx% = COS(balls(0).angle * PI / 180) * 50       'Line of target        ty% = SIN(balls(0).angle * PI / 180) * 50        LINE (balls(0).x, balls(0).y)-(balls(0).x + tx%, balls(0).y + ty%), 15, , &HFAFA                screensync        screencopy                IF MULTIKEY(&h4B) then balls(0).angle = (balls(0).angle - 1) MOD 360        IF MULTIKEY(&h4D) then balls(0).angle = balls(0).angle + 1 MOD 360        LOOP WHILE NOT MULTIKEY(&h39)    'Set initial ball vectors    balls(0).xv = COS(balls(0).angle * PI / 180) * balls(0).speed    balls(0).yv = SIN(balls(0).angle * PI / 180) * balls(0).speed'Bouncy!!!!dim xva!,xvb!,yva!,yvb!,impulsex!,impulsey!DO    LINE (0, 0)-(319, 199), 0, BF           'cls    FOR i% = 0 TO 1                         'move the balls        balls(i%).x = balls(i%).x + balls(i%).xv        'x move        balls(i%).y = balls(i%).y + balls(i%).yv        'y move        'the next if then else clause checks to see if the balls are        'inside the screen of out of bounds, they bounce        IF balls(i%).x < 10 THEN            balls(i%).xv = -balls(i%).xv        ELSEIF balls(i%).x > 310 THEN            balls(i%).xv = -balls(i%).xv        ELSE        END IF        IF balls(i%).y < 10 THEN            balls(i%).yv = -balls(i%).yv        ELSEIF balls(i%).y > 190 THEN            balls(i%).yv = -balls(i%).yv        ELSE        END IF        balls(i%).xv = balls(i%).xv - balls(i%).xv * FRICTION        balls(i%).yv = balls(i%).yv - balls(i%).yv * FRICTION        x = balls(i%).x        y = balls(i%).y        CIRCLE (x, y), 10, i% + 5       'Draw the balls        PAINT (x, y), i% + 5    NEXT i%    IF Collide(balls()) = -1 THEN            GOSUB calcVectors           'The ball to ball algo            balls(0).xv = xva!          'set new velocities/vectors            balls(0).yv = yva!            balls(1).xv = xvb!            balls(1).yv = yvb!    END IF    screensync    screencopy    LOOP WHILE NOT MULTIKEY(&h1)ENDcalcVectors:    'Notes:    'vectors: Impact,Impulse,    '           balla,ballb,newa,newb    'Points:    p1,p2    'Real Floats: Mass1,Mass2,Impactspeed    'Formula:    '1. Impact= balla-ballb         'vector subtaction    '2. impulse = Normalize(p1,p2)  'see normalize sub    '3. impactspeed = Dot!(impact,impulse)    '4. newimpulse=impulse*impactspeed*mass1*mass2    '5. newa=balla+newimpulse/mass1    '6. newb=ballb-newimpulse/mass2    'PS the divide by 2 is for the frictionless model. ;*)    impactx! = balls(1).xv - balls(0).xv    impacty! = balls(1).yv - balls(0).yv    Normalize impulsex!, impulsey!, balls(0).x, balls(0).y, balls(1).x, balls(1).y    impactSpeed! = Dot!(impactx!, impacty!, impulsex!, impulsey!)    impulsex! = impulsex! * impactSpeed! * balls(0).mass * balls(1).mass / 2    impulsey! = impulsey! * impactSpeed! * balls(0).mass * balls(1).mass / 2    xva! = balls(0).xv + impulsex! / balls(0).mass    yva! = balls(0).yv + impulsey! / balls(0).mass    xvb! = balls(1).xv - impulsex! / balls(1).mass    yvb! = balls(1).yv - impulsey! / balls(1).massRETURNFUNCTION Collide (Ball() AS ballType)'returns id the ball collided using the distance formula.'can be optimized a lot!!!    Collide = 0    dx! = Ball(1).x - Ball(0).x    dy! = Ball(1).y - Ball(0).y    dist! = SQR(dx! ^ 2 + dy! ^ 2)    IF dist! <= 20 THEN        Collide = -1    END IFEND FUNCTIONFUNCTION Dot! (ax!, ay!, bx!, by!)'returns the dot product between 2 vectors a and b.    Dot! = (ax! * bx!) + (ay! * by!)END FUNCTIONSUB Normalize (nx!, ny!, X1!, Y1!, X2!, Y2!)'normalizes the components of a vector derived from 2 points (x1,y1) and'(x2,y2)    dx! = X2! - X1!    dy! = Y2! - Y1!    dist! = SQR(dx! ^ 2 + dy! ^ 2)    nx! = dx! / dist!    ny! = dy! / dist!END SUB`

Compiles with -lang qb. You'll have to do the usual changes to compile it with -lang fb (declare all variables, no variable suffixes, etc.).

Personally, this code is all I need in ball to ball collision. Relsoft is God! :P

Sorry, but I think this code is somehow flawed. Try changing the masses of the two balls to - say - 1 and 10, and you wil clearly see that the total momentum is increasing when in fact it should be conserved.
Lachie Dazdarian
Posts: 2230
Joined: May 31, 2005 9:59
Location: Croatia
Contact:
But I think it's a great start, wouldn't you say so?

If exige chooses to reinvent the wheel, be my guest.
h4tt3n
Posts: 659
Joined: Oct 22, 2005 21:12
Location: Denmark
Yes, it's not a bad start. It's definitely better than my go at solving the problem so far ^^

Seriously, imho reinventing things over and over is very important. That's how you learn new skills. Your very own - say - ball to ball collision engine may not ever become the best one around, but essentially this is how you learn to program.
Mindlessly copy-pasting other peoples code is always the easiest and least educational way to solve a problem.

And occasionally something entirely new and useful emerges from this constant re-thinking, re-experimenting and reinventing.

So in other words: Go exige go! I'm coming along too... ^^

http://hyperphysics.phy-astr.gsu.edu/hbase/elacol.html
http://en.wikipedia.org/wiki/Elastic_collision
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:
Normalize the dot product.
exige
Posts: 3
Joined: Jul 15, 2007 20:52

I have been busy with other things lately, but I will take time some day to try to solve my problem!

I think that I now have all the information I need to solve it! :D
h4tt3n
Posts: 659
Joined: Oct 22, 2005 21:12
Location: Denmark
Here is a really neat tutorial on elastic 2D collision, including full tutorial as .pdf file, a nice program that implements the method and full source code:

http://www.geocities.com/vobarian/2dcollisions/

I did a quick port of the most important part of it:

Code: Select all

`''  physics engine that simulates bouncing balls using vector math''  This code is based on the 2D elastic collision tutorial found at:''  http://www.geocities.com/vobarian/2dcollisions/Randomize TimerType Vector_2D  As Single X, YEnd TypeType Ball  As Uinteger Col  As Vector_2D Pos_New, Vel  As Single Mass, Density, RadiusEnd Type Declare Function Vector_Sub (Byref v1 As Vector_2D, Byref v2 As Vector_2D) As Vector_2DDeclare Function Vector_Add (Byref v1 As Vector_2D, Byref v2 As Vector_2D) As Vector_2DDeclare Function Vector_Magnitude (Byref vector As vector_2d) As SingleDeclare Function Vector_Normalize (Byref vector As vector_2d) As Vector_2DDeclare Function Dot_Product (Byref v1 As vector_2d, Byref v2 As vector_2d) As SingleDeclare Function Vector_Scalar_Mul (Byref s1 As Single, Byref v1 As vector_2d) As vector_2DDeclare Sub DoElasticCollision (Byref Ball_1 As Ball, Byref Ball_2 As Ball)Const Pi = 4*Atn(1)Dim As Vector_2D DistDim As Single Distance, Dist_MinDim As String X_Clicked = Chr(255)+"k"Dim As Integer Screen_x, Screen_Y, i, i2Dim Ball(1 to 5) As Ball''  screen settingsscreen_x = 600          ''  screen widthscreen_y = 400          ''  screen heightscreenres screen_x, screen_y, 16With Ball(1)  .Mass = 10  .Density = 0.001  .Radius = (((.Mass/.Density)/((4/3)*pi))^(1/3))  .Pos_New.X = 100  .Pos_New.Y = Screen_Y\2  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(255, 32, 32)End WithWith Ball(2)  .Mass = 20  .Density = 0.001  .Radius = (((.Mass/.Density)/((4/3)*pi))^(1/3))  .Pos_New.X = 200  .Pos_New.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(255, 32, 255)End WithWith Ball(3)  .Mass = 40  .Density = 0.001  .Radius = (((.Mass/.Density)/((4/3)*pi))^(1/3))  .Pos_New.X = 300  .Pos_New.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(32, 32, 255)End WithWith Ball(4)  .Mass = 80  .Density = 0.001  .Radius = (((.Mass/.Density)/((4/3)*pi))^(1/3))  .Pos_New.X = 400  .Pos_New.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(32, 255, 32)End WithWith Ball(5)  .Mass = 160  .Density = 0.001  .Radius = (((.Mass/.Density)/((4/3)*pi))^(1/3))  .Pos_New.X = 500  .Pos_New.Y = (Screen_Y\2)  .Vel.X = -2  .Vel.Y = -(Rnd-Rnd)/3  .Col = RGB(255, 255, 32)End WithDo     Screenlock        cls        For i = Lbound(Ball) to Ubound(Ball)            With Ball(i)                ''ball - wall collision detection        If .Pos_New.X > screen_x-.Radius-1 Then          .Pos_New.X = screen_x-.Radius-1          .Vel.X = -.Vel.X        Elseif .Pos_New.X < .Radius Then          .Pos_New.X = .Radius          .Vel.X = -.Vel.X        End If        If .Pos_New.Y > screen_y-.Radius-1 Then          .Pos_New.Y = screen_y-.Radius-1          .Vel.Y = -.Vel.Y        Elseif .Pos_New.Y < .Radius Then          .Pos_New.Y = .Radius          .Vel.Y = -.Vel.Y        End If                ''  ball - ball collision detection        For i2 = i+1 to Ubound(Ball)          Dist = Vector_Sub(.Pos_New, Ball(i2).Pos_New)          Distance = Vector_Magnitude(Dist)          Dist_Min = .Radius+Ball(i2).Radius          ''  elastic bounce          If Distance <= Dist_Min Then            DoElasticCollision(Ball(i), Ball(i2))          End If        Next                .Pos_New = Vector_Add(.Pos_New, .Vel)        Circle (.Pos_New.X, .Pos_New.Y), .Radius, .col,,,1,f              End With          Next      screenunlock    sleep 1, 1  Loop Until Multikey(1) Or Inkey = X_ClickedEnd'-------------------------------------------------------------------------------Function Vector_Sub (Byref v1 As Vector_2D, Byref v2 As Vector_2D) As Vector_2D  Dim As Vector_2D v  v.x = v1.x-v2.x  v.y = v1.y-v2.y  Return vEnd FunctionFunction Vector_Add (Byref v1 As Vector_2D, Byref v2 As Vector_2D) As Vector_2D  Dim As Vector_2D v  v.x = v1.x+v2.x  v.y = v1.y+v2.y  Return vEnd FunctionFunction Vector_Magnitude (Byref vector As vector_2d) As Single  Dim as Single x, y, r  x = Vector.x^2  y = Vector.y^2  r = Sqr(x+y)  Return rEnd FunctionFunction Vector_Normalize (Byref vector As vector_2d) As Vector_2D  Dim As Vector_2D v  Dim as Single r  r = Vector_Magnitude(Vector)  v.x = vector.x/r  v.y = vector.y/r  Return vEnd FunctionFunction Dot_Product (Byref v1 As vector_2d, Byref v2 As vector_2d) As Single  Return v1.x*v2.x+v1.y*v2.yEnd FunctionFunction Vector_Scalar_Mul (Byref s1 As Single, Byref v1 As vector_2d) As vector_2D  Dim as Vector_2d v  v.x = v1.x*s1  v.y = v1.y*s1  Return vEnd FunctionSub DoElasticCollision (Byref Ball_1 As Ball, Byref Ball_2 As Ball)    Dim As Vector_2D v_n, v_un, v_ut, v_v1tPrime, v_v2tPrime, v_v1nPrime, v_v2nPrime  Dim As Single v1n, v1t, v2n, v2t, v1tPrime, v2tPrime, v1nPrime, v2nPrime    ''  vector normal to collision surface  v_n = Vector_Sub(Ball_2.Pos_New, Ball_1.Pos_New)    ''  normalize vector - make it a unit vector  v_un = Vector_Normalize(v_n)    ''  unit tangenti vector  v_ut.x = -v_un.y  v_ut.y = v_un.x    ''  old normal and tangential velocity vectors  v1n = Dot_Product(v_un, Ball_1.vel)  v1t = Dot_Product(v_ut, Ball_1.vel)  v2n = Dot_Product(v_un, Ball_2.vel)  v2t = Dot_Product(v_ut, Ball_2.vel)    ''  new tangential velocity (uncanged)  v1tPrime = v1t  v2tPrime = v2t    ''  new normal velocity  v1nPrime = ((v1n * (ball_1.mass - ball_2.mass) + 2 * ball_2.mass * v2n)) / (ball_1.mass + ball_2.mass)  v2nPrime = ((v2n * (ball_2.mass - ball_1.mass) + 2 * ball_1.mass * v1n)) / (ball_1.mass + ball_2.mass)    ''  new normal and tangential velocity vectors  v_v1nPrime = Vector_scalar_mul(v1nPrime, v_un)  v_v1tPrime = Vector_scalar_mul(v1tPrime, v_ut)  v_v2nPrime = Vector_scalar_mul(v2nPrime, v_un)  v_v2tPrime = Vector_scalar_mul(v2tPrime, v_ut)    ''  new ball velocities  Ball_1.Vel = Vector_Add(v_v1nPrime, v_v1tPrime)  Ball_2.Vel = Vector_Add(v_v2nPrime, v_v2tPrime)  End Sub `