Its probaly more fair if I post the code we have so far for others while I am occupied. So here is a complete post of all the files so far. Note: Collide.bmx only needs some vector and matrix equations converted. I've commented out the work still to be completed so it should run, but with major errors however. It should be debugable however.
arbiter.bmx
Rem
* Copyright (c) 2006 Erin Catto http://www.gphysics.com"
*
* Permission To use, copy, modify, distribute And sell this software
* And its documentation For any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software For any purpose.
* It is provided "as is" without express Or implied warranty.
End Rem
'/**
' *
' */
Const inEdge1:Int = 0
Const inEdge2:Int = 1
Const outEdge1:Int = 2
Const outEdge2:Int = 3
'/**
' *
' */
Type TFeaturePair
Field e:Byte Ptr
Field key:Int
Method New( )
e = Byte Ptr( Varptr( key ) )
End Method
End Type
'/**
' *
' */
Type TContact
Field position:TVec2
Field normal:TVec2
Field separation:Float
Field accumulatedNormalImpulse:Float
Field accumulatedTangentImpulse:Float
Field massNormal:Float, massTangent:Float
Field bias:Float
Field feature:TFeaturePair;
End Type
'/**
' *
' */
Function Arbiter:TArbiter( a:TBody, b:TBody )
Local nArb:TArbiter = New TArbiter
nArb.body1 = a
nArb.body2 = b
nArb.numContacts = Collide( nArb.contacts[TArbiter.MAX_POINTS], nArb.body1, nArb.body2 )
nArb.friction = Sqr( nArb.body1.friction * nArb.body2.friction )
Return nArb
End Function
'/**
' *
' */
Type TArbiter
Const MAX_POINTS:Int = 2
Field contacts:TContact[MAX_POINTS]
Field numContacts:Int
Field body1:TBody
Field body2:TBody
Field friction:Float
Method Update( newContacts:TContact[], numNewContacts:Int )
Local i:Int, j:Int, k:Int
Local mergedContacts:TContact[2]
For i = 0 To numNewContacts-1
Local cNew:TContact = newContacts[ i ]
k = -1
For j = 0 To numContacts-1
Local cOld:TContact = contacts[ j ]
If cNew.feature.key = cOld.feature.key
k = j
Exit
EndIf
Next
If k > -1
Local c:TContact = mergedContacts[i]
Local cOld:TContact = contacts[k]
c = cNew
c.accumulatedNormalImpulse = cOld.accumulatedNormalImpulse
c.accumulatedTangentImpulse = cOld.accumulatedTangentImpulse
Else
mergedContacts[i] = newContacts[i]
EndIf
Next
For i = 0 To numNewContacts-1
contacts[i] = mergedContacts[i]
Next
numContacts = numNewContacts
End Method
Method PreStep( inv_dt:Float )
Local k_allowedPenetration:Float = Float( 0.01 )
Local i:Int
For i = 0 To numContacts-1
Local c:TContact = contacts[i]
Local r1:TVec2 = SubVec2Vec2( c.position, body1.position )
Local r2:TVec2 = SubVec2Vec2( c.position, body2.position )
'// Precompute normal mass, tangent mass, And bias.
Local rn1:Float = Dot( r1, c.normal )
Local rn2:Float = Dot( r2, c.normal )
Local kNormal:Float = body1.invMass + body2.invMass
kNormal :+ body1.invI * (Dot(r1, r1) - rn1 * rn1)
kNormal :+ body2.invI * (Dot(r2, r2) - rn2 * rn2)
c.massNormal = 1.0 / kNormal
Local tangent:TVec2 = CrossVec2Float( c.normal, 1 )
Local rt1:Float = Dot( r1, tangent )
Local rt2:Float = Dot( r2, tangent )
Local kTangent:Float = body1.invMass + body2.invMass
kTangent :+ body1.invI*(Dot(r1, r1)-rt1*rt1)+body2.invI*(Dot(r2, r2)-rt2*rt2)
c.massTangent = 1 / kTangent
c.bias = -0.1 * inv_dt * Min(0, c.separation + k_allowedPenetration)
'// Apply normal + friction impulse
Local tVector1:TVec2 = c.normal.MultEx( c.accumulatedNormalImpulse )
Local tVector2:TVec2 = tangent.MultEx( c.accumulatedTangentImpulse )
Local impulse:TVec2 = AddVec2Vec2( tVector1, tVector2 )
body1.velocity = AddVec2Vec2( body1.velocity, impulse.MultEx( body1.invMass ) )
body1.angularVelocity :- CrossVec2Vec2( Impulse, r1 ) * body1.invI
body2.velocity = AddVec2Vec2( body2.velocity, impulse.MultEx( body2.invMass ) )
body2.angularVelocity :+ CrossVec2Vec2( Impulse, r2 ) * body2.invI
Next
End Method
Method ApplyImpulse( )
Local b1:TBody = body1
Local b2:TBody = body2
Local i:Int
For i = 0 To numContacts-1
Local c:TContact = contacts[i]
Local r1:TVec2 = SubVec2Vec2( c.position, body1.position )
Local r2:TVec2 = SubVec2Vec2( c.position, body2.position )
'// Relative velocity at contact
Local rv:TVec2 = AddVec2Vec2( b2.velocity, CrossFloatVec2( b2.angularVelocity, r2 ) )
rv = SubVec2Vec2( rv, b1.velocity )
rv = SubVec2Vec2( rv, CrossFloatVec2( b1.angularVelocity, r1 ) )
Local dv:TVec2 = Vec2( rv.x, rv.y )
'// Compute normal impulse with bias.
Local vn:Float = Dot( dv, c.normal )
Local normalImpulse:Float = c.massNormal * ( -vn + c.bias )
'// Clamp the accumulated impulse
Local oldNormalImpulse:Float = c.accumulatedNormalImpulse
c.accumulatedNormalImpulse = Max( oldNormalImpulse + normalImpulse, 0 )
normalImpulse = c.accumulatedNormalImpulse - oldNormalImpulse
'// Apply contact impulse
Local impulse:TVec2 = c.normal.MultEx( normalImpulse )
b1.velocity = SubVec2Vec2( b1.velocity, impulse.multEx( b1.invMass ) )
b1.angularVelocity :- CrossVec2Vec2( r1, impulse ) * b1.invI
b2.velocity = SubVec2Vec2( b2.velocity, impulse.multEx( b2.invMass ) )
b2.angularVelocity :+ CrossVec2Vec2( r2, impulse ) * b2.invI
'// Compute friction impulse
Local maxTangentImpulse:Float = friction * c.accumulatedNormalImpulse
Local tangent:TVec2 = CrossVec2Float( c.normal, 1 )
Local vt:Float = Dot( rv, tangent )
Local tangentImpulse:Float = c.massTangent * (-vt)
'// Clamp friction
Local oldTangentImpulse:Float = c.accumulatedTangentImpulse
c.accumulatedTangentImpulse = ClampFloat(oldTangentImpulse + tangentImpulse, -maxTangentImpulse, maxTangentImpulse)
tangentImpulse = c.accumulatedTangentImpulse - oldTangentImpulse
'// Apply contact impulse
impulse = tangent.MultEx( tangentImpulse )
b1.velocity = SubVec2Vec2( b1.velocity, impulse.MultEx( b1.invMass ) )
b1.angularVelocity :- b1.invI * CrossVec2Vec2( r1, impulse )
b2.velocity = SubVec2Vec2( b2.velocity, impulse.MultEx( b2.invMass ) )
b2.angularVelocity :+ b2.invI * CrossVec2Vec2( r2, impulse )
Next
End Method
End Type
body.bmx
Rem
* Copyright (c) 2006 Erin Catto http://www.gphysics.com"
*
* Permission To use, copy, modify, distribute And sell this software
* And its documentation For any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software For any purpose.
* It is provided "as is" without express Or implied warranty.
End Rem
'/**
' *
' */
Function Body:TBody()
Local b:Tbody = New TBody
b.position.Set(0.0, 0.0)
b.rotation = 0.0
b.velocity.Set(0.0, 0.0)
b.angularVelocity = 0.0
b.force.Set(0.0, 0.0)
b.torque = 0.0
b.friction = 0.2
b.width.Set(1.0, 1.0)
b.mass = FLT_MAX
b.invMass = 0.0
b.I = FLT_MAX
b.invI = 0.0
Return New TBody
End Function
'/**
' *
' */
Type TBody
Field position:TVec2
Field rotation:Float
Field velocity:TVec2
Field angularVelocity:Float
Field force:TVec2
Field torque:Float
Field width:TVec2
Field friction:Float
Field mass:Float, invMass:Float
Field I:Float, invI:Float
Method New()
position = New TVec2
velocity = New TVec2
force = New TVec2
width = New TVec2
End Method
Method Set(w:TVec2, m:Float)
position.Set(0.0, 0.0)
rotation = 0.0
velocity.Set(0.0, 0.0)
angularVelocity = 0.0
force.Set(0.0, 0.0)
torque = 0.0
friction = 0.2
width = w
mass = m
If (mass < FLT_MAX)
invMass = 1.0 / mass
I = mass * (width.x * width.x + width.y * width.y) / 12.0
invI = 1.0 / I
Else
invMass = 0.0
I = FLT_MAX
invI = 0.0
End If
End Method
Method AddForce (f:TVec2)
force.AddV(f)
End Method
End Type
joint.bmx
Rem
* Copyright (c) 2006 Erin Catto http://www.gphysics.com"
*
* Permission To use, copy, modify, distribute And sell this software
* And its documentation For any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software For any purpose.
* It is provided "as is" without express Or implied warranty.
End Rem
Function Joint:TJoint ()
Return New TJoint
End Function
Type TJoint
Field M:TMat22
Field localAnchor1:TVec2, localAnchor2:TVec2
Field r1:TVec2, r2:TVec2
Field bias:TVec2
Field accumulatedImpulse:TVec2
Field body1:TBody
Field body2:TBody
Field relaxation:Float
Method New()
AccumulatedImpulse = New TVec2
Relaxation = 1.0
End Method
Method Set (b1:TBody, b2:TBody, anchor:TVec2)
body1 = b1
body2 = b2
Local Rot1:TMat22 = Mat22_Angle(body1.rotation)
Local Rot2:TMat22 = Mat22_Angle(body2.rotation)
Local Rot1T:TMat22 = Rot1.Transpose()
Local Rot2T:TMat22 = Rot2.Transpose()
localAnchor1 = MultMat22Vec2(Rot1T, SubVec2Vec2(anchor, body1.position))
localAnchor1 = MultMat22Vec2(Rot2T, SubVec2Vec2(anchor, body2.position))
accumulatedImpulse.Set(0.0, 0.0)
relaxation = 1.0
End Method
Method PreStep(inv_dt:Float)
' Pre-compute anchors, mass matrix, And bias.
Local Rot1:TMat22 = Mat22_Angle(body1.rotation)
Local Rot2:TMat22 = Mat22_Angle(body2.rotation)
r1 = MultMat22Vec2(Rot1, localAnchor1)
r2 = MultMat22Vec2(Rot2, localAnchor2)
' deltaV = deltaV0 + K * impulse
' invM = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
' = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
' [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
Local K1:TMat22 = New TMat22
K1.col1.x = body1.invMass + body2.invMass; K1.col2.x = 0.0
K1.col1.y = 0.0; K1.col2.y = body1.invMass + body2.invMass
Local K2:TMat22
K2.col1.x = body1.invI * r1.y * r1.y; K2.col2.x = -body1.invI * r1.x * r1.y
K2.col1.y = -body1.invI * r1.x * r1.y; K2.col2.y = body1.invI * r1.x * r1.x
Local K3:TMat22
K3.col1.x = body2.invI * r2.y * r2.y; K3.col2.x = -body2.invI * r2.x * r2.y;
K3.col1.y = -body2.invI * r2.x * r2.y; K3.col2.y = body2.invI * r2.x * r2.x;
Local K:TMat22 = AddMat22Mat22(AddMat22Mat22(K1, K2), K3)
M = K.Invert()
Local p1:TVec2 = AddVec2Vec2(body1.position, r1)
Local p2:TVec2 = AddVec2Vec2(body2.position, r2)
Local dp:TVec2 = SubVec2Vec2(p2, p1)
bias = MultFloatVec2((-0.1 * inv_dt), dp)
'Apply accumulated impulse.
accumulatedImpulse.Mult(relaxation)
body1.velocity.SubV(MultFloatVec2(body1.invMass, accumulatedImpulse))
body1.angularVelocity :- body1.invI * CrossVec2Vec2(r1, accumulatedImpulse)
body2.velocity.AddV(MultFloatVec2(body2.invMass, accumulatedImpulse))
body2.angularVelocity :+ body2.invI * CrossVec2Vec2(r2, accumulatedImpulse)
End Method
Method ApplyImpulse()
Local dv:TVec2 = AddVec2Vec2(body2.velocity, CrossFloatVec2(body2.angularVelocity, r2))
dv.SubV(SubVec2Vec2(body1.velocity, CrossFloatVec2(body1.angularVelocity, r1)))
Local impulse:TVec2 = MultMat22Vec2(M, AddVec2Vec2(dv.Reverse(), bias))
body1.velocity.SubV(MultFloatVec2(body1.invMass,impulse))
body1.angularVelocity :- body1.invI * CrossVec2Vec2(r1, impulse)
body2.velocity.AddV(MultFloatVec2(body2.invMass, impulse))
body2.angularVelocity :+ body2.invI * CrossVec2Vec2(r2, impulse)
accumulatedImpulse.AddV(impulse)
End Method
End Type
world.bmx
Rem
* Copyright (c) 2006 Erin Catto <a href="http://www.gphysics.com" target="_blank">www.gphysics.com</a>
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software for any purpose.
* It is provided "as is" without express or implied warranty.
End Rem
Function World:TWorld (gravity:TVec2, iterations:Int)
Local w:TWorld = New TWorld
w.gravity = gravity
w.iterations = iterations
Return w
End Function
Type TWorld
Field Bodies:TList
Field Joints:TList
Field Arbiters:TList
Field Gravity:TVec2
Field iterations:Int
Method New()
Bodies = CreateList()
Joints = CreateList()
Arbiters = CreateList()
Gravity = Vec2(0.0,0.0)
End Method
Method Add ( obj:Object )
If TBody(obj) Bodies.AddLast(obj)
If TJoint(obj) Joints.AddLast(obj)
End Method
Method Clear()
Bodies.Clear
Joints.Clear
Arbiters.Clear
End Method
Method BroadPhase()
' O(n^2) broad-phase
Local BodiesArray:Object [] = Bodies.ToArray()
For Local i:Int = 0 To BodiesArray.Length - 1
Local bi:Tbody = TBody(BodiesArray[i])
For Local j:Int = i + 1 To BodiesArray.Length - 1
Local bj:TBody = TBody(BodiesArray[j])
If (bi.invMass = 0.0 And bj.invMass = 0.0) Continue
Local newArb:TArbiter = Arbiter(bi, bj)
If (newArb.numContacts > 0)
'Not sure what is being accomplished here:
Local arb:TLink = Arbiters.FindLink(newArb)
'ArbIter arb = arbiters.find(newArb)
If (arb = Arbiters.LastLink())
Arbiters.AddLast(newArb)
Else
TArbiter(arb.Value()).Update(newArb.contacts, newArb.numContacts)
End If
Else
Arbiters.Remove(newArb)
End If
Next
Next
End Method
Method _Step (dt:Float)
Local inv_dt:Float
If dt > 0.0 Then inv_dt = 1.0 / dt Else inv_dt = 0.0
BroadPhase()
Local BodiesArray:Object [] = Bodies.ToArray()
For Local i:Int = 0 To BodiesArray.Length -1
Local b:TBody = TBody(BodiesArray[i])
If (b.invMass = 0.0) Continue
b.velocity.AddV(MultFloatVec2(dt,(AddVec2Vec2(gravity, MultFloatVec2(b.invMass, b.force)))))
b.angularVelocity :+ dt * b.invI * b.torque
Next
For Local arb:TArbiter = EachIn Arbiters
arb.PreStep(inv_dt)
Next
Local JointsArray:Object [] = Bodies.ToArray()
For Local i:Int = 0 To JointsArray.Length - 1
TJoint(JointsArray[i]).PreStep(inv_dt)
Next
For Local i:Int = 0 To iterations
For Local arb:TArbiter = EachIn Arbiters
arb.ApplyImpulse()
Next
For Local j:Int = 0 To JointsArray.Length - 1
TJoint(JointsArray[j]).ApplyImpulse()
Next
Next
For Local i:Int = 0 To BodiesArray.Length - 1
Local b:TBody = TBody(BodiesArray[i])
b.position.AddV(MultFLoatVec2(dt,b.velocity))
b.rotation :+ dt * b.angularVelocity
b.force.Set(0.0, 0.0)
b.torque = 0.0
Next
End Method
End Type
mathutils.bmx
Rem
* Copyright (c) 2006 Erin Catto <a href="http://www.gphysics.com" target="_blank">www.gphysics.com</a>
*
* Permission To use, copy, modify, distribute And sell this software
* And its documentation For any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software For any purpose.
* It is provided "as is" without express Or implied warranty.
End Rem
Const FLT_MAX:Float = 10^37
Function Vec2:TVec2 (_x:Float, _y:Float) 'Constructor
Local v:TVec2 = New TVec2
v.X = _x
v.Y = _y
Return v
End Function
Type TVec2
Field x:Float, y:Float
Method Set(_x:Float, _y:Float)
X = _x
Y = _y
End Method
Method Reverse:TVec2() '-()
Return Vec2(-X, -Y)
End Method
Method AddV(v:TVec2) '+=
X :+ v.X
y :+ v.Y
End Method
Method SubV(v:TVec2) '-=
X :- v.X
y :- v.Y
End Method
Method Mult(a:Float) '*=
x :* a
y :* a
End Method
Method Neg( )
x =-x
y =-y
End Method
Method MultEx:TVec2( a:Float )
Local nVec2:TVec2 = New TVec2
nVec2.x = x*a
nVec2.y = y*a
Return nVec2
End Method
Method NegEx:TVec2( )
Local nVec2:TVec2 = New TVec2
nVec2.x =-x
nVec2.y =-y
Return nVec2
End Method
Method Length:Float ()
Return Sqr(X * X + Y * Y)
End Method
End Type
Function Mat22:TMat22(_col1:TVec2,_col2:TVec2) 'Constructor
Local m:TMat22 = New TMat22
m.col1 = _col1
m.col2 = _col2
Return m
End Function
Function Mat22_Angle:TMat22(angle:Float) 'Constructor from angle
Local m:TMat22 = New TMat22
Local c:Float = Float(Cos(angle)), s:Float = Float(Sin(angle))
m.col1.X = c
m.col2.X = -s
m.col1.Y = s
m.col2.Y = c
Return m
End Function
Type TMat22
Field col1:TVec2
Field col2:TVec2
Method New()
col1 = New TVec2
col2 = New TVec2
End Method
Method Transpose:TMat22()
Return Mat22(Vec2(col1.X, col2.X), Vec2(col1.Y, col2.Y))
End Method
Method Invert:TMat22()
Local a:Float = col1.x, b:Float = col2.x, c:Float = col1.y, d:Float = col2.y
Local E:TMat22
Local det:Float = a * d - b * c
Assert (det <> 0.0),"Error: Type Mat22>Invert"
det = 1.0 / det
E.col1.X = det * d
E.col2.x = -det * b
E.col1.Y = -det * c
E.col2.y = det * a
Return E
End Method
End Type
Function Dot:Float(a:TVec2, b:TVec2)
Return a.X * b.X + a.X * b.X
End Function
Function CrossVec2Vec2:Float(a:TVec2, b:TVec2)
Return a.X * b.Y - a.Y * b.X
End Function
Function CrossVec2Float:TVec2(a:TVec2, s:Float)
Return Vec2(s * a.Y, -s * a.X)
End Function
Function CrossFloatVec2:TVec2(s:Float, a:TVec2)
Return Vec2(-s * a.Y, s * a.X)
End Function
Function MultMat22Vec2:TVec2 (A:TMat22, v:TVec2)
Return Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y)
End Function
Function AddVec2Vec2:TVec2 (a:TVec2, b:TVec2)
Return Vec2(a.x + b.x, a.y + b.y)
End Function
Function SubVec2Vec2:TVec2 (a:TVec2, b:TVec2)
Return Vec2(a.x - b.x, a.y - b.y)
End Function
Function MultFloatVec2:TVec2 (s:Float, v:TVec2)
Return Vec2(s * v.x, s * v.y)
End Function
Function AddMat22Mat22:TMat22 (A:TMat22, B:TMat22)
Return Mat22(AddVec2Vec2(A.col1, B.col1), AddVec2Vec2(A.col2, B.col2))
End Function
Function MultMat22Mat22:TMat22 (A:TMat22, B:TMat22)
Return Mat22(MultMat22Vec2(A, B.col1), MultMat22Vec2(A, B.col2))
End Function
Function AbsoluteVec2:TVec2(a:TVec2)
Return Vec2(Abs(a.x), Abs(a.y))
End Function
Function AbsoluteMat22:TMat22 (A:TMat22)
Return Mat22(AbsoluteVec2(A.col1), AbsoluteVec2(A.col2))
End Function
Function Sign:Float(x:Float)
Return Sgn(x)
End Function
Function MinFloat:Float(a:Float, b:Float)
If a < b Return a Else Return b
End Function
Function MaxFloat:Float(a:Float, b:Float)
If a > b Return a Else Return b
End Function
Function ClampFloat:Float(a:Float, low:Float, high:Float)
Return MaxFloat(low, MinFloat(a, high))
End Function
Function Swap(a:Object, b:Object)
Local tmp:Object = a
a = b
b = tmp
End Function
' Random number in range [-1,1]
Function Random:Float()
Return Float(Rnd(-1,1))
End Function
Function Random2:Float(lo:Float, hi:Float)
Return Float(Rnd(lo,hi))
End Function
main.bmx
Rem
* Copyright (c) 2006 Erin Catto http://www.gphysics.com"
*
* Permission To use, copy, modify, distribute And sell this software
* And its documentation For any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software For any purpose.
* It is provided "as is" without express Or implied warranty.
End Rem
SuperStrict
Include "Source\MathUtils.bmx"
Include "Source\Arbiter.bmx"
Include "Source\Body.bmx"
Include "Source\Collide.bmx"
Include "Source\Joint.bmx"
Include "Source\World.bmx"
Graphics 800,600
Global DeltaTime:Float = 1.0 / 60.0
Global _World:TWorld = World(Vec2(0.0, -10.0), 10)
Global Bomb:TBody
'* Demo 1 "A single box"
Local Ground:TBody = Body()
Ground.Set(Vec2(100.0, 20.0), FLT_MAX)
Ground.Position.Set(0.0, -0.5 * Ground.Width.Y)
_World.Add(Ground)
Local Box:TBody = Body()
Box.Set(Vec2(1.0, 1.0), 100.0)
Box.position.Set(0.0, 4.0)
_World.Add(Box)
While Not KeyHit(KEY_ESCAPE)
If KeyHit(KEY_SPACE)
LaunchBomb
End If
Cls
_World._Step(DeltaTime)
For Local b:TBody = EachIn _World.bodies
DrawBody(b)
Next
For Local j:TJoint = EachIn _World.joints
DrawJoint(j)
Next
DrawText("Demo 1",0,0)
DrawText("Press Space to Launch the Bomb",0,15)
Flip
Wend
Function DrawBody (body:Tbody)
Local R:TMat22 = Mat22_Angle(body.rotation)
Local x:TVec2 = body.Position
Local h:TVec2 = MultFloatVec2(0.5, body.width)
Local v1:TVec2 = AddVec2Vec2(x, MultMat22Vec2(R, Vec2(-h.x, -h.y)))
Local v2:TVec2 = AddVec2Vec2(x, MultMat22Vec2(R, Vec2(h.x, -h.y)))
Local v3:TVec2 = AddVec2Vec2(x, MultMat22Vec2(R, Vec2(h.x, h.y)))
Local v4:TVec2 = AddVec2Vec2(x, MultMat22Vec2(R, Vec2(-h.x, h.y)))
If (body = Bomb)
SetColor 128,255,128
Else
SetColor 200,200,255
End If
DrawLine v1.x, v1.y, v2.x, v2.y
DrawLine v2.x, v2.y, v3.x, v3.y
DrawLine v3.x, v3.y, v4.x, v4.y
DrawLine v4.x, v4.y, v1.x, v1.y
End Function
Function DrawJoint (joint:TJoint)
Local b1:TBody = joint.body1
Local b2:TBody = joint.body2
Local R1:TMat22 Mat22_Angle(b1.rotation)
Local R2:TMat22 Mat22_Angle(b2.rotation)
Local x1:TVec2 = b1.position
Local p1:TVec2 = AddVec2Vec2(x1, MultMat22Vec2(R1, joint.localAnchor1))
Local x2:TVec2 = b2.position
Local p2:TVec2 = AddVec2Vec2(x2, MultMat22Vec2(R2, joint.localAnchor2))
SetColor 128,128,200
DrawLine x1.x, x1.y, p1.x, p1.y
DrawLine p1.x, p1.y, x2.x, x2.y
DrawLine x2.x, x2.y, p2.x, p2.y
DrawLine p2.x, p2.y, x1.x, x1.y
End Function
Function LaunchBomb ()
If (Not bomb)
Bomb = Body()
Bomb.Set(Vec2(1.0, 1.0), 50.0)
Bomb.Friction = 0.2
_World.Add(Bomb)
End If
Bomb.position.Set(Random2(-15.0, 15.0), 15.0)
Bomb.rotation = Random2(-1.5, 1.5)
Bomb.velocity = MultFloatVec2(-1.5, Bomb.position)
Bomb.angularVelocity = Random2(-20.0, 20.0)
End Function
collide.bmx
Rem
* Copyright (c) 2006 Erin Catto http://www.gphysics.com"
*
* Permission To use, copy, modify, distribute And sell this software
* And its documentation For any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies.
* Erin Catto makes no representations about the suitability
* of this software For any purpose.
* It is provided "as is" without express Or implied warranty.
End Rem
'/**
' *
' */
Type TAxis
Const FACE_A_X:Int = 1
Const FACE_A_Y:Int = 2
Const FACE_B_X:Int = 3
Const FACE_B_Y:Int = 4
End Type
'/**
' *
' */
'Type EdgeNumbers
Const NO_EDGE:Int = 0
Const EDGE1:Int = 1
Const EDGE2:Int = 2
Const EDGE3:Int = 3
Const EDGE4:Int = 4
'End Type
'/**
' *
' */
Type TClipVertex
Field v:TVec2
Field fp:TFeaturePair
End Type
'/**
' *
' */
Function _Flip( fp:TFeaturePair )
'Swap( fp.e[ inEdge1 ], fp.e[ inEdge2 ] )
'Swap( fp.e[outEdge1 ], fp.e[outEdge2 ] )
End Function
'/**
' *
' */
Function ClipSegmentToLine:Int( vOut:TClipVertex[], vIn:TClipVertex[], normal:TVec2, Offset:Float, ClipEdge:Int )
'// Start with no output points
Local numOut:Int = 0
'// Calculate the distance of end points to the line
Local distance0:Float = Dot( normal, vIn[0].v ) - Offset
Local distance1:Float = Dot( normal, vIn[1].v ) - Offset
'// If the points are behind the plane
If ( distance0 <= 0 ) vOut[numOut] = vIn[0];
If ( distance1 <= 0 ) vOut[numOut+1] = vIn[1];
numOut :+2
'// If the points are on different sides of the plane
If ( distance0 * distance1 < 0 )
'// Find intersection point of edge and plane
Local interp:Float = distance0 / (distance0 - distance1)
vOut[numOut].v = subVec2Vec2( vIn[1].v, vIn[0].v ).MultEx( interp )
vOut[numOut].v = addVec2Vec2( vIn[0].v, vOut[numOut].v )
If ( distance0 > 0 )
vOut[numOut].fp = vIn[0].fp;
vOut[numOut].fp.e[inEdge1] = clipEdge
vOut[numOut].fp.e[inEdge2] = NO_EDGE
Else
vOut[numOut].fp = vIn[1].fp
vOut[numOut].fp.e[outEdge1] = clipEdge
vOut[numOut].fp.e[outEdge2] = NO_EDGE
EndIf
numOut :+1
EndIf
Return numOut
End Function
'/**
' *
' */
Function ComputeIncidentEdge( c:TClipVertex[], h:TVec2, Pos:TVec2, Rot:TMat22, normal:TVec2 )
'// The normal is from the reference box. Convert it
'// to the incident boxe's frame and flip sign.
Local RotT:TMat22 = Rot.Transpose( )
Local n:TVec2 = MultMat22Vec2( RotT, normal )
n.Neg( )
Local nAbs:TVec2 = AbsoluteVec2( n )
If ( nAbs.x > nAbs.y )
If ( Sign( n.x ) > 0 )
c[0].v.Set( h.x, -h.y )
c[0].fp.e[inEdge2] = EDGE3
c[0].fp.e[outEdge2] = EDGE4
c[1].v.Set( h.x, h.y )
c[1].fp.e[inEdge2] = EDGE4
c[1].fp.e[outEdge2] = EDGE1
Else
c[0].v.Set( -h.x, h.y )
c[0].fp.e[inEdge2] = EDGE1
c[0].fp.e[outEdge2] = EDGE2
c[1].v.Set( -h.x, -h.y )
c[1].fp.e[inEdge2] = EDGE2
c[1].fp.e[outEdge2] = EDGE3
EndIf
Else
If ( Sign(n.y) > 0 )
c[0].v.Set( h.x, h.y )
c[0].fp.e[inEdge2] = EDGE4
c[0].fp.e[outEdge2] = EDGE1
c[1].v.Set( -h.x, h.y )
c[1].fp.e[inEdge2] = EDGE1
c[1].fp.e[outEdge2] = EDGE2
Else
c[0].v.Set( -h.x, -h.y )
c[0].fp.e[inEdge2] = EDGE2
c[0].fp.e[outEdge2] = EDGE3
c[1].v.Set( h.x, -h.y )
c[1].fp.e[inEdge2] = EDGE3
c[1].fp.e[outEdge2] = EDGE4
EndIf
EndIf
' c[0].v = Pos + Rot * c[0].v
' c[1].v = Pos + Rot * c[1].v
End Function
'/**
' *
' */
Function Collide:Int( contacts:TContact, bodyA:TBody, bodyB:TBody )
'// Setup
Local hA:TVec2 = bodyA.width.MultEx( 0.5 )
Local hB:TVec2 = bodyB.width.MultEx( 0.5 )
Local posA:TVec2 = bodyA.position
Local posB:TVec2 = bodyB.position
Local RotA:TMat22 = MAT22_Angle( bodyA.rotation )
Local RotB:TMat22 = MAT22_Angle( bodyB.rotation )
Local RotAT:TMat22 = RotA.Transpose( )
Local RotBT:TMat22 = RotB.Transpose( )
Local a1:TVec2 = RotA.col1
Local a2:TVec2 = RotA.col2
Local b1:TVec2 = RotB.col1
Local b2:TVec2 = RotB.col2
Local dp:TVec2 = SubVec2Vec2( posB, posA )
Local dA:TVec2 = MultMat22Vec2( RotAT, dp )
Local dB:TVec2 = MultMat22Vec2( RotBT, dp )
Local C:TMat22 = MultMat22Mat22( RotAT, RotB )
Local absC:TMat22 = AbsoluteMat22( C )
Local absCT:TMat22 = absC.Transpose()
'// Box A faces
Local faceA:TVec2 = AbsoluteVec2( dA )' - hA - absC * hB
If (faceA.x > 0 Or faceA.y > 0)
Return 0
EndIf
'// Box B faces
Local faceB:TVec2 = AbsoluteVec2( dB )' - absCT * hA - hB
If (faceB.x > 0 Or faceB.y > 0)
Return 0
EndIf
'// Find best axis
Local axis:Int
Local separation:Float
Local normal:TVec2
'// Box A faces
axis = TAxis.FACE_A_X
separation = faceA.x
If ( dA.x > 0 )
normal = RotA.col1
Else
normal = RotA.col1.NegEx( )
EndIf
If (faceA.y > (1.05 * separation + 0.01 * hA.y))
axis = TAxis.FACE_A_Y
separation = faceA.y
If (dA.y > 0)
normal = RotA.col2
Else
normal = RotA.col2.NegEx( )
EndIf
EndIf
'// Box B faces
If (faceB.x > (1.05 * separation + 0.01 * hB.x))
axis = TAxis.FACE_B_X
separation = faceB.x
If (dB.x > 0)
normal = RotB.col1
Else
normal = RotB.col1.NegEx( )
EndIf
EndIf
If (faceB.y > 1.05 * separation + 0.01 * hB.y)
axis = TAxis.FACE_B_Y
separation = faceB.y;
If (dB.y > 0.0)
normal = RotB.col2
Else
normal = RotB.col2.NegEx( )
EndIf
EndIf
Rem
'// Setup clipping plane data based on the separating axis
Local frontNormal:TVec2
Local sideNormal:TVec2
Local incidentEdge:TClipVertex[2]
Local front:Float, negSide:Float, posSide:Float
Local negEdge:Byte, posEdge:Byte
'// Compute the clipping lines And the line segment To be clipped
Select (axis)
Case TAxis.FACE_A_X
frontNormal = normal
front = Dot(posA, frontNormal) + hA.x
sideNormal = RotA.col2
Float side = Dot(posA, sideNormal)
negSide = -side + hA.y
posSide = side + hA.y
negEdge = EDGE3
posEdge = EDGE1
ComputeIncidentEdge(incidentEdge, hB, posB, RotB, frontNormal)
Case TAxis.FACE_A_Y
frontNormal = normal
front = Dot(posA, frontNormal) + hA.y
sideNormal = RotA.col1
Float side = Dot(posA, sideNormal)
negSide = -side + hA.x
posSide = side + hA.x
negEdge = EDGE2
posEdge = EDGE4
ComputeIncidentEdge(incidentEdge, hB, posB, RotB, frontNormal)
Case TAxis.FACE_B_X
frontNormal = -normal
front = Dot(posB, frontNormal) + hB.x
sideNormal = RotB.col2
Float side = Dot(posB, sideNormal)
negSide = -side + hB.y
posSide = side + hB.y
negEdge = EDGE3
posEdge = EDGE1
ComputeIncidentEdge( incidentEdge, hA, posA, RotA, frontNormal )
Case TAxis.FACE_B_Y
frontNormal = -normal
front = Dot(posB, frontNormal) + hB.y
sideNormal = RotB.col1
Float side = Dot(posB, sideNormal)
negSide = -side + hB.x
posSide = side + hB.x
negEdge = EDGE2
posEdge = EDGE4
ComputeIncidentEdge( incidentEdge, hA, posA, RotA, frontNormal )
End Select
'// clip other face with 5 box planes (1 face plane, 4 edge planes)
Local clipPoints1:TClipVertex[2]
Local clipPoints2:TClipVertex[2]
Local np:Int
'// Clip To box side 1
np = ClipSegmentToLine( clipPoints1, incidentEdge,-sideNormal, negSide, negEdge )
If (np < 2)
Return 0
EndIf
'// Clip To negative box side 1
np = ClipSegmentToLine( clipPoints2, clipPoints1, sideNormal, posSide, posEdge )
If (np < 2)
Return 0
EndIf
'// Now clipPoints2 contains the clipping points.
'// Due To roundoff, it is possible that clipping removes all points.
Local numContacts:Int = 0, i:Int
For i = 0 To 1
Local separation:Float = Dot( frontNormal, clipPoints2[i].v ) - front
If (separation <= 0)
contacts[numContacts].separation = separation
contacts[numContacts].normal = normal
'// slide contact point onto reference face (easy To cull)
contacts[numContacts].position = clipPoints2[i].v - separation * frontNormal
contacts[numContacts].feature = clipPoints2[i].fp
If ((axis = FACE_B_X) Or (axis = FACE_B_Y))
_Flip(contacts[numContacts].feature)
EndIf
numContacts:+1
EndIf
Next
Return numContacts
End Rem
End Function
Oh yeah, and merry christmas :)