Alright here's how you do angle collisions. To do it right, you need to (i) conserve momentum, and (ii) conserve energy. If you're a real mac daddy, you can reflect shapes with arbitrary boundaries (so long as they're closed), AND create and manipulate new shapes while the program is running. This program does all four. It was written before my Option Explicit days so I don't stand by the style and I don't update it anymore. It perfects collisions but does not quite do condensed matter particularly well.
Code: (Select All)
' Display
Screen _NewImage(800, 600, 32)
_ScreenMove (_DesktopWidth \ 2 - _Width \ 2) - 3, (_DesktopHeight \ 2 - _Height \ 2) - 29
_Title "Collisions - Version 9"
_Delay 1
' Meta
start:
Clear
Cls
Randomize Timer
' Data structures
Type Vector
x As Double
y As Double
End Type
Dim Shared vtemp As Vector
' Object type
Type Object
Centroid As Vector
Collisions As Long
CollisionSwitch As Integer
DeltaO As Double
DeltaV As Vector
Diameter As Double
Elements As Integer
Fixed As Integer
Mass As Double
MOI As Double
PartialNormal As Vector
Omega As Double
Shade As _Unsigned Long
Velocity As Vector
End Type
' Object storage
Dim Shared Shape(300) As Object
Dim Shared PointChain(300, 500) As Vector
Dim Shared TempChain(300, 500) As Vector
Dim Shared ShapeCount As Integer
Dim Shared SelectedShape As Integer
' Dynamics
Dim Shared CollisionCount As Integer
Dim Shared ProximalPairs(300 / 2, 1 To 2) As Integer
Dim Shared ProximalPairsCount As Integer
Dim Shared ContactPoints As Integer
Dim Shared CPC, FPC, RST, VD, SV As Double
' Environment
Dim Shared ForceField As Vector ' Ex: gravity
' Initialize
ShapeCount = 0
CollisionCount = 0
' Prompt
Cls
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 ")
_Display
'_KeyClear
'Do
' kk = _KeyHit
' Select Case kk
' Case Asc("1")
' Call SetupPoolGame
' Exit Do
' Case Asc("2")
' Call SetupWackyGame
' Exit Do
' Case Asc("3")
' Call SetupRings
' Exit Do
' Case Asc("4")
' Call SetupWallsOnly
' Exit Do
' Case Asc("5")
' Call SetupAnglePong
' Exit Do
' Case Else
' _KeyClear
' End Select
' _Limit 60
'Loop
Call SetupAnglePong
Call Graphics
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.")
_Display
Do: Loop Until (_KeyHit > 0)
While (_MouseInput): Wend
_KeyClear
' Main loop
Do
If (UserInput = -1) Then GoTo start
Call PairDynamics(CPC, FPC, RST)
Call FleetDynamics(VD, SV)
Call Graphics
_Limit 120
Loop
End
Function UserInput
TheReturn = 0
' Keyboard input
kk = _KeyHit
Select Case kk
Case 32
Do: Loop Until _KeyHit
While _MouseInput: Wend
_KeyClear
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)
Cls
Case 18432, Asc("w"), Asc("W") ' Up arrow
Shape(SelectedShape).Velocity.y = Shape(SelectedShape).Velocity.y * 1.05 + 1.5
Case 20480, Asc("s"), Asc("S") ' Down arrow
Shape(SelectedShape).Velocity.y = Shape(SelectedShape).Velocity.y * 0.95 - 1.5
Case 19200, Asc("a"), Asc("A") ' Left arrow
Shape(SelectedShape).Velocity.x = Shape(SelectedShape).Velocity.x * 0.95 - 1.5
Case 19712, Asc("d"), Asc("D") ' Right arrow
Shape(SelectedShape).Velocity.x = Shape(SelectedShape).Velocity.x * 1.05 + 1.5
Case Asc("e"), Asc("E")
Shape(SelectedShape).Omega = Omega * 0.5 - .02
Case Asc("q"), Asc("Q")
Shape(SelectedShape).Omega = Omega * 1.5 + .02
Case Asc("r"), Asc("R")
TheReturn = -1
Case 27
For k = 1 To ShapeCount
Shape(k).Velocity.x = .000001 * (Rnd - .5)
Shape(k).Velocity.y = .000001 * (Rnd - .5)
Shape(k).Omega = .000001 * (Rnd - .5)
Next
End Select
If (kk) Then
_KeyClear
End If
' Mouse input
mb = 0
mxold = 999999999
myold = 999999999
Do While _MouseInput
x = _MouseX
y = _MouseY
If (x > 0) And (x < _Width) And (y > 0) And (y < _Height) Then
x = x - (_Width / 2)
y = -y + (_Height / 2)
rmin = 999999999
For k = 1 To ShapeCount
dx = x - Shape(k).Centroid.x
dy = y - Shape(k).Centroid.y
r2 = dx * dx + dy * dy
If (r2 < rmin) Then
rmin = r2
SelectedShape = k
End If
Next
If (_MouseButton(1)) Then
If (mb = 0) Then
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
End If
End If
If (_MouseButton(2)) Then
If (mb = 0) Then
mb = 1
Call NewAutoBall(x, y, 15, 0, 1, 1, 0)
_Delay .1
End If
End If
If (_MouseWheel > 0) Then
Call RotShape(SelectedShape, Shape(SelectedShape).Centroid, -.02 * 8 * Atn(1))
End If
If (_MouseWheel < 0) Then
Call RotShape(SelectedShape, Shape(SelectedShape).Centroid, .02 * 8 * Atn(1))
End If
End If
Loop
If ((mxold <> 999999999) And (myold <> 999999999)) Then
Shape(SelectedShape).Velocity.x = x - mxold
Shape(SelectedShape).Velocity.y = y - myold
End If
UserInput = TheReturn
End Function
Sub PairDynamics (CoarseProximityConstant As Double, FineProximityConstant As Double, Restitution As Double)
Dim GrossJ(300) As Integer
Dim GrossK(300) As Integer
Dim NumJK As Integer
' Proximity detection
ProximalPairsCount = 0
Shape1 = 0
Shape2 = 0
For j = 1 To ShapeCount
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
End If
Next
Next
ContactPoints = 0
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
ContactPoints = ContactPoints + 1
' 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
End If
If (r2 < rmin) Then
rmin = r2
ClosestIndex1 = j
ClosestIndex2 = k
End If
Next
Next
If (NumJK > 1) Then
If ((GrossJ(1) - GrossJ(NumJK)) * (GrossJ(1) - GrossJ(NumJK)) > 50) Then
'ClosestIndex1 = 1
Else
ClosestIndex1 = Int(IntegrateArray(GrossJ(), NumJK) / NumJK)
End If
If ((GrossK(1) - GrossK(NumJK)) * (GrossK(1) - GrossK(NumJK)) > 50) Then
'ClosestIndex2 = 1
Else
ClosestIndex2 = Int(IntegrateArray(GrossK(), NumJK) / NumJK)
End If
End If
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, -1 * Shape(Shape1).Omega)
vtemp.x = -1 * (Shape(Shape1).Velocity.x)
vtemp.y = -1 * (Shape(Shape1).Velocity.y)
Call TranslateShape(Shape1, vtemp)
End If
If (Shape(Shape2).Collisions = 0) Then
Call RotShape(Shape2, Shape(Shape2).Centroid, -1 * Shape(Shape2).Omega)
vtemp.x = -1 * (Shape(Shape2).Velocity.x)
vtemp.y = -1 * (Shape(Shape2).Velocity.y)
Call TranslateShape(Shape2, vtemp)
End If
' 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
End If
If (Shape(Shape2).Collisions = 0) Then
Shape(Shape2).Velocity.x = Shape(Shape2).Velocity.x * Restitution
Shape(Shape2).Velocity.y = Shape(Shape2).Velocity.y * Restitution
End If
' 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 = -1 * dy1
pry1 = dx1
pp = Sqr(prx1 * prx1 + pry1 * pry1)
prx1 = prx1 / pp
pry1 = pry1 / pp
' Perpendicular vector 2 (prx2, pry2)
prx2 = -1 * 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)
If (qx1 * qx1 > 0.01) Then
qhatx1 = qx1 / qq
Else
qx1 = 0
qhatx1 = 0
End If
If (qy1 * qy1 > 0.01) Then
qhaty1 = qy1 / qq
Else
qy1 = 0
qhaty1 = 0
End If
qq = Sqr(qx2 * qx2 + qy2 * qy2)
If (qx2 * qx2 > 0.01) Then
qhatx2 = qx2 / qq
Else
qx2 = 0
qhatx2 = 0
End If
If (qy2 * qy2 > 0.01) Then
qhaty2 = qy2 / qq
Else
qy2 = 0
qhaty2 = 0
End If
' Angular impulse (qdotp)
q1dotp1 = qx1 * prx1 + qy1 * pry1
q2dotp2 = qx2 * prx2 + qy2 * pry2
' Translational impulse (qdotn, ndotrhat, f)
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
If (np > 0) Then
dcx = cx1 - cx2
dcy = cy1 - cy2
dc = Sqr(dcx * dcx + dcy * dcy)
If (dc < (r1 + r2)) Then
If (m1 > m2) Then ' This criteria may be bullshit in general but works now.
q1dotp1 = -q1dotp1
f1 = -f1
Else
q2dotp2 = -q2dotp2
f2 = -f2
End If
End If
End If
' Angular impulse update (edits omega)
Shape(Shape1).DeltaO = Shape(Shape1).DeltaO + r1 * q1dotp1 / i1
Shape(Shape2).DeltaO = Shape(Shape2).DeltaO - r2 * q2dotp2 / i2
' Linear impulse update (edits velocity)
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
If ((dvx1s > .001) And (dvx1s < 50)) Then
Shape(Shape1).DeltaV.x = Shape(Shape1).DeltaV.x + dvx1
End If
If ((dvy1s > .001) And (dvy1s < 50)) Then
Shape(Shape1).DeltaV.y = Shape(Shape1).DeltaV.y + dvy1
End If
If ((dvx2s > .001) And (dvx2s < 50)) Then
Shape(Shape2).DeltaV.x = Shape(Shape2).DeltaV.x + dvx2
End If
If ((dvy2s > .001) And (dvy2s < 50)) Then
Shape(Shape2).DeltaV.y = Shape(Shape2).DeltaV.y + dvy2
End If
' External torque (edits omega)
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 (edits position)
If (Shape(Shape1).Collisions < 2) Then ' changed from = 0
vtemp.x = -nx1 * (.5 / m1) * (1 * v1 ^ 2 + 1 * w1 ^ 2)
vtemp.y = -ny1 * (.5 / m1) * (1 * v1 ^ 2 + 1 * w1 ^ 2)
Call TranslateShape(Shape1, vtemp)
End If
If (Shape(Shape2).Collisions < 2) Then
vtemp.x = -nx2 * (.5 / m2) * (1 * v2 ^ 2 + 1 * w2 ^ 2)
vtemp.y = -ny2 * (.5 / m2) * (1 * v2 ^ 2 + 1 * w2 ^ 2)
Call TranslateShape(Shape2, vtemp)
End If
' 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)
End If
End If
Next
End If
End Sub
Sub FleetDynamics (MotionDamping As Double, LowLimitVelocity As Double)
For ShapeIndex = 1 To ShapeCount
' Contact update
If (Shape(ShapeIndex).CollisionSwitch = 1) Then
Shape(ShapeIndex).Collisions = Shape(ShapeIndex).Collisions + 1
Else
Shape(ShapeIndex).Collisions = 0
End If
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 = 0) Then
' Freefall (if airborne)
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x + ForceField.x
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y + ForceField.y
End If
If (Shape(ShapeIndex).Collisions > 2) Then
' Static friction
If ((Shape(ShapeIndex).Velocity.x * Shape(ShapeIndex).Velocity.x) < LowLimitVelocity) Then
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x * .05
End If
If ((Shape(ShapeIndex).Velocity.y * Shape(ShapeIndex).Velocity.y) < LowLimitVelocity) Then
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y * .05
End If
If ((Shape(ShapeIndex).Omega * Shape(ShapeIndex).Omega) < .000015 * LowLimitVelocity) Then
Shape(ShapeIndex).Omega = 0
End If
End If
' 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
Else
' Lock all motion
Shape(ShapeIndex).Velocity.x = 0
Shape(ShapeIndex).Velocity.y = 0
Shape(ShapeIndex).Omega = 0
End If
Next
End Sub
Sub Graphics
Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 200), BF
'Locate 1, 1: Print ProximalPairsCount, CollisionCount, ContactPoints
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)
End If
Next
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)
End If
Next
_Display
End Sub
Function IntegrateArray (arr() As Integer, lim As Integer)
t = 0
For j = 1 To lim
t = t + arr(j)
Next
IntegrateArray = t
End Function
Function CalculateNormalX (k As Integer, i As Integer)
Dim l As Vector
Dim r As Vector
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
End Function
Function CalculateNormalY (k As Integer, i As Integer)
Dim l As Vector
Dim r As Vector
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
End Function
Sub CalculateCentroid (k As Integer)
xx = 0
yy = 0
For i = 1 To Shape(k).Elements
xx = xx + PointChain(k, i).x
yy = yy + PointChain(k, i).y
Next
Shape(k).Centroid.x = xx / Shape(k).Elements
Shape(k).Centroid.y = yy / Shape(k).Elements
End Sub
Sub CalculateDiameter (k As Integer)
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
If (r2 > r2max) Then
r2max = r2
End If
Next
Shape(k).Diameter = Sqr(r2max)
End Sub
Sub CalculateMass (k As Integer, factor As Double)
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
Next
Shape(k).Mass = factor * Sqr(aa * aa)
End Sub
Sub CalculateMOI (k As Integer, ctrvec As Vector)
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
Next
Shape(k).MOI = Sqr((xx + yy) * (xx + yy)) * (Shape(k).Mass / Shape(k).Elements)
End Sub
Sub TranslateShape (k As Integer, c As Vector)
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
Next
Shape(k).Centroid.x = Shape(k).Centroid.x + c.x
Shape(k).Centroid.y = Shape(k).Centroid.y + c.y
End Sub
Sub RotShape (k As Integer, c As Vector, da As Double)
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)
Next
End Sub
Sub NewAutoBall (x1 As Double, y1 As Double, r1 As Double, r2 As Double, pa As Double, pb As Double, fx As Integer)
ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = fx
Shape(ShapeCount).Collisions = 0
i = 0
For j = 0 To (8 * Atn(1)) Step .02 * 8 * Atn(1)
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)
Next
Shape(ShapeCount).Elements = i
Call CalculateCentroid(ShapeCount)
If (fx = 0) Then
Call CalculateMass(ShapeCount, 1)
Else
Call CalculateMass(ShapeCount, 999999)
End If
Call CalculateMOI(ShapeCount, Shape(ShapeCount).Centroid)
Call CalculateDiameter(ShapeCount)
Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
If (fx = 0) Then
Shape(ShapeCount).Shade = _RGB(100 + Int(Rnd * 155), 100 + Int(Rnd * 155), 100 + Int(Rnd * 155))
Else
Shape(ShapeCount).Shade = _RGB(100, 100, 100)
End If
SelectedShape = ShapeCount
End Sub
Sub NewAutoBrick (x1 As Double, y1 As Double, wx As Double, wy As Double, ang As Double)
ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 1
Shape(ShapeCount).Collisions = 0
i = 0
For j = -wy / 2 To wy / 2 Step 5
i = i + 1
PointChain(ShapeCount, i).x = x1 + wx / 2
PointChain(ShapeCount, i).y = y1 + j
Next
For j = wx / 2 To -wx / 2 Step -5
i = i + 1
PointChain(ShapeCount, i).x = x1 + j
PointChain(ShapeCount, i).y = y1 + wy / 2
Next
For j = wy / 2 To -wy / 2 Step -5
i = i + 1
PointChain(ShapeCount, i).x = x1 - wx / 2
PointChain(ShapeCount, i).y = y1 + j
Next
For j = -wx / 2 To wx / 2 Step 5
i = i + 1
PointChain(ShapeCount, i).x = x1 + j
PointChain(ShapeCount, i).y = y1 - wy / 2
Next
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)
End Sub
Sub NewBrickLine (xi As Double, yi As Double, xf As Double, yf As Double, wx As Double, wy As Double)
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
For t = 0 To 1 + f Step f
Call NewAutoBrick(xi * (1 - t) + xf * t, yi * (1 - t) + yf * t, wx, wy, ang)
Next
End Sub
Sub NewMouseShape (rawresolution As Double, targetpoints As Integer, smoothiterations As Integer)
ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 0
Shape(ShapeCount).Collisions = 0
numpoints = 0
xold = 999 ^ 999
yold = 999 ^ 999
Do
Do While _MouseInput
x = _MouseX
y = _MouseY
If (x > 0) And (x < _Width) And (y > 0) And (y < _Height) Then
If _MouseButton(1) Then
x = x - (_Width / 2)
y = -y + (_Height / 2)
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
Call cpset(x, y, _RGB(0, 255, 255))
xold = x
yold = y
End If
End If
End If
Loop
_Display
Loop Until Not _MouseButton(1) And (numpoints > 1)
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
If rad2 > rad2max Then
kmax = k
rad2max = rad2
End If
Next
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
If (rad2 > rad2max) Then
kmax = numpoints
rad2max = rad2
edgecase = 1
End If
numpoints = numpoints + 1
If (edgecase = 0) Then
For j = numpoints To kmax + 1 Step -1
PointChain(ShapeCount, j + 1).x = PointChain(ShapeCount, j).x
PointChain(ShapeCount, j + 1).y = PointChain(ShapeCount, j).y
Next
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)
Else
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)
End If
Loop
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)
Next
For k = 2 To numpoints - 1
PointChain(ShapeCount, k).x = TempChain(ShapeCount, k).x
PointChain(ShapeCount, k).y = TempChain(ShapeCount, k).y
Next
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
Next
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
Shape(ShapeCount).Shade = _RGB(100 + Int(Rnd * 155), 100 + Int(Rnd * 155), 100 + Int(Rnd * 155))
SelectedShape = ShapeCount
End Sub
Sub cline (x1 As Double, y1 As Double, x2 As Double, y2 As Double, col As _Unsigned Long)
Line (_Width / 2 + x1, -y1 + _Height / 2)-(_Width / 2 + x2, -y2 + _Height / 2), col
End Sub
Sub ccircle (x1 As Double, y1 As Double, rad As Double, col As _Unsigned Long)
Circle (_Width / 2 + x1, -y1 + _Height / 2), rad, col
End Sub
Sub cpset (x1 As Double, y1 As Double, col As _Unsigned Long)
PSet (_Width / 2 + x1, -y1 + _Height / 2), col
End Sub
Sub cpaint (x1 As Double, y1 As Double, col1 As _Unsigned Long, col2 As _Unsigned Long)
Paint (_Width / 2 + x1, -y1 + _Height / 2), col1, col2
End Sub
Sub cprintstring (y As Double, a As String)
_PrintString (_Width / 2 - (Len(a) * 8) / 2, -y + _Height / 2), a
End Sub
Sub snd (frq As Double, dur As Double)
If ((frq >= 37) And (frq <= 2000)) Then
Sound frq, dur
End If
End Sub
Sub SetupPoolGame
' Set external field
ForceField.x = 0
ForceField.y = 0
' Rectangular border
wx = 42
wy = 10
Call NewBrickLine(-_Width / 2 + wx, _Height / 2 - wy, _Width / 2 - wx, _Height / 2 - wy, wx, wy)
Call NewBrickLine(-_Width / 2 + wx, -_Height / 2 + wy, _Width / 2 - wx, -_Height / 2 + wy, wx, wy)
wx = 40
wy = 10
Call NewBrickLine(-_Width / 2 + wy, -_Height / 2 + 2 * wx, -_Width / 2 + wy, _Height / 2 - 2 * wx, wx, wy)
Call NewBrickLine(_Width / 2 - wy, -_Height / 2 + 2 * wx, _Width / 2 - wy, _Height / 2 - 2 * wx, wx, wy)
' Balls (billiard setup)
x0 = 160
y0 = 0
r = 15
gg = 2 * r + 4
gx = gg * Cos(30 * 3.14159 / 180)
gy = gg * Sin(30 * 3.14159 / 180)
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
End Sub
Sub SetupWackyGame
' Set external field
ForceField.x = 0
ForceField.y = -.08
' Rectangular border
wx = 42
wy = 10
Call NewBrickLine(-_Width / 2 + wx, _Height / 2 - wy, _Width / 2 - wx, _Height / 2 - wy, wx, wy)
Call NewBrickLine(-_Width / 2 + wx, -_Height / 2 + wy, _Width / 2 - wx, -_Height / 2 + wy, wx, wy)
wx = 40
wy = 10
Call NewBrickLine(-_Width / 2 + wy, -_Height / 2 + 2 * wx, -_Width / 2 + wy, _Height / 2 - 2 * wx, wx, wy)
Call NewBrickLine(_Width / 2 - wy, -_Height / 2 + 2 * wx, _Width / 2 - wy, _Height / 2 - 2 * wx, wx, wy)
' Wacky balls
x0 = -70
y0 = 120
r1 = 15
r2 = 2.5
gg = 2.5 * (r1 + r2) + 3.5
gx = gg * Cos(30 * 3.14159 / 180)
gy = gg * Sin(30 * 3.14159 / 180)
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
End Sub
Sub SetupRings
' Set external field
ForceField.x = 0
ForceField.y = 0
' Rectangular border
wx = 42
wy = 10
Call NewBrickLine(-_Width / 2 + wx, _Height / 2 - wy, _Width / 2 - wx, _Height / 2 - wy, wx, wy)
Call NewBrickLine(-_Width / 2 + wx, -_Height / 2 + wy, _Width / 2 - wx, -_Height / 2 + wy, wx, wy)
wx = 40
wy = 10
Call NewBrickLine(-_Width / 2 + wy, -_Height / 2 + 2 * wx, -_Width / 2 + wy, _Height / 2 - 2 * wx, wx, wy)
Call NewBrickLine(_Width / 2 - wy, -_Height / 2 + 2 * wx, _Width / 2 - wy, _Height / 2 - 2 * wx, wx, wy)
For r = 25 To 175 Step 25
Call NewAutoBall(0, 0, r, 0, 1, 1, 0)
Next
' Parameters
CPC = 1.15
FPC = 8
RST = 0.75
VD = 0.995
SV = 0.025
End Sub
Sub SetupWallsOnly
' 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
Call NewBrickLine(-_Width / 2 + wx, _Height / 2 - wy, _Width / 2 - wx, _Height / 2 - wy, wx, wy)
Call NewBrickLine(-_Width / 2 + wx, -_Height / 2 + wy, _Width / 2 - wx, -_Height / 2 + wy, wx, wy)
wx = 40
wy = 10
Call NewBrickLine(-_Width / 2 + wy, -_Height / 2 + 2 * wx, -_Width / 2 + wy, _Height / 2 - 2 * wx, wx, wy)
Call NewBrickLine(_Width / 2 - wy, -_Height / 2 + 2 * wx, _Width / 2 - wy, _Height / 2 - 2 * wx, wx, wy)
' Parameters
CPC = 1.15
FPC = 8
RST = 0.75
VD = 0.995
SV = 0.025
End Sub
Sub SetupAnglePong
' Set external field
ForceField.x = 0
ForceField.y = 0
' Rectangular border
wx = 42
wy = 10
Call NewBrickLine(-_Width / 2 + wx, _Height / 2 - wy, _Width / 2 - wx, _Height / 2 - wy, wx, wy)
Call NewBrickLine(-_Width / 2 + wx, -_Height / 2 + wy, _Width / 2 - wx, -_Height / 2 + wy, wx, wy)
wx = 40
wy = 10
Call NewBrickLine(-_Width / 2 + wy, -_Height / 2 + 2 * wx, -_Width / 2 + wy, _Height / 2 - 2 * wx, wx, wy)
Call NewBrickLine(_Width / 2 - wy, -_Height / 2 + 2 * wx, _Width / 2 - wy, _Height / 2 - 2 * wx, wx, wy)
' Pong ball
Call NewAutoBall(-50, 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, -.02 * 8 * Atn(1))
vtemp.x = 0
vtemp.y = -200
Call TranslateShape(ShapeCount, vtemp)
Shape(ShapeCount).Shade = _RGB(200, 200, 200)
' Wacky balls
x0 = -70
y0 = 120
r1 = 15
r2 = 5.5
gg = 2.5 * (r1 + r2) + 3.5
gx = gg * Cos(30 * 3.14159 / 180)
gy = gg * Sin(30 * 3.14159 / 180)
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)
' Parameters
CPC = 1.15
FPC = 8
RST = 1 '0.75
VD = 1 '0.995
SV = 0.025
End Sub