## Simple Circle/Line Physics Library

User projects written in or related to FreeBASIC.
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york
Also, my method works on any polygon... Not just triangles...
Prime Productions
Posts: 147
Joined: May 24, 2009 23:13
Location: Texas, United States, Planet Earth
Contact:
rolliebollocks wrote:Well, a triangle can have multiple heights for the same perimeter. That's why I figured it wasn't possible. I didn't know about Heron's formula. That's a good one.

Heron's formula would not be viable in a loop... Way too many Sqare Roots... Listen to me, Prime Production's method is not a viable solution...

Lol, Yes Rollie, I was just giving him an answer that would work (after all, he asked if it was mathematically possible), but yeah, I agree, it would be long-term better to use some sort of vertice sorting algo, like the one you described.
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
I've implemented the algo in an article from the QB Express. The only problem is finding out which normal to use. Because if you use the wrong one, the wall turns into a powerup sort of thing, and instead of bouncing, it throws it faster through the wall. Now, I'll probably have figured it out by the time I get back on here, but the question still deserves an answer. I'll be updating the first post's code to what I have done w/o the wall collision detect stuff that I'm working on shortly
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
What I need is not a collision detect algo now, I already understand that. What I need is a bounce algorithm that I can understand. If I don't understand it, I can't use it. I'm currently working on the vector side of the problem, but can't seem to make the ball bounce off both sides of the line. It bounces off one side, but the other side sends it shooting through the line like in this example.

test.bas (use the files from the first post for 'point2d.bi' and 'circle.bi')

Code: Select all

`#Include "fbgfx.bi"#Include "point2d.bi"#Include "circle.bi"Using fbType linetype   coord1 As Point2D   coord2 As Point2D   normal As point2dEnd TypeDeclare Function dist(ByVal a as point2d, ByVal b as point2d) as SingleDeclare sub normalize (ByRef p as point2d)Declare function dot(ByVal a as point2d, ByVal b as point2d) as SingleDeclare Function closest_point_on_line(ByVal linee As linetype, ByVal p as point2d) as point2dDeclare function collide_on_line ( l as linetype, ball as circletype) as IntegerDeclare sub get_2dnormal (seg as linetype, s as integer)Const accel = .5Dim ball As circletype = circletype(100, 40, 10, 4, USER)Dim p As point2dDim lin(1 To 1) As linetypeDim i As IntegerWith lin(1)   .coord1.x = 0   .coord1.y = 0   .coord2.x = 500   .coord2.y = 500End Withget_2dnormal(lin(1), 1)Screen 19Do   ScreenLock   Cls   For i = 1 To UBound(lin)      With lin(i)         Line (.coord1.x, .coord1.y)-(.coord2.x, .coord2.y), 15      End With   Next   ball.display   ScreenSync   screenunlock   If MultiKey(SC_UP) Then ball.yvelocity = ball.yvelocity - accel   If MultiKey(SC_RIGHT) Then ball.xvelocity = ball.xvelocity + accel   If MultiKey(SC_DOWN) Then ball.yvelocity = ball.yvelocity + accel   If MultiKey(SC_LEFT) Then ball.xvelocity = ball.xvelocity - accel   If MultiKey(SC_INSERT) Then ball.halt   ball.updatevalues   For i = 1 To UBound(lin)      collide_on_line(lin(i), ball)   Next   Sleep 25Loop Until MultiKey(SC_ESCAPE)Sleepprivate sub normalize (ByRef p as point2d)    dim leng as single    leng = sqr(p.x * p.x + p.y * p.y )    p.x = p.x / leng    p.y = p.y / lengend Subprivate function get_magnitude ( v as point2d ) as single        return sqr( ( v.x * v.x ) + ( v.y * v.y ) )    end Functionfunction dist(ByVal a as point2d, ByVal b as point2d) as Single   Dim as single dx, dy   dx = a.x - b.x   dy = a.y - b.y   return SQR((dx*dx)+(dy*dy))end functionfunction dot(ByVal a as point2d, ByVal b as point2d) as Single   return (a.x*b.x + a.y*b.y )end functionfunction closest_point_on_line(ByVal linee As linetype, ByVal p as point2d) as point2d    dim d as single    dim t as single    dim as point2d p1, p2, preturn   p1.x = p.x - linee.coord1.x   p1.y = p.y - linee.coord1.y   p2.x = linee.coord2.x - linee.coord1.x   p2.y = linee.coord2.y - linee.coord1.y   normalize p2   'calculate distance between 2 points a and b   d = dist(linee.coord1, linee.coord2)'       p'      /|'     / |'    /  |'   /   |' a-------------b'  |----| -> dist "t"   'get the distance of the projected vector from va by dropping a   'perpendicular from v1 to a point in v2   t = dot(p2, p1)   'if our projected distance is less than or equal to 0 then   If t<=0 Then Return linee.coord1   'if it is >= to the magnitude of the line segment v2 - v1 then   'it's closest to b.   If t>=d Then Return linee.coord2   'otherwise the point is n betweent the 2 endpoints so we   'create a vector with length "t" and ad it to our original point va   'to trace a line.   preturn.x = linee.coord1.x + (p2.x * t)   preturn.y = linee.coord1.y + (p2.y * t)   return preturnend Functionfunction collide_on_line ( l as linetype, ball as circletype) as integer    dim as point2d  a,b,impulse,impact,xpoint,pnt        a.x = l.coord1.x    a.y = l.coord1.y    b.x = l.coord2.x    b.y = l.coord2.y    pnt.x = ball.x    pnt.y = ball.y        xpoint = closest_point_on_line(l, pnt)        dim as single d        d = dist(pnt,xpoint)        if d<=ball.radius Then                        a.x = ball.xvelocity        a.y = ball.yvelocity                b.x = -a.x        b.y = -a.y                        impact.x = b.x - a.x        impact.y = b.y - a.y                impulse.x = l.normal.x        impulse.y = l.normal.y                'new = (impact dot impulse)/|impulse| * impulse        dim as single comp, leng,s        comp = dot(impact, impulse)        leng = get_magnitude(impulse)        s = (comp)/leng        impulse.x = impulse.x * s        impulse.y = impulse.y * s                                ball.xvelocity = ball.xvelocity + impulse.x         ball.yvelocity = ball.yvelocity + impulse.y                 'snap it back        ball.x = ball.x + l.normal.x * (ball.radius - d )        ball.y = ball.y + l.normal.y * (ball.radius - d )                            return 1                        end if        return 0end Functionprivate sub get_2dnormal (seg as linetype, s as integer)         if s then    seg.normal.x = -(seg.coord2.y-seg.coord1.y)  'negate to get the other normal    seg.normal.y = (seg.coord2.x-seg.coord1.x) 'erase negatio here if you want the other                                     'normal    else    seg.normal.x = (seg.coord2.y-seg.coord1.y)  'negate to get the other normal    seg.normal.y = -(seg.coord2.x-seg.coord1.x) 'erase negatio here if you want the other                                     'normal    end if    normalize (seg.normal)end Sub`
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
I got it all figured out. Here's the revised code for test.bas:

Code: Select all

`#Include "fbgfx.bi"#Include "point2d.bi"#Include "Bubble World.bi"Using fbType linetype   coord1 As Point2D   coord2 As Point2D   normal As point2dEnd TypeDeclare Function dist(ByVal a as point2d, ByVal b as point2d) as SingleDeclare sub normalize (ByRef p as point2d)Declare function dot(ByVal a as point2d, ByVal b as point2d) as SingleDeclare Function closest_point_on_line(ByVal linee As linetype, ByVal p as point2d) as point2dDeclare function collide_on_line ( l as linetype, ball as circletype) as IntegerDeclare sub get_2dnormal (seg as linetype, s as integer)Const accel = .5Dim ball As circletype = circletype(100, 40, 25, 4, USER)Dim As point2d p, screenmaxDim lin As linetypeDim As Integer i, x, yScreen 19ScreenInfo x, yRandomize Timer, 3screenmax.x = x:screenmax.y = yWith lin   .coord1.x = Rnd * screenmax.x   .coord1.y = Rnd * screenmax.y   .coord2.x = Rnd * screenmax.x   .coord2.y = Rnd * screenmax.yEnd WithDo   ScreenLock   Line (0, 0)-(screenmax.x, screenmax.y), 0, bf   With lin      Line (.coord1.x, .coord1.y)-(.coord2.x, .coord2.y), 15   End With   ball.display   ScreenSync   screenunlock   If MultiKey(SC_UP) Then ball.yvelocity = ball.yvelocity - accel   If MultiKey(SC_RIGHT) Then ball.xvelocity = ball.xvelocity + accel   If MultiKey(SC_DOWN) Then ball.yvelocity = ball.yvelocity + accel   If MultiKey(SC_LEFT) Then ball.xvelocity = ball.xvelocity - accel   If MultiKey(SC_INSERT) Then ball.halt   ball.updatevalues   collide_on_line(lin, ball)   Sleep 25Loop Until MultiKey(SC_ESCAPE)Sleepprivate sub normalize (ByRef p as point2d)    dim leng as single    leng = sqr(p.x * p.x + p.y * p.y )    p.x = p.x / leng    p.y = p.y / lengend Subprivate function get_magnitude ( v as point2d ) as single        return sqr( ( v.x * v.x ) + ( v.y * v.y ) )    end Functionfunction dist(ByVal a as point2d, ByVal b as point2d) as Single   Dim as single dx, dy   dx = a.x - b.x   dy = a.y - b.y   return SQR((dx*dx)+(dy*dy))end functionfunction dot(ByVal a as point2d, ByVal b as point2d) as Single   return (a.x*b.x + a.y*b.y )end functionfunction closest_point_on_line(ByVal linee As linetype, ByVal p as point2d) as point2d    dim d as single    dim t as single    dim as point2d p1, p2, preturn   p1.x = p.x - linee.coord1.x   p1.y = p.y - linee.coord1.y   p2.x = linee.coord2.x - linee.coord1.x   p2.y = linee.coord2.y - linee.coord1.y   normalize p2   'calculate distance between 2 points a and b   d = dist(linee.coord1, linee.coord2)'       p'      /|'     / |'    /  |'   /   |' a-------------b'  |----| -> dist "t"   'get the distance of the projected vector from va by dropping a   'perpendicular from v1 to a point in v2   t = dot(p2, p1)   'if our projected distance is less than or equal to 0 then   If t<=0 Then Return linee.coord1   'if it is >= to the magnitude of the line segment v2 - v1 then   'it's closest to b.   If t>=d Then Return linee.coord2   'otherwise the point is n betweent the 2 endpoints so we   'create a vector with length "t" and ad it to our original point va   'to trace a line.   preturn.x = linee.coord1.x + (p2.x * t)   preturn.y = linee.coord1.y + (p2.y * t)   return preturnend Functionfunction collide_on_line ( l as linetype, ball as circletype) as integer    dim as point2d  a,b,impulse,impact,xpoint,pnt,normal,normal0,normal1,blah0,blah1        a.x = l.coord1.x    a.y = l.coord1.y    b.x = l.coord2.x    b.y = l.coord2.y    pnt.x = ball.x    pnt.y = ball.y        xpoint = closest_point_on_line(l, pnt)        dim as single d        d = dist(pnt,xpoint)        if d<=ball.radius Then       get_2dnormal(l, 0)       normal0 = l.normal       get_2dnormal(l, 1)       normal1 = l.normal       blah0.x = xpoint.x + normal0.x       blah0.y = xpoint.y + normal0.y       blah1.x = xpoint.x + normal1.x       blah1.y = xpoint.y + normal1.y       If dist(blah0, pnt) < dist(blah1, pnt) Then l.normal = normal0       If dist(blah0, pnt) > dist(blah1, pnt) Then l.normal = normal1                   a.x = ball.xvelocity        a.y = ball.yvelocity                b.x = -a.x        b.y = -a.y                        impact.x = b.x - a.x        impact.y = b.y - a.y                impulse.x = l.normal.x        impulse.y = l.normal.y                'new = (impact dot impulse)/|impulse| * impulse        dim as single comp, leng,s        comp = dot(impact, impulse)        leng = get_magnitude(impulse)        s = (comp)/leng        impulse.x = impulse.x * s        impulse.y = impulse.y * s                                ball.xvelocity = ball.xvelocity + impulse.x         ball.yvelocity = ball.yvelocity + impulse.y                 'snap it back        ball.x = ball.x + l.normal.x * (ball.radius - d )        ball.y = ball.y + l.normal.y * (ball.radius - d )                            return 1                        end if        return 0end Functionprivate sub get_2dnormal (seg as linetype, s as integer)         if s then    seg.normal.x = -(seg.coord2.y-seg.coord1.y)  'negate to get the other normal    seg.normal.y = (seg.coord2.x-seg.coord1.x) 'erase negatio here if you want the other                                     'normal    else    seg.normal.x = (seg.coord2.y-seg.coord1.y)  'negate to get the other normal    seg.normal.y = -(seg.coord2.x-seg.coord1.x) 'erase negatio here if you want the other                                     'normal    end if    normalize (seg.normal)end Sub`

Compare with the code of the last post to figure out what happened.
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
I decided to bump this because I'm still working on it, Its just that I ran into the Extended FreeBASIC Library and all of its vector funtions, which are very helpful. I've decided to port my code to it and to move on to the next stage which is circle-circle collision detection. If any of you have any ideas or tuts that might help they would be appreciated.
h4tt3n
Posts: 694
Joined: Oct 22, 2005 21:12
Location: Denmark
qbworker wrote:I've decided to port my code to it and to move on to the next stage which is circle-circle collision detection. If any of you have any ideas or tuts that might help they would be appreciated.

The sph.zip in the thread linked to below contains a very effective circle-circle collision detection. I've commented the code, so you should be able to find it.

cheers Mike

http://www.freebasic.net/forum/viewtopi ... hlight=sph
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york
Circle to Circle collision is just the distance formula again. If the distance from the center of one circle to another is less than the two radii summed you have a collision.
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
The idea is I want them to bounce, not just stop when they hit each other.
rolliebollocks
Posts: 2655
Joined: Aug 28, 2008 10:54
Location: new york
I found this:

'' 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/

Code: Select all

`Randomize TimerType Vector_2D  As Double X, YEnd TypeType Ball  As Uinteger Col  As Vector_2D Pos, Vel  As Double 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 DoubleDeclare 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 DoubleDeclare Function Vector_Scalar_Mul (Byref s1 As Double, 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 Double Distance, Dist_Min, Momentum, momentum_init, velocity, Ekin, Ekin_initDim 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, 16randomize timerWith Ball(1)  .Mass = 16  .Density = 0.001  .Radius = ((.Mass/.Density)/((4/3)*pi))^(1/3)  .Pos.X = 100  .Pos.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(255, 32, 32)End WithWith Ball(2)  .Mass = 32  .Density = 0.001  .Radius = ((.Mass/.Density)/((4/3)*pi))^(1/3)  .Pos.X = 200  .Pos.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(255, 32, 255)End WithWith Ball(3)  .Mass = 64  .Density = 0.001  .Radius = ((.Mass/.Density)/((4/3)*pi))^(1/3)  .Pos.X = 300  .Pos.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(32, 32, 255)End WithWith Ball(4)  .Mass = 128  .Density = 0.001  .Radius = ((.Mass/.Density)/((4/3)*pi))^(1/3)  .Pos.X = 400  .Pos.Y = (Screen_Y\2)  .Vel.X = 0  .Vel.Y = 0  .Col = RGB(32, 255, 32)End WithWith Ball(5)  .Mass = 256  .Density = 0.001  .Radius = ((.Mass/.Density)/((4/3)*pi))^(1/3)  .Pos.X = 500  .Pos.Y = (Screen_Y\2)  .Vel.X = rnd-rnd  .Vel.Y = rnd-rnd  .Col = RGB(255, 255, 32)End WithFor i = Lbound(Ball) to Ubound(Ball)  Velocity = Vector_Magnitude(Ball(i).vel)  momentum_init += Ball(i).mass*Velocity  Ekin_init += 0.5*Ball(i).Mass*Velocity^2NextDo     Screenlock        Cls        For i = Lbound(Ball) to Ubound(Ball)            With Ball(i)                ''ball - wall collision detection        If .Pos.X > screen_x-.Radius-1 Then          .Pos.X = screen_x-.Radius-1          .Vel.X = -.Vel.X        Elseif .Pos.X < .Radius Then          .Pos.X = .Radius          .Vel.X = -.Vel.X        End If        If .Pos.Y > screen_y-.Radius-1 Then          .Pos.Y = screen_y-.Radius-1          .Vel.Y = -.Vel.Y        Elseif .Pos.Y < .Radius Then          .Pos.Y = .Radius          .Vel.Y = -.Vel.Y        End If                ''  ball - ball collision detection        For i2 = i+1 to Ubound(Ball)                    Dist = Vector_Sub(.Pos, Ball(i2).Pos)          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 = Vector_Add(.Pos, .Vel)        Circle (.Pos.X, .Pos.Y), .Radius, .col,,,1,f                Momentum = 0        Ekin = 0                For i2 = Lbound(Ball) to Ubound(Ball)          Velocity = Vector_Magnitude(Ball(i2).vel)          momentum += Ball(i2).mass*Velocity          Ekin += 0.5*Ball(i2).Mass*Velocity^2        Next                Locate 1, 1: Print Momentum_Init        Locate 2, 1: Print Momentum        Locate 4, 1: Print Ekin_Init        Locate 5, 1: Print Ekin              End With          Next      screenunlock    sleep 2, 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 Double  Dim as Double 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 Double 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 Double  Return v1.x*v2.x+v1.y*v2.yEnd FunctionFunction Vector_Scalar_Mul (Byref s1 As Double, 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 Double v1n, v1t, v2n, v2t, v1tPrime, v2tPrime, v1nPrime, v2nPrime    ''  vector normal (perpendicular) to collision surface  v_n = Vector_Sub(Ball_2.Pos, Ball_1.Pos)    ''  normalize vector - make it a unit vector  v_un = Vector_Normalize(v_n)    ''  unit tangent vector (parallel to collision surface)  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 `
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
Thanks! I'll just turn this into a massless proggie and I'll have what I'm looking for. I just wanted not a full physics simulation just something easy to build upon to make different stuff that needs this sort of thing.
dodicat
Posts: 6754
Joined: Jan 10, 2006 20:30
Location: Scotland
qbworker wrote:Thanks! I'll just turn this into a massless proggie and I'll have what I'm looking for. I just wanted not a full physics simulation just something easy to build upon to make different stuff that needs this sort of thing.

Hi qbworker
I'm messing about with 2d collisions, and trying out simple vector stuff.
I've kinda simplified this code a bit, pretty nearly mathematically correct, but needs touched up.
The balls bounce off each other, off the sides and off some lines, if they get through the bottom gap, they come back on screen at the top.
You can nudge them with the mouse, and use the up/down keys to adjust for a bit of gravity.
The basic motion of the balls is Newton's second equation
S=START+U*T + .5*G*T^2
where T increments by 1 each frame, and on every impact T becomes zero, START becomes the position at impact, in other words a new trajectory starts at each collision.
The up/down keys are not too sensitive, I'll have to fix that.
It's all a bit silly really.

Code: Select all

`'BALLSType vector3d    As Single x,y,z    End TypeType plane    As vector3d v1,v2,v3End TypeType line3d    As vector3d v1,v2    End Type#define vct type<vector3d>#define ln type<line3d>#define pl type<plane>#define cross <>#define dot *operator + (v1 As vector3d,v2 As vector3d) As vector3dReturn Type<vector3d>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)End operatoroperator -(v1 As vector3d,v2 As vector3d) As vector3dReturn Type<vector3d>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)End operator'______________ SCALARs and  products_______________________operator * Overload (v1 As vector3d,v2 As vector3d) As SingleReturn v1.x*v2.x+v1.y*v2.y+v1.z*v2.zEnd operatoroperator * Overload (f As Single,v1 As vector3d) As vector3dReturn Type<vector3d>(f*v1.x,f*v1.y,f*v1.z)End operatoroperator * Overload (v1 As vector3d,f As Single) As vector3dReturn Type<vector3d>(f*v1.x,f*v1.y,f*v1.z)End operator'________________END SCALERS _________________operator <>(v1 As vector3d,v2 As vector3d) As vector3d 'crossReturn Type<vector3d>(v1.y*v2.z-v2.y*v1.z,-(v1.x*v2.z-v2.x*v1.z),v1.x*v2.y-v2.x*v1.y)End operatordeclare Function length(v As vector3d) As Singledeclare Function normalize(v As vector3d) As vector3ddeclare Function r(first As Single, last As Single) As Singledeclare Function isleft(L As line3d,p As vector3d) As Double  declare Function planedistance(v3 As PLANE,p As vector3d) As Singledeclare sub drawline(l as line3d)declare Function drop_perpendicular(p As vector3d,L2 As line3d) As vector3ddeclare Sub balls(n As Integer,rad As Single)declare Function segmentdistance(L() As line3d,p As vector3d,Byref p2 As vector3d=vct(0,0,0)) As Singledim shared gravity as singleDim Shared As Integer xres,yresScreen 19,32Screeninfo xres,yresDim As vector3d vl1,vl2,vl3vL1=vct(0,yres/3,0):vL2=vct(xres/2.5,yres,0):vl3=vct(0,yres/3,100)Dim Shared As line3d line1,line2,lineseg(1)Dim Shared As plane plane1,plane2line1=ln(vL1,vL2)plane1=pl(vl1,vl2,vl3)vL1=vct(xres,yres/3,0):vL2=vct(xres-xres/2.5,yres,0):vl3=vct(xres,yres/3,100)line2=ln(vL1,vL2)plane2=pl(vl1,vl2,vl3)vl1=vct(.3*xres,.2*yres,0):vl2=vct(.6*xres,.4*yres,0)lineseg(1)=ln(vl1,vl2)dim as string iDo    i=inkey    if i=chr(255)&"P" then gravity=gravity+.005    if i=chr(255)&"H" then gravity=gravity-.005:if gravity<0 then gravity=0    Screenlock    Cls    locate 2,2    print "Gravity = "; gravity    drawline(line1)    drawline(line2)    drawline(lineseg(1))    balls(5,50)    Screenunlock    Sleep 1,1    Loop Until Inkey=Chr(27)SleepFunction segmentdistance(L() As line3d,p As vector3d,Byref p2 As vector3d=vct(0,0,0)) As Single    Dim As vector3d near,far,pp    Dim n As Integer=L(0).v1.z    If length(p-L(n).v1) > length(p-L(n).v2) Then        far=L(n).v1        near=L(n).v2    Else        far=L(n).v2        near=L(n).v1    End If    pp=drop_perpendicular(p,L(n))    If length(far-pp)<length(L(n).v1-L(n).v2) Then        p2=pp        Return length(p-pp)    Else        p2=near        Return length(p-near)    End If   End FunctionFunction length(v As vector3d) As Single    Return Sqr(v.x*v.x+v.y*v.y+v.z*v.z)End FunctionFunction normalize(v As vector3d) As vector3d    Dim n As Single=length(v)    If n<>0 Then    Return Type<vector3d>(v.x/n,v.y/n,v.z/n)    End If    End FunctionFunction r(first As Single, last As Single) As Single    Function = Rnd * (last - first) + firstEnd FunctionFunction isleft(L As line3d,p As vector3d) As Double      Return -Sgn(  (L.v1.x-L.v2.x)*(p.y-L.v2.y) - (p.x-L.v2.x)*(L.v1.y-L.v2.y))End FunctionFunction planedistance(v3 As PLANE,p As vector3d) As Single    Dim As vector3d pv=p-v3.v1     Dim As vector3d vp1,vp2,unitcross    vp1=v3.v1-v3.v2      vp2=v3.v2-v3.v3    unitcross=normalize(vp1 cross vp2)    Return unitcross dot pvEnd Function sub drawline(l as line3d)    line(l.v1.x,l.v1.y)-(l.v2.x,l.v2.y),rgb(200,200,200)end sub Function drop_perpendicular(p As vector3d,L2 As line3d) As vector3d     Dim As Double M1,M2,C1,C2    Dim As vector3d pt    M2=(L2.v2.y-L2.v1.y)/(L2.v2.x-L2.v1.x)    M1=-1/M2    C1=p.y-M1*p.x    C2=(L2.v1.y*L2.v2.x-L2.v1.x*L2.v2.y)/(L2.v2.x-L2.v1.x)    pt.x=(C2-C1)/(M1-M2)    pt.y=(M1*C2-M2*C1)/(M1-M2)    Return ptEnd FunctionSub balls(n As Integer,rad As Single)    Static runflag As Byte        Static As vector3d b()        Redim Preserve b(1 To n)        Static As vector3d u()        Redim Preserve u(1 To n)        Static As Uinteger col()        Redim Preserve col(1 To n)        Static As Single sp()        Redim Preserve sp(1 To n)        Static As Single k()        Redim Preserve k(1 To n)        Static As vector3d startpos()        Redim Preserve startpos(1 To n)        Static As Single _rad()        Redim Preserve _rad(1 To n)        dim as vector3d impactIf runflag=0 ThenFor x As Integer=1 To n    b(x)=vct(r(0,xres),0,0)    _rad(x)=rad    sp(x)=1    k(x)=0    col(x)=Rgb(00,200,00)    startpos(x)=vct(r(0,xres),0,0)Next x       runflag=1End IfDim As vector3d impulse,p2,mousedim as integer mx,my#macro sides()For z2 As Integer=1 To n    lineseg(0).v1.z=1    if segmentdistance(lineseg(1),b(z2),impact)<_rad(z2) then        impulse=normalize(b(z2)-impact)        u(z2)=u(z2)+impulse        sp(z2)=length(u(z2))    u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)        end if              If planedistance(plane1,b(z2))<_rad(z2) Then     p2=drop_perpendicular(b(z2),line1)    impulse=normalize(b(z2)-p2)    If isleft(line1,b(z2))<0 Then    u(z2)=u(z2)+impulseElse    u(z2)=u(z2)-impulse    End If   ' sp(z2)=length(u(z2))   ' u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)    End If        If -planedistance(plane2,b(z2))<rad Then         p2=drop_perpendicular(b(z2),line2)    impulse=normalize(b(z2)-p2)    If -isleft(line2,b(z2))<0 Then    u(z2)=u(z2)+impulseElse    u(z2)=u(z2)-impulse    End If    'sp(z2)=length(u(z2))    'u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)End If     If b(z2).y>yres Then'-rad    If (b(z2).x>line1.v2.x) And (b(z2).x<line2.v2.x)  Then     For x As Integer=2 To 5     If z2 Mod x  Then          Select Case col(z2)         Case Rgb(0,200,0)         col(z2)=Rgb(200,0,0)         Exit Select     Case Rgb(200,0,0)         col(z2)=Rgb(0,0,200)         Exit Select     Case Rgb(0,0,200)         col(z2)=Rgb(200,200,0)         Exit Select     Case Rgb(200,200,0)         col(z2)=Rgb(0,200,200)         Exit Select     Case Rgb(0,200,200)         col(z2)=Rgb(0,200,0)         Exit Select         End Select    k(z2)=0    startpos(z2).y=0    sp(z2)=.01    End IfNext xElse   impulse=vct(0,-1,0)    u(z2)=u(z2)+impulse    sp(z2)=length(u(z2))    u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)     End If    End If              If b(z2).x<rad Then    u(z2)=u(z2)+vct(1,0,0)    sp(z2)=length(u(z2))    u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)End IfIf b(z2).x>xres-rad Then    u(z2)=u(z2)+vct(-1,0,0)    sp(z2)=length(u(z2))    u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)End IfIf b(z2).y<rad Then    u(z2)=u(z2)+vct(0,1,0)    sp(z2)=length(u(z2))    u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)End Ifgetmouse(mx,my)mouse=vct(mx,my,0)circle(mx,my),20,rgb(100,100,100),,,,fif length(b(z2)-mouse)<_rad(z2)+20 then    impulse=normalize(b(z2)-mouse)    u(z2)=u(z2)+impulse    'sp(z2)=length(u(z2))    'u(z2)=normalize(u(z2))    k(z2)=0    startpos(z2)=b(z2)    end ifNext z2#endmacro#macro ball_to_ball()For xx As Integer=1 To n    For yy As Integer=1 To n        If xx<>yy Then            If length(b(xx)-b(yy))<=_rad(xx)+_rad(yy) Then                impulse=normalize(b(xx)-b(yy))              u(xx)=u(xx)+impulse                u(yy)=u(yy)-impulse                sp(xx)=length(u(xx))                sp(yy)=length(u(yy))               u(xx)= normalize(u(xx)):u(yy)=normalize(u(yy))               k(xx)=0:k(yy)=0:startpos(xx)=b(xx):startpos(yy)=b(yy)            End If        End If    Next yyNext xx#endmacro'Dim As vector3d c    sides()    ball_to_ball()    For z As Integer=1 To n        k(z)=k(z)+1        b(z)=startpos(z)+k(z)*sp(z)*u(z)+sp(z)*vct(0,gravity*k(z)*k(z),0)        'c.x=c.x+b(z).x:c.y=c.y+b(z).y    Circle(b(z).x,b(z).y),rad,col(z),,,,fNext z'c.x=c.x/n:c.y=c.y/n'_rad(n)=rad'b(n).x=c.x:b(n).y=c.y:col(n)=Rgba(100,0,0,200)'face(c.x,c.y)    End Sub`
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
dodicat: thanks for the help!(a month later!)

Ok, I'm having trouble here. Far as I can see, somehow when I collide with something, I change the velocity of my circle to infinity, and when I add infinity to my position, it changes the position to infinity(#QNAN)

Basically here's what happens:

1. I bump the line.
2. The velocity becomes 1.#IND (both the x and y velocity)
3. The position becomes 1.#IND, and the velocity becomes 1.#QNAN.
4. The position becomes 1.#QNAN

From googling, I found out that #QNAN stands for quiet not a number. #IND I haven't been able to figure out though. It's too much like Indiana, so, on googling, it gives me millions of links to sites about Indiana! Thanks for all the help so far. The programs are below(requires the FreeBASIC Extended Libary)

physics.bi

Code: Select all

`#Include "fbgfx.bi"#Include Once "ext/math/line2.bi"#Include Once "ext/math/projections.bi"#Include Once "ext/math/reflections.bi"#Include Once "ext/math/vector2.bi"Using fbType vector2d As ext.math.fbext_Vector2( ((Single)) )Type line2d As ext.math.fbext_Line2( ((Single)) )Type circle2d    posi As vector2d    vel As vector2d    radius As Integer    ccolor As Integer    maxvelocity As Integer    Declare Function bounce (ByRef ball As circle2d) As Integer    Declare Function bounce Overload (ByRef wall As line2d) As Integer    Declare Sub halt()    Declare Sub display(ByVal xx_ As single, ByVal yy_ As Single)    Declare Constructor(x As Single, y As Single, rad As Integer, colr As Integer, maxvel As Integer)    Declare Constructor()End TypeDeclare Function lineNormal(ByVal l As line2d, ByVal num As Integer) As vector2dfunction circle2d.bounce (byref wall as line2d) as integer    dim as vector2d impulse,impact,xpoint,normal,normal0,normal1,blah0,blah1        xpoint = ext.math.ClampProjectedPoint(wall, this.posi)        dim as single d        d = this.posi.distance(xpoint)        if d < this.radius then        normal0 = lineNormal(wall, 1)        normal1 = lineNormal(wall, 1)        blah0 = xpoint + normal0        blah1 = xpoint + normal1        if this.posi.distance(blah0) < this.posi.distance(blah1) then normal = normal0        if this.posi.distance(blah0) > this.posi.distance(blah1) then normal = normal1        Print normal.x, normal.y        Sleep        impact.x = -this.vel.x - this.vel.x        impact.y = -this.vel.y - this.vel.y                impulse = normal                dim as single comp, leng, s        comp = impact.dot(impulse)        leng = impulse.magnitude()        s = (comp)/leng        impulse = impulse * s                this.vel = this.vel + impulse                this.posi = this.posi + normal * (this.radius - d)                return 1    end if        return 0end functionfunction circle2d.bounce(byref ball as circle2d) As Integer    if this.posi.distance(ball.posi) <= this.radius + ball.radius then        dim as vector2d impact, impulse        dim impactspeed as double        impact = this.vel - ball.vel        impulse = this.posi - ball.posi        impulse.normalize        impactspeed = impulse.dot(impact)        impulse = impulse * impactspeed        this.vel = this.vel + impulse        ball.vel = ball.vel + -impulse        return 1    end if    return 0end functionSub circle2d.halt()   this.vel.x = 0   this.vel.y = 0End SubSub circle2d.display(ByVal xx_ As single, ByVal yy_ As Single)   Circle(xx_, yy_), this.radius, this.ccolor,,,,fEnd SubConstructor circle2d(x_ As Single, y_ As Single, rad_ As Integer, colr_ As Integer, maxvel_ As Integer)   this.posi.x = x_   this.posi.y = y_   this.radius = rad_   this.ccolor = colr_   this.maxvelocity = maxvel_End ConstructorConstructor circle2d()   this.posi.x = 0   this.posi.y = 0   this.radius = 0   this.ccolor = 0   this.maxvelocity = 0End ConstructorFunction lineNormal(ByVal l As line2d, ByVal num As Integer) As vector2d   Dim As vector2d normal1, normal2         normal1.x = -(l.b.y-l.a.y)      normal1.y = (l.b.x-l.a.x)            normal2.x = (l.b.y-l.a.y)      normal2.y = -(l.b.x-l.a.x)        normal1.normalize     normal2.normalize         If num = 1 Then Return normal1    If num = 2 Then Return normal2End Function`

test.bas

Code: Select all

`#Include "fbgfx.bi"#Include "physics.bi"Using fbConst accel = .5Const friction = .02Dim ball As circle2dDim As vector2d screenmax, blahx, blahyDim l As line2dDim As Integer i, j, x, y, ubindex = 0Screen 19Screeninfo x, yRandomize Timer, 3screenmax.x = x:screenmax.y = yWith ball   .posi.x = CInt(Rnd * screenmax.x)   .posi.y = CInt(Rnd * screenmax.y)   .radius = CInt(Rnd * 20) + 10   .ccolor = i + 1   .maxvelocity = .radius / 2End WithDo    With l             .a.x = Rnd * screenmax.x            .a.y = Rnd * screenmax.y            .b.x = Rnd * screenmax.x            .b.y = Rnd * screenmax.y    End With       Do        Screenlock        Cls        With l                Line (.a.x, .a.y)-(.b.x, .b.y), 15        End With        ball.display(ball.posi.x, ball.posi.y)        Locate 0, 0        Print "X"; ball.posi.x, "Y"; ball.posi.y, "XV"; ball.vel.x, "YV"; ball.vel.y        ScreenSync        Screenunlock        If Multikey(SC_UP) Then ball.vel.y = ball.vel.y - accel        If Multikey(SC_RIGHT) Then ball.vel.x = ball.vel.x + accel        If Multikey(SC_DOWN) Then ball.vel.y = ball.vel.y + accel        If Multikey(SC_LEFT) Then ball.vel.x = ball.vel.x - accel        If Multikey(SC_INSERT) Then ball.halt       ball.posi.x += ball.vel.x       ball.posi.y += ball.vel.y       ball.vel *= (1 - friction)       ball.bounce(l)       If Abs(ball.vel.magnitude) > ball.maxvelocity Then ball.vel = ball.vel - 1    Loop Until Multikey(SC_ESCAPE) Or Multikey(SC_SPACE)Loop Until Multikey(SC_ESCAPE)`
qbworker
Posts: 73
Joined: Jan 14, 2011 2:34
Bug fixed. First post updated.
Dr_D
Posts: 2415
Joined: May 27, 2005 4:59
Contact:
I'm glad to see you're using the fbext vector stuff. this makes me happy. i thought no one would ever use it. thank you. :)