' Display
_TITLE "Collisions - Version 9"
' Meta
start:
' Data structures
' Object type
' Object storage
' Dynamics
' Environment
' Initialize
ShapeCount = 0
CollisionCount = 0
' Prompt
CALL cprintstring
(16 * 17, "WELCOME! ") CALL cprintstring
(16 * 16, "Press 1 for Pool prototype ") CALL cprintstring
(16 * 15, "Press 2 for Wacky game ") CALL cprintstring
(16 * 14, "Press 3 for Concentric rings") CALL cprintstring
(16 * 13, "Press 4 for Walls only ") CALL cprintstring
(16 * 12, "Press 5 for Angle pong game ")
CALL cprintstring
(-16 * 4, "During Play:") CALL cprintstring
(-16 * 6, "Move mouse to select closest object (by centroid).") CALL cprintstring
(-16 * 7, "Boost velocity with arrow keys or W/S/A/D. ") CALL cprintstring
(-16 * 8, "Boost angluar velocity with Q/E. ") CALL cprintstring
(-16 * 9, "Drag and fling object with Mouse 1. ") CALL cprintstring
(-16 * 10, "Rotate selected object with Mousewheel. ") CALL cprintstring
(-16 * 11, "Halt all motion with ESC. ") CALL cprintstring
(-16 * 12, "Create new ball with Mouse 2. ") CALL cprintstring
(-16 * 13, "Initiate creative mode with SPACE. ") CALL cprintstring
(-16 * 14, "Restart by pressing R during motion. ") CALL cprintstring
(-16 * 16, "PRESS ANY KEY TO BEGIN.")
' Main loop
CALL PairDynamics
(CPC
, FPC
, RST
) CALL FleetDynamics
(VD
, SV
)
TheReturn = 0
' Keyboard input
CALL cprintstring
(16 * 17, "Drag Mouse 1 counter-clockwise to draw a new shape.") CALL cprintstring
(16 * 16, "Make sure centroid is inside body. ") CALL NewMouseShape
(7.5, 150, 15) Shape(SelectedShape).Velocity.y = Shape(SelectedShape).Velocity.y * 1.05 + 1.5
Shape(SelectedShape).Velocity.y = Shape(SelectedShape).Velocity.y * 0.95 - 1.5
Shape(SelectedShape).Velocity.x = Shape(SelectedShape).Velocity.x * 0.95 - 1.5
Shape(SelectedShape).Velocity.x = Shape(SelectedShape).Velocity.x * 1.05 + 1.5
Shape(SelectedShape).Omega = Omega * 0.5 - .02
Shape(SelectedShape).Omega = Omega * 1.5 + .02
TheReturn = -1
Shape
(k
).Velocity.x
= .000001 * (RND - .5) Shape
(k
).Velocity.y
= .000001 * (RND - .5) Shape
(k
).Omega
= .000001 * (RND - .5)
' Mouse input
mb = 0
mxold = 999999999
myold = 999999999
rmin = 999999999
dx = x - Shape(k).Centroid.x
dy = y - Shape(k).Centroid.y
r2 = dx * dx + dy * dy
rmin = r2
SelectedShape = k
mb = 1
vtemp.x = x - Shape(SelectedShape).Centroid.x
vtemp.y = y - Shape(SelectedShape).Centroid.y
CALL TranslateShape
(SelectedShape
, vtemp
) Shape(SelectedShape).Velocity.x = 0
Shape(SelectedShape).Velocity.y = 0
Shape(SelectedShape).Omega = 0
mxold = x
myold = y
mb = 1
CALL NewAutoBall
(x
, y
, 15, 0, 1, 1, 0) CALL RotShape
(SelectedShape
, Shape
(SelectedShape
).Centroid
, -.02 * 8 * ATN(1)) CALL RotShape
(SelectedShape
, Shape
(SelectedShape
).Centroid
, .02 * 8 * ATN(1)) IF ((mxold
<> 999999999) AND (myold
<> 999999999)) THEN Shape(SelectedShape).Velocity.x = x - mxold
Shape(SelectedShape).Velocity.y = y - myold
UserInput = TheReturn
SUB PairDynamics
(CoarseProximityConstant
, FineProximityConstant
, Restitution
)
' Proximity detection
ProximalPairsCount = 0
Shape1 = 0
Shape2 = 0
Shape(j).CollisionSwitch = 0
Shape(j).DeltaO = 0
Shape(j).DeltaV.x = 0
Shape(j).DeltaV.y = 0
Shape(j).PartialNormal.x = 0
Shape(j).PartialNormal.y = 0
FOR k
= j
+ 1 TO ShapeCount
dx = Shape(j).Centroid.x - Shape(k).Centroid.x
dy = Shape(j).Centroid.y - Shape(k).Centroid.y
dr
= SQR(dx
* dx
+ dy
* dy
) IF (dr
< (CoarseProximityConstant
) * (Shape
(j
).Diameter
+ Shape
(k
).Diameter
)) THEN ProximalPairsCount = ProximalPairsCount + 1
ProximalPairs(ProximalPairsCount, 1) = j
ProximalPairs(ProximalPairsCount, 2) = k
Shape1 = j
Shape2 = k
IF (ProximalPairsCount
> 0) THEN FOR n
= 1 TO ProximalPairsCount
Shape1 = ProximalPairs(n, 1)
Shape2 = ProximalPairs(n, 2)
' Collision detection
rmin = 999999999
ClosestIndex1 = 0
ClosestIndex2 = 0
NumJK = 0
FOR j
= 1 TO Shape
(Shape1
).Elements
FOR k
= 1 TO Shape
(Shape2
).Elements
dx = PointChain(Shape1, j).x - PointChain(Shape2, k).x
dy = PointChain(Shape1, j).y - PointChain(Shape2, k).y
r2 = dx * dx + dy * dy
IF (r2
<= FineProximityConstant
) THEN
' Partial normal vector 1
nx1 = CalculateNormalY(Shape1, j)
ny1 = -CalculateNormalX(Shape1, j)
nn
= SQR(nx1
* nx1
+ ny1
* ny1
) nx1 = nx1 / nn
ny1 = ny1 / nn
Shape(Shape1).PartialNormal.x = Shape(Shape1).PartialNormal.x + nx1
Shape(Shape1).PartialNormal.y = Shape(Shape1).PartialNormal.y + ny1
' Partial normal vector 2
nx2 = CalculateNormalY(Shape2, k)
ny2 = -CalculateNormalX(Shape2, k)
nn
= SQR(nx2
* nx2
+ ny2
* ny2
) nx2 = nx2 / nn
ny2 = ny2 / nn
Shape(Shape2).PartialNormal.x = Shape(Shape2).PartialNormal.x + nx2
Shape(Shape2).PartialNormal.y = Shape(Shape2).PartialNormal.y + ny2
NumJK = NumJK + 1
GrossJ(NumJK) = j
GrossK(NumJK) = k
rmin = r2
ClosestIndex1 = j
ClosestIndex2 = k
IF ((GrossJ
(1) - GrossJ
(NumJK
)) * (GrossJ
(1) - GrossJ
(NumJK
)) > 50) THEN 'ClosestIndex1 = 1
ClosestIndex1
= INT(IntegrateArray
(GrossJ
(), NumJK
) / NumJK
) IF ((GrossK
(1) - GrossK
(NumJK
)) * (GrossK
(1) - GrossK
(NumJK
)) > 50) THEN 'ClosestIndex2 = 1
ClosestIndex2
= INT(IntegrateArray
(GrossK
(), NumJK
) / NumJK
)
IF (rmin
<= FineProximityConstant
) THEN
CollisionCount = CollisionCount + 1
Shape(Shape1).CollisionSwitch = 1
Shape(Shape2).CollisionSwitch = 1
' Undo previous motion
IF (Shape
(Shape1
).Collisions
= 0) THEN CALL RotShape
(Shape1
, Shape
(Shape1
).Centroid
, -Shape
(Shape1
).Omega
) vtemp.x = -(Shape(Shape1).Velocity.x)
vtemp.y = -(Shape(Shape1).Velocity.y)
CALL TranslateShape
(Shape1
, vtemp
) IF (Shape
(Shape2
).Collisions
= 0) THEN CALL RotShape
(Shape2
, Shape
(Shape2
).Centroid
, -Shape
(Shape2
).Omega
) vtemp.x = -(Shape(Shape2).Velocity.x)
vtemp.y = -(Shape(Shape2).Velocity.y)
CALL TranslateShape
(Shape2
, vtemp
)
' Momentum absorption
IF (Shape
(Shape1
).Collisions
= 0) THEN Shape(Shape1).Velocity.x = Shape(Shape1).Velocity.x * Restitution
Shape(Shape1).Velocity.y = Shape(Shape1).Velocity.y * Restitution
IF (Shape
(Shape2
).Collisions
= 0) THEN Shape(Shape2).Velocity.x = Shape(Shape2).Velocity.x * Restitution
Shape(Shape2).Velocity.y = Shape(Shape2).Velocity.y * Restitution
' Centroid of object 1 (cx1, cy1)
cx1 = Shape(Shape1).Centroid.x
cy1 = Shape(Shape1).Centroid.y
' Centroid of object 2 (cx2, cy2)
cx2 = Shape(Shape2).Centroid.x
cy2 = Shape(Shape2).Centroid.y
' Contact point on object 1 (px1, py1)
px1 = PointChain(Shape1, ClosestIndex1).x
py1 = PointChain(Shape1, ClosestIndex1).y
' Contact point on object 2 (px2, py2)
px2 = PointChain(Shape2, ClosestIndex2).x
py2 = PointChain(Shape2, ClosestIndex2).y
' Contact-centroid differentials 1 (dx1, dy1)
dx1 = px1 - cx1
dy1 = py1 - cy1
' Contact-centroid differentials 2 (dx2, dy2)
dx2 = px2 - cx2
dy2 = py2 - cy2
' Normal vector 1 (nx1, ny1)
nn
= SQR(Shape
(Shape1
).PartialNormal.x
* Shape
(Shape1
).PartialNormal.x
+ Shape
(Shape1
).PartialNormal.y
* Shape
(Shape1
).PartialNormal.y
) nx1 = Shape(Shape1).PartialNormal.x / nn
ny1 = Shape(Shape1).PartialNormal.y / nn
' Normal vector 2 (nx2, ny2)
nn
= SQR(Shape
(Shape2
).PartialNormal.x
* Shape
(Shape2
).PartialNormal.x
+ Shape
(Shape2
).PartialNormal.y
* Shape
(Shape2
).PartialNormal.y
) nx2 = Shape(Shape2).PartialNormal.x / nn
ny2 = Shape(Shape2).PartialNormal.y / nn
'''
'nx1 = CalculateNormalY(Shape1, ClosestIndex1)
'ny1 = -CalculateNormalX(Shape1, ClosestIndex1)
'nn = SQR(nx1 * nx1 + ny1 * ny1)
'nx1 = nx1 / nn
'ny1 = ny1 / nn
'nx2 = CalculateNormalY(Shape2, ClosestIndex2)
'ny2 = -CalculateNormalX(Shape2, ClosestIndex2)
'nn = SQR(nx2 * nx2 + ny2 * ny2)
'nx2 = nx2 / nn
'ny2 = ny2 / nn
'''
' Perpendicular vector 1 (prx1, pry1)
prx1 = -dy1
pry1 = dx1
pp
= SQR(prx1
* prx1
+ pry1
* pry1
) prx1 = prx1 / pp
pry1 = pry1 / pp
' Perpendicular vector 2 (prx2, pry2)
prx2 = -dy2
pry2 = dx2
pp
= SQR(prx2
* prx2
+ pry2
* pry2
) prx2 = prx2 / pp
pry2 = pry2 / pp
' Angular velocity vector 1 (w1, r1, vx1, vy1)
w1 = Shape(Shape1).Omega
r1
= SQR(dx1
* dx1
+ dy1
* dy1
) vx1 = w1 * r1 * prx1
vy1 = w1 * r1 * pry1
' Angular velocity vector 2 (w2, r2, vx2, vy2)
w2 = Shape(Shape2).Omega
r2
= SQR(dx2
* dx2
+ dy2
* dy2
) vx2 = w2 * r2 * prx2
vy2 = w2 * r2 * pry2
' Mass terms (m1, m2, mu)
m1 = Shape(Shape1).Mass
m2 = Shape(Shape2).Mass
mu = 1 / (1 / m1 + 1 / m2)
' Re-Calculate moment of inertia (i1, i2)
vtemp.x = px1
vtemp.y = py1
CALL CalculateMOI
(Shape1
, vtemp
) vtemp.x = px2
vtemp.y = py2
CALL CalculateMOI
(Shape2
, vtemp
) i1 = Shape(Shape1).MOI
i2 = Shape(Shape2).MOI
' Velocity differentials (v1, v2, dvtx, dvty)
vcx1 = Shape(Shape1).Velocity.x
vcy1 = Shape(Shape1).Velocity.y
vcx2 = Shape(Shape2).Velocity.x
vcy2 = Shape(Shape2).Velocity.y
vtx1 = vcx1 + vx1
vty1 = vcy1 + vy1
vtx2 = vcx2 + vx2
vty2 = vcy2 + vy2
v1
= SQR(vtx1
* vtx1
+ vty1
* vty1
) v2
= SQR(vtx2
* vtx2
+ vty2
* vty2
) dvtx = vtx2 - vtx1
dvty = vty2 - vty1
' Geometry (n1dotdvt, n2dotdvt)
n1dotdvt = nx1 * dvtx + ny1 * dvty
n2dotdvt = nx2 * dvtx + ny2 * dvty
' Momentum exchange (qx1, qy1, qx2, qy2)
qx1 = nx1 * 2 * mu * n1dotdvt
qy1 = ny1 * 2 * mu * n1dotdvt
qx2 = nx2 * 2 * mu * n2dotdvt
qy2 = ny2 * 2 * mu * n2dotdvt
' Momentum exchange unit vector (qhat)
qq
= SQR(qx1
* qx1
+ qy1
* qy1
) qhatx1 = qx1 / qq
qhaty1 = qy1 / qq
qq
= SQR(qx2
* qx2
+ qy2
* qy2
) qhatx2 = qx2 / qq
qhaty2 = qy2 / qq
' Angular impulse
q1dotp1 = qx1 * prx1 + qy1 * pry1
q2dotp2 = qx2 * prx2 + qy2 * pry2
' Translational impulse
q1dotn1 = qhatx1 * nx1 + qhaty1 * ny1
q2dotn2 = qhatx2 * nx2 + qhaty2 * ny2
n1dotr1hat = (nx1 * dx1 + ny1 * dy1) / r1
n2dotr2hat = (nx2 * dx2 + ny2 * dy2) / r2
f1 = -q1dotn1 * n1dotr1hat
f2 = -q2dotn2 * n2dotr2hat
' Special case for shape within shape.
np = nx1 * nx2 + ny1 * ny2
dcx = cx1 - cx2
dcy = cy1 - cy2
dc
= SQR(dcx
* dcx
+ dcy
* dcy
) IF (m1
> m2
) THEN ' This criteria may be bullshit in general but works now. q1dotp1 = -q1dotp1
f1 = -f1
q2dotp2 = -q2dotp2
f2 = -f2
' Angular impulse update
Shape(Shape1).DeltaO = Shape(Shape1).DeltaO + r1 * q1dotp1 / i1
Shape(Shape2).DeltaO = Shape(Shape2).DeltaO - r2 * q2dotp2 / i2
' Linear impulse update
dvx1 = f1 * qx1 / m1
dvy1 = f1 * qy1 / m1
dvx2 = f2 * qx2 / m2
dvy2 = f2 * qy2 / m2
dvx1s = dvx1 * dvx1
dvy1s = dvy1 * dvy1
dvx2s = dvx2 * dvx2
dvy2s = dvy2 * dvy2
Shape(Shape1).DeltaV.x = Shape(Shape1).DeltaV.x + dvx1
Shape(Shape1).DeltaV.y = Shape(Shape1).DeltaV.y + dvy1
Shape(Shape2).DeltaV.x = Shape(Shape2).DeltaV.x + dvx2
Shape(Shape2).DeltaV.y = Shape(Shape2).DeltaV.y + dvy2
' External torque
torque1 = m1 * (dx1 * ForceField.y - dy1 * ForceField.x)
torque2 = m2 * (dx2 * ForceField.y - dy2 * ForceField.x)
Shape(Shape1).DeltaO = Shape(Shape1).DeltaO - torque1 / i1
Shape(Shape2).DeltaO = Shape(Shape2).DeltaO - torque2 / i2
' Separate along normal
vtemp.x = -nx1 * 1 * ((v1 + 0.01) / m1)
vtemp.y = -ny1 * 1 * ((v1 + 0.01) / m1)
CALL TranslateShape
(Shape1
, vtemp
) vtemp.x = -nx2 * 1 * ((v2 + 0.01) / m2)
vtemp.y = -ny2 * 1 * ((v2 + 0.01) / m2)
CALL TranslateShape
(Shape2
, vtemp
)
' Dent along normal
'PointChain(Shape1, ClosestIndex1).x = PointChain(Shape1, ClosestIndex1).x - v1 * nx1 / 2
'PointChain(Shape1, ClosestIndex1).y = PointChain(Shape1, ClosestIndex1).y - v1 * ny1 / 2
'PointChain(Shape2, ClosestIndex2).x = PointChain(Shape2, ClosestIndex2).x - v2 * nx2 / 2
'PointChain(Shape2, ClosestIndex2).y = PointChain(Shape2, ClosestIndex2).y - v2 * ny2 / 2
' Feedback
IF (Shape
(Shape1
).Collisions
= 0) AND (Shape
(Shape2
).Collisions
= 0) THEN CALL snd
(100 * (v1
+ v2
) / 2, .5)
SUB FleetDynamics
(MotionDamping
, StoppingVelocity
)
FOR ShapeIndex
= 1 TO ShapeCount
' Contact update
IF (Shape
(ShapeIndex
).CollisionSwitch
= 1) THEN Shape(ShapeIndex).Collisions = Shape(ShapeIndex).Collisions + 1
Shape(ShapeIndex).Collisions = 0
IF (Shape
(ShapeIndex
).Fixed
= 0) THEN
' Angular velocity update
Shape(ShapeIndex).Omega = Shape(ShapeIndex).Omega + Shape(ShapeIndex).DeltaO
' Linear velocity update
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x + Shape(ShapeIndex).DeltaV.x
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y + Shape(ShapeIndex).DeltaV.y
IF (Shape
(ShapeIndex
).Collisions
< 2) THEN ' changed from = 0 ' Freefall (if airborne)
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x + ForceField.x
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y + ForceField.y
' Static friction
IF ((Shape
(ShapeIndex
).Velocity.x
* Shape
(ShapeIndex
).Velocity.x
) < StoppingVelocity
) THEN Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x * .05
IF ((Shape
(ShapeIndex
).Velocity.y
* Shape
(ShapeIndex
).Velocity.y
) < StoppingVelocity
) THEN Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y * .05
IF ((Shape
(ShapeIndex
).Omega
* Shape
(ShapeIndex
).Omega
) < .000015 * StoppingVelocity
) THEN Shape(ShapeIndex).Omega = 0
' Rotation update
CALL RotShape
(ShapeIndex
, Shape
(ShapeIndex
).Centroid
, Shape
(ShapeIndex
).Omega
)
' Position update
CALL TranslateShape
(ShapeIndex
, Shape
(ShapeIndex
).Velocity
)
' Motion Damping
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x * MotionDamping
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y * MotionDamping
Shape(ShapeIndex).Omega = Shape(ShapeIndex).Omega * MotionDamping
' Lock all motion
Shape(ShapeIndex).Velocity.x = 0
Shape(ShapeIndex).Velocity.y = 0
Shape(ShapeIndex).Omega = 0
FOR ShapeIndex
= 1 TO ShapeCount
FOR i
= 1 TO Shape
(ShapeIndex
).Elements
- 1 CALL cpset
(PointChain
(ShapeIndex
, i
).x
, PointChain
(ShapeIndex
, i
).y
, Shape
(ShapeIndex
).Shade
) CALL cline
(PointChain
(ShapeIndex
, i
).x
, PointChain
(ShapeIndex
, i
).y
, PointChain
(ShapeIndex
, i
+ 1).x
, PointChain
(ShapeIndex
, i
+ 1).y
, Shape
(ShapeIndex
).Shade
) IF (ShapeIndex
= SelectedShape
) THEN CALL ccircle
(PointChain
(ShapeIndex
, i
).x
, PointChain
(ShapeIndex
, i
).y
, 1, Shape
(ShapeIndex
).Shade
) CALL cpset
(PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).x
, PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).y
, Shape
(ShapeIndex
).Shade
) CALL cline
(PointChain
(ShapeIndex
, 1).x
, PointChain
(ShapeIndex
, 1).y
, PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).x
, PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).y
, Shape
(ShapeIndex
).Shade
) CALL cline
(Shape
(ShapeIndex
).Centroid.x
, Shape
(ShapeIndex
).Centroid.y
, PointChain
(ShapeIndex
, 1).x
, PointChain
(ShapeIndex
, 1).y
, Shape
(ShapeIndex
).Shade
) IF (ShapeIndex
= SelectedShape
) THEN CALL ccircle
(Shape
(ShapeIndex
).Centroid.x
, Shape
(ShapeIndex
).Centroid.y
, 3, Shape
(ShapeIndex
).Shade
) CALL cpaint
(Shape
(ShapeIndex
).Centroid.x
, Shape
(ShapeIndex
).Centroid.y
, Shape
(ShapeIndex
).Shade
, Shape
(ShapeIndex
).Shade
)
t = 0
t = t + arr(j)
IntegrateArray = t
li = i - 1
ri = i + 1
IF (i
= 1) THEN li
= Shape
(k
).Elements
IF (i
= Shape
(k
).Elements
) THEN ri
= 1 l.x = PointChain(k, li).x
r.x = PointChain(k, ri).x
dx = r.x - l.x
CalculateNormalX = dx
li = i - 1
ri = i + 1
IF (i
= 1) THEN li
= Shape
(k
).Elements
IF (i
= Shape
(k
).Elements
) THEN ri
= 1 l.y = PointChain(k, li).y
r.y = PointChain(k, ri).y
dy = r.y - l.y
CalculateNormalY = dy
xx = 0
yy = 0
FOR i
= 1 TO Shape
(k
).Elements
xx = xx + PointChain(k, i).x
yy = yy + PointChain(k, i).y
Shape(k).Centroid.x = xx / Shape(k).Elements
Shape(k).Centroid.y = yy / Shape(k).Elements
r2max = -1
FOR i
= 1 TO Shape
(k
).Elements
xx = Shape(k).Centroid.x - PointChain(k, i).x
yy = Shape(k).Centroid.y - PointChain(k, i).y
r2 = xx * xx + yy * yy
r2max = r2
Shape
(k
).Diameter
= SQR(r2max
)
aa = 0
FOR i
= 2 TO Shape
(k
).Elements
x = PointChain(k, i).x - Shape(k).Centroid.x
y = PointChain(k, i).y - Shape(k).Centroid.y
dx = (PointChain(k, i).x - PointChain(k, i - 1).x)
dy = (PointChain(k, i).y - PointChain(k, i - 1).y)
da = .5 * (x * dy - y * dx)
aa = aa + da
Shape
(k
).Mass
= factor
* SQR(aa
* aa
)
xx = 0
yy = 0
FOR i
= 1 TO Shape
(k
).Elements
a = ctrvec.x - PointChain(k, i).x
b = ctrvec.y - PointChain(k, i).y
xx = xx + a * a
yy = yy + b * b
Shape
(k
).MOI
= SQR((xx
+ yy
) * (xx
+ yy
)) * (Shape
(k
).Mass
/ Shape
(k
).Elements
)
FOR i
= 1 TO Shape
(k
).Elements
PointChain(k, i).x = PointChain(k, i).x + c.x
PointChain(k, i).y = PointChain(k, i).y + c.y
Shape(k).Centroid.x = Shape(k).Centroid.x + c.x
Shape(k).Centroid.y = Shape(k).Centroid.y + c.y
FOR i
= 1 TO Shape
(k
).Elements
xx = PointChain(k, i).x - c.x
yy = PointChain(k, i).y - c.y
PointChain
(k
, i
).x
= c.x
+ xx
* COS(da
) - yy
* SIN(da
) PointChain
(k
, i
).y
= c.y
+ yy
* COS(da
) + xx
* SIN(da
)
SUB NewAutoBall
(x1
, y1
, r1
, r2
, pa
, pb
, fx
) ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = fx
Shape(ShapeCount).Collisions = 0
i = 0
i = i + 1
r
= r1
+ r2
* COS(pa
* j
) ^ pb
PointChain
(ShapeCount
, i
).x
= x1
+ r
* COS(j
) PointChain
(ShapeCount
, i
).y
= y1
+ r
* SIN(j
) Shape(ShapeCount).Elements = i
CALL CalculateCentroid
(ShapeCount
) CALL CalculateMass
(ShapeCount
, 1) CALL CalculateMass
(ShapeCount
, 999999) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameter
(ShapeCount
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
Shape
(ShapeCount
).Shade
= _RGB(100, 100, 100) SelectedShape = ShapeCount
SUB NewAutoBrick
(x1
, y1
, wx
, wy
, ang
) ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 1
Shape(ShapeCount).Collisions = 0
i = 0
i = i + 1
PointChain(ShapeCount, i).x = x1 + wx / 2
PointChain(ShapeCount, i).y = y1 + j
i = i + 1
PointChain(ShapeCount, i).x = x1 + j
PointChain(ShapeCount, i).y = y1 + wy / 2
i = i + 1
PointChain(ShapeCount, i).x = x1 - wx / 2
PointChain(ShapeCount, i).y = y1 + j
i = i + 1
PointChain(ShapeCount, i).x = x1 + j
PointChain(ShapeCount, i).y = y1 - wy / 2
Shape(ShapeCount).Elements = i
CALL CalculateCentroid
(ShapeCount
) CALL CalculateMass
(ShapeCount
, 99999) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameter
(ShapeCount
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
Shape
(ShapeCount
).Shade
= _RGB(100, 100, 100) SelectedShape = ShapeCount
CALL RotShape
(ShapeCount
, Shape
(ShapeCount
).Centroid
, ang
)
SUB NewBrickLine
(xi
, yi
, xf
, yf
, wx
, wy
) d1
= SQR((xf
- xi
) ^ 2 + (yf
- yi
) ^ 2) d2
= SQR(wx
^ 2 + wy
^ 2) ang
= ATN((yf
- yi
) / (xf
- xi
)) f = 1.2 * d2 / d1
CALL NewAutoBrick
(xi
* (1 - t
) + xf
* t
, yi
* (1 - t
) + yf
* t
, wx
, wy
, ang
)
ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 0
Shape(ShapeCount).Collisions = 0
numpoints = 0
xold = 999 ^ 999
yold = 999 ^ 999
delta
= SQR((x
- xold
) ^ 2 + (y
- yold
) ^ 2) IF (delta
> rawresolution
) AND (numpoints
< targetpoints
- 1) THEN numpoints = numpoints + 1
PointChain(ShapeCount, numpoints).x = x
PointChain(ShapeCount, numpoints).y = y
xold = x
yold = y
DO WHILE (numpoints
< targetpoints
) rad2max = -1
kmax = -1
FOR k
= 1 TO numpoints
- 1 xfac = PointChain(ShapeCount, k).x - PointChain(ShapeCount, k + 1).x
yfac = PointChain(ShapeCount, k).y - PointChain(ShapeCount, k + 1).y
rad2 = xfac ^ 2 + yfac ^ 2
kmax = k
rad2max = rad2
edgecase = 0
xfac = PointChain(ShapeCount, numpoints).x - PointChain(ShapeCount, 1).x
yfac = PointChain(ShapeCount, numpoints).y - PointChain(ShapeCount, 1).y
rad2 = xfac ^ 2 + yfac ^ 2
kmax = numpoints
rad2max = rad2
edgecase = 1
numpoints = numpoints + 1
PointChain(ShapeCount, j + 1).x = PointChain(ShapeCount, j).x
PointChain(ShapeCount, j + 1).y = PointChain(ShapeCount, j).y
PointChain(ShapeCount, kmax + 1).x = (1 / 2) * (PointChain(ShapeCount, kmax).x + PointChain(ShapeCount, kmax + 2).x)
PointChain(ShapeCount, kmax + 1).y = (1 / 2) * (PointChain(ShapeCount, kmax).y + PointChain(ShapeCount, kmax + 2).y)
PointChain(ShapeCount, numpoints).x = (1 / 2) * (PointChain(ShapeCount, 1).x + PointChain(ShapeCount, numpoints - 1).x)
PointChain(ShapeCount, numpoints).y = (1 / 2) * (PointChain(ShapeCount, 1).y + PointChain(ShapeCount, numpoints - 1).y)
FOR j
= 1 TO smoothiterations
FOR k
= 2 TO numpoints
- 1 TempChain(ShapeCount, k).x = (1 / 2) * (PointChain(ShapeCount, k - 1).x + PointChain(ShapeCount, k + 1).x)
TempChain(ShapeCount, k).y = (1 / 2) * (PointChain(ShapeCount, k - 1).y + PointChain(ShapeCount, k + 1).y)
FOR k
= 2 TO numpoints
- 1 PointChain(ShapeCount, k).x = TempChain(ShapeCount, k).x
PointChain(ShapeCount, k).y = TempChain(ShapeCount, k).y
TempChain(ShapeCount, 1).x = (1 / 2) * (PointChain(ShapeCount, numpoints).x + PointChain(ShapeCount, 2).x)
TempChain(ShapeCount, 1).y = (1 / 2) * (PointChain(ShapeCount, numpoints).y + PointChain(ShapeCount, 2).y)
PointChain(ShapeCount, 1).x = TempChain(ShapeCount, 1).x
PointChain(ShapeCount, 1).y = TempChain(ShapeCount, 1).y
TempChain(ShapeCount, numpoints).x = (1 / 2) * (PointChain(ShapeCount, 1).x + PointChain(ShapeCount, numpoints - 1).x)
TempChain(ShapeCount, numpoints).y = (1 / 2) * (PointChain(ShapeCount, 1).y + PointChain(ShapeCount, numpoints - 1).y)
PointChain(ShapeCount, numpoints).x = TempChain(ShapeCount, numpoints).x
PointChain(ShapeCount, numpoints).y = TempChain(ShapeCount, numpoints).y
Shape(ShapeCount).Elements = numpoints
CALL CalculateCentroid
(ShapeCount
) CALL CalculateMass
(ShapeCount
, 1) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameter
(ShapeCount
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
SelectedShape = ShapeCount
' Set external field
ForceField.x = 0
ForceField.y = 0
' Rectangular border
wx = 42
wy = 10
wx = 40
wy = 10
' Balls (billiard setup)
x0 = 160
y0 = 0
r = 15
gg = 2 * r + 4
xf
= COS(30 * 3.14159 / 180) yf
= SIN(30 * 3.14159 / 180) gx = gg * xf
gy = gg * yf
CALL NewAutoBall
(x0
+ 0 * gx
, y0
+ 0 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 1 * gx
, y0
+ 1 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 1 * gx
, y0
- 1 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
+ 2 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
+ 0 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
- 2 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
+ 3 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
+ 1 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
- 1 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
- 3 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 4 * gx
, y0
+ 4 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 4 * gx
, y0
+ 2 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 4 * gx
, y0
- 0 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 4 * gx
, y0
- 2 * gy
, r
, 0, 1, 1, 0) CALL NewAutoBall
(x0
+ 4 * gx
, y0
- 4 * gy
, r
, 0, 1, 1, 0)
' Cue ball
CALL NewAutoBall
(-220, 0, r
, 0, 1, 1, 0) Shape
(ShapeCount
).Velocity.x
= 10 + 2 * RND Shape
(ShapeCount
).Velocity.y
= 1 * (RND - .5) Shape
(ShapeCount
).Shade
= _RGB(255, 255, 255)
' Parameters
CPC = 1.15
FPC = 8
RST = 0.75
VD = 0.995
SV = 0
' Set external field
ForceField.x = 0
ForceField.y = -.08
' Rectangular border
wx = 42
wy = 10
wx = 40
wy = 10
' Wacky balls
x0 = -70
y0 = 120
r1 = 15
r2 = 2.5
gg = 2.5 * (r1 + r2) + 3.5
xf
= COS(30 * 3.14159 / 180) yf
= SIN(30 * 3.14159 / 180) gx = gg * xf
gy = gg * yf
CALL NewAutoBall
(x0
+ 0 * gx
, y0
+ 0 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 1 * gx
, y0
+ 1 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 1 * gx
, y0
- 1 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
+ 2 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
+ 0 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
- 2 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
+ 3 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
+ 1 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
- 1 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 3 * gx
, y0
- 3 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0)
' Slanted bricks
wx = 60
wy = 10
ww
= SQR(wx
* wx
+ wy
* wy
) * .85 CALL NewBrickLine
(ww
, 0, 100 + ww
, 100, wx
, wy
) CALL NewBrickLine
(-ww
, 0, -100 - ww
, 100, wx
, wy
)
' Fidget spinner
CALL NewAutoBall
(-220, 0, 20, 15, 1.5, 2, 0) Shape
(ShapeCount
).Shade
= _RGB(255, 255, 255)
' Parameters
CPC = 1.15
FPC = 8
RST = 0.70
VD = 0.995
SV = 0.025
' Set external field
ForceField.x = 0
ForceField.y = 0
' Rectangular border
wx = 42
wy = 10
wx = 40
wy = 10
CALL NewAutoBall
(0, 0, r
, 0, 1, 1, 0)
' Parameters
CPC = 1.15
FPC = 8
RST = 0.75
VD = 0.995
SV = 0.025
' Set external field
ForceField.x = 0
ForceField.y = 0 - .08
' Fidget spinner
CALL NewAutoBall
(-220, 0, 20, 15, 1.5, 2, 0) Shape
(ShapeCount
).Shade
= _RGB(255, 255, 255)
' Rectangular border
wx = 42
wy = 10
wx = 40
wy = 10
' Parameters
CPC = 1.15
FPC = 8
RST = 0.75
VD = 0.995
SV = 0.025
' Set external field
ForceField.x = 0
ForceField.y = 0
' Rectangular border
wx = 42
wy = 10
wx = 40
wy = 10
' Pong ball
CALL NewAutoBall
(0, 200, 20, 0, 1, 1, 0) Shape(ShapeCount).Velocity.x = -1
Shape(ShapeCount).Velocity.y = -3
Shape
(ShapeCount
).Shade
= _RGB(255, 255, 255)
' Pong Paddle
CALL NewAutoBrick
(-100, 10, 100, -10, .1) vtemp.x = 0
vtemp.y = -200
CALL TranslateShape
(ShapeCount
, vtemp
) Shape
(ShapeCount
).Shade
= _RGB(200, 200, 200)
' Parameters
CPC = 1.15
FPC = 8
RST = 1 '0.75
VD = 1 '0.995
SV = 0.025