NM...use Brucey's Chipmunk module instead.
Updated: Version 0.05, Nov 2, 2007.
Put in realistic velocity transfer on ball to ball collision. It's acting a lot like billiards now. Try it out.
*** *** *** *** ***
Here's something I've been messing around with. I think the order that I'm doing the collision check might be off though. It's got the basics of ball collision and it's somewhat cleanly coded.
If anyone can add to this or improve it that'd be great. Feel free to use it.
main.bmx
Vec2D.bmx
Updated: Version 0.05, Nov 2, 2007.
Put in realistic velocity transfer on ball to ball collision. It's acting a lot like billiards now. Try it out.
*** *** *** *** ***
Here's something I've been messing around with. I think the order that I'm doing the collision check might be off though. It's got the basics of ball collision and it's somewhat cleanly coded.
If anyone can add to this or improve it that'd be great. Feel free to use it.
main.bmx
'Advanced 2D Ball Fizzix v0.005 'Nov 2, 2007 SuperStrict Import "Vec2D.bmx" SeedRnd MilliSecs() Graphics 800,600',32,75 Global BodyList:TList = New TList 'Create some balls For Local i:Int = 1 To 30 Local ball:TBody = CreateBody() ball.fRadius = Rand(10,40) ball.fMass = ball.fRadius / 10.0 Local distok% Repeat distok = True ball.current.vPos.Set(Rand(ball.fRadius,GraphicsWidth()-ball.fRadius), Rand(ball.fRadius,GraphicsHeight()-ball.fRadius)) Local a:TBody For a = EachIn BodyList If a <> ball If BodyDist(ball,a) < ball.fRadius + a.fRadius distok = False Exit EndIf EndIf Next Until distok = True 'ball.current.vVel.Set(Rand(-250,250), Rand(-250,250)) ball.previous = ball.current.Copy() ball.fGravity = 9.81 Select Rand(4) Case 1 SetBodyColor ball,255,0,0 Case 2 SetBodyColor ball,255,255,0 Case 3 SetBodyColor ball,0,255,0 Case 4 SetBodyColor ball,0,0,255 End Select Next SetBlend ALPHABLEND Global GravityOn% = True Local body:TBody Global pixelScale# = 100 Local newTime:Int = MilliSecs() Local oldtime:Int = newTime Local LogicFPS% = 100 Local dt# = 1.0/LogicFPS Local deltaTime#, accumulator#, alpha#, t# While KeyDown(KEY_ESCAPE)=False And AppTerminate()=False Cls If KeyHit(KEY_H) Local temp:TBody = CreateBody(1000) EndIf If KeyHit(KEY_SPACE) Then GravityOn = 1 - GravityOn newTime = MilliSecs() deltaTime# = (newTime - oldTime) * 0.001 oldTime = newTime accumulator :+ deltaTime While accumulator >= dt 'User input If KeyHit(KEY_ENTER) For body = EachIn bodyList body.current.vVel.Set(Rand(-250,250),Rand(-250,250)) Next EndIf 'Update Logic For body = EachIn bodyList body.Logic(dt, t) Next accumulator :- dt t :+ dt Wend 'Calculate tween alpha = accumulator / dt 'Render with tween(alpha) For body = EachIn bodyList body.Render(alpha) Next DrawText "Press the Space Bar to toggle gravity.",5,5 DrawText "Press the Enter Key to send em' flying.",5,25 Flip 1'False Wend End Type TBody Field image:TImage Field fMass:Float = 10.0 Field fInertia:Float = 1.0 Field fInertiaInverse:Float Field fGravity:Float Field fRadius:Float = 16 Field fBounce:Float = .8 Field fFriction_roll:Float = 1.0 Field r%, g%, b% Field current:TState = New TState Field previous:TState = New TState Method Logic(dt#, t#) 'DrawText Int(self.current.vVel.Magnitude()),self.current.vPos.x+16,self.current.vPos.y-16 'Store the current state of the object self.previous = self.current.Copy() 'Reset Forces self.current.vForces.Zero() self.current.fMoment = 0 'Gravity If GravityOn If self.fGravity Then ApplyLinearForce Self,0,self.fMass * self.fGravity * pixelScale,0 EndIf 'Linear self.current.vAcc = self.current.vForces.DividedByScalar(self.fMass) self.current.vVel = self.current.vVel.Plus(self.current.vAcc.TimesScalar(dt)) self.current.vPos = self.current.vPos.Plus(self.current.vVel.TimesScalar(dt)) 'Rotational self.current.fAngAcc = self.current.fMoment * self.fInertiaInverse self.current.fAngVel :+ self.current.fAngAcc * dt 'Advanced Ball Collision For Local body2:TBody = EachIn bodyList Local dx#, dy#, ax#, ay#, vx1#, vy1#, vx2#, vy2#, va1#, vb1#, va2#, vb2#, ed#, vaP1#, vaP2# 'Rem If Self <> body2 Local dist# = BodyDist(Self, body2) If dist < self.fRadius + body2.fRadius 'set body to position prior to collision self.current.vPos = self.previous.vPos.Copy() body2.current.vPos = body2.previous.vPos.Copy() 'find x and y distances dx# = body2.current.vPos.x - self.current.vPos.x dy# = body2.current.vPos.y - self.current.vPos.y 'find body to body distance dist = Sqr(dx*dx + dy*dy) 'find normal ax# = dx / dist ay# = dy / dist 'store velocities for computation convenience vx1# = self.current.vVel.x vy1# = self.current.vVel.y vx2# = body2.current.vVel.x vy2# = body2.current.vVel.y 'calc new x and y velocities for each body va1# = (vx1*ax+vy1*ay) vb1# = (-vx1*ay+vy1*ax) va2# = (vx2*ax+vy2*ay) vb2# = (-vx2*ay+vy2*ax) 'Elasticity Factor ed# = 0.8 vaP1# = va1 + (1+ed)*(va2-va1)/(1+self.fMass/body2.fMass) vaP2# = va2 + (1+ed)*(va1-va2)/(1+body2.fMass/self.fMass) 'set body1 new velocity self.current.vVel.x = vaP1*ax-vb1*ay self.current.vVel.y = vaP1*ay+vb1*ax 'set body2 new velocity body2.current.vVel.x = vaP2*ax-vb2*ay body2.current.vVel.y = vaP2*ay+vb2*ax 'Exit EndIf EndIf Next 'Find out which way the ball is traveling Local col% = False Local dirx# = self.current.vPos.x - self.previous.vPos.x Local diry# = self.current.vPos.y - self.previous.vPos.y 'Basic Collision (32 is the diameter of the ball) If self.current.vPos.y <= self.fRadius col = True self.current.vVel.y = -self.current.vVel.y * self.fBounce 'bounce factor self.current.vPos.y = self.previous.vPos.y 'set ball to previous y position If dirx < 0 Then self.current.fAngVel = 360.0 * Sqr(self.current.vVel.x^2) / (Pi * 32) If dirx > 0 Then self.current.fAngVel = 360.0 * -Sqr(self.current.vVel.x^2) / (Pi * 32) EndIf If self.current.vPos.y >= GraphicsHeight() - self.fRadius col = True self.current.vVel.y = -self.current.vVel.y * self.fBounce 'bounce factor self.current.vPos.y = self.previous.vPos.y 'set ball to previous y position If dirx < 0 Then self.current.fAngVel = 360.0 * -Sqr(self.current.vVel.x^2) / (Pi * 32) If dirx > 0 Then self.current.fAngVel = 360.0 * Sqr(self.current.vVel.x^2) / (Pi * 32) EndIf If self.current.vPos.x <= self.fRadius col = True self.current.vVel.x = -self.current.vVel.x * self.fBounce 'bounce factor self.current.vPos.x = self.previous.vPos.x 'set ball to previous x position If diry < 0 Then self.current.fAngVel = 360.0 * -Sqr(self.current.vVel.y^2) / (Pi * 32) If diry > 0 Then self.current.fAngVel = 360.0 * Sqr(self.current.vVel.y^2) / (Pi * 32) EndIf If self.current.vPos.x >= GraphicsWidth() - self.fRadius col = True self.current.vVel.x = -self.current.vVel.x * self.fBounce 'bounce factor self.current.vPos.x = self.previous.vPos.x 'set ball to previous x position If diry < 0 Then self.current.fAngVel = 360.0 * Sqr(self.current.vVel.y^2) / (Pi * 32) If diry > 0 Then self.current.fAngVel = 360.0 * -Sqr(self.current.vVel.y^2) / (Pi * 32) EndIf If col = True Then self.current.vVel = self.current.vVel.TimesScalar(self.fFriction_roll) 'Update the object angle self.current.fAngle :+ self.current.fAngVel * dt 'Reset all forces and moments 'self.current.vForces.Zero() 'self.current.fMoment = 0 End Method Method Render(alpha#) Local x#, y#, s# x = self.current.vPos.x * alpha + self.previous.vPos.x * (1.0 - alpha) y = self.current.vPos.y * alpha + self.previous.vPos.y * (1.0 - alpha) s = self.current.fAngle * alpha + self.previous.fAngle * (1.0 - alpha) 'SetRotation s SetColor self.r, self.g, self.b DrawOval x-self.fRadius,y-self.fRadius,self.fRadius*2,self.fRadius*2 'DrawImage self.image, x, y SetRotation 0 SetColor 255, 255, 255 'DrawLine self.current.vPos.x,self.current.vPos.y,self.current.vPos.x + self.current.vVel.x/2,self.current.vPos.y + self.current.vVel.y/2 End Method End Type Function CreateBody:TBody(mass#=1, x#=400, y# = 100, radius#=10) Local b:TBody = New TBody b.current.vPos.x = x b.current.vPos.y = y b.r = 100 b.g = 100 b.b = 100 b.fGravity = 9.81 b.fRadius = radius b.fMass = Mass b.fInertiaInverse = 1.0/b.fInertia BodyList.AddLast(b) Return b End Function Type TState Field vPos:TVec2 = Vec2() Field vVel:TVec2 = Vec2() Field vAcc:TVec2 = Vec2() Field vForces:TVec2 = Vec2() Field fAngle:Float Field fAngVel:Float Field fAngAcc:Float Field fMoment:Float Method Copy:TState() Local t:TState = New TState t.vPos = self.vPos.Copy() t.vVel = self.vVel.Copy() t.vAcc = self.vAcc.Copy() t.fAngle = self.fAngle Return t End Method End Type Function ApplyLinearForce(body:TBody, xf#, yf#, zf#) Local vF:TVec2 = Vec2(xf, yf) body.current.vForces = body.current.vForces.Plus( vF ) End Function Function BodyDist:Float(body1:TBody, body2:TBody) Local x# = body1.current.vPos.x - body2.current.vPos.x Local y# = body2.current.vPos.y - body1.current.vPos.y Return Sqr(x*x + y*y) End Function Function BodyDist2:Float(body1:TBody, body2:TBody) Local x# = body1.current.vPos.x - body2.current.vPos.x Local y# = body1.current.vPos.y - body2.current.vPos.y Return Sqr(x*x + y*y) End Function Function SetBodyColor(body:TBody, r%, g%, b%) body.r = r body.g = g body.b = b End Function
Vec2D.bmx
Rem bbdoc: EndRem '2D Vector Lib Type TVec2 Field x:Float, y:Float Method Copy:TVec2() Return Vec2(self.x, self.y) End Method Method Plus:TVec2(v:TVec2) Local r:TVec2 = New TVec2 r.x = self.x + v.x r.y = self.y + v.y Return r End Method Method PlusNumber:TVec2(n:Float) Local r:TVec2 = New TVec2 r.x = self.x + n r.y = self.y + n Return r End Method Method Minus:TVec2(v:TVec2) Local r:TVec2 = New TVec2 r.x = self.x - v.x r.y = self.y - v.y Return r End Method Method MinusNumber:TVec2(n:Float) Local r:TVec2 = New TVec2 r.x = self.x - n r.y = self.y - n Return r End Method Method Times:TVec2(v:TVec2) Local r:TVec2 = New TVec2 r.x = self.x * v.x r.y = self.y * v.y Return r End Method Method TimesScalar:TVec2(s:Float) Local r:TVec2 = New TVec2 r.x = self.x * s r.y = self.y * s Return r End Method Method DividedBy:TVec2(v:TVec2) Local r:TVec2 = New TVec2 r.x = self.x / v.x r.y = self.y / v.y Return r End Method Method DividedByScalar:TVec2(s:Float) Local r:TVec2 = New TVec2 r.x = self.x / s r.y = self.y / s Return r End Method Method Magnitude:Float() Return Sqr(self.x * self.x + self.y * self.y) End Method Method Set(x#, y#) self.x = x self.y = y End Method Method Zero() self.x = 0 self.y = 0 End Method End Type Rem bbdoc: EndRem Function Vec2:TVec2(x#=0, y#=0) Local v:TVec2 = New TVec2 v.x = x v.y = y Return v End Function Rem bbdoc: EndRem Function GetAngle2D:Float(v1:TVec2, v2:TVec2) Return ATan2(v1.y - v2.y, v1.x - v2.x) End Function