Angle Collisions
#88
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
Reply


Messages In This Thread
Angle Collisions - by james2464 - 10-15-2022, 01:39 AM
RE: Angle Collisions - by bplus - 10-15-2022, 02:16 AM
RE: Angle Collisions - by james2464 - 10-15-2022, 04:01 AM
RE: Angle Collisions - by James D Jarvis - 10-15-2022, 10:39 PM
RE: Angle Collisions - by Pete - 10-15-2022, 10:46 PM
RE: Angle Collisions - by James D Jarvis - 10-15-2022, 11:24 PM
RE: Angle Collisions - by james2464 - 10-16-2022, 12:17 AM
RE: Angle Collisions - by OldMoses - 10-16-2022, 01:14 PM
RE: Angle Collisions - by james2464 - 10-16-2022, 07:11 PM
RE: Angle Collisions - by OldMoses - 10-18-2022, 08:20 PM
RE: Angle Collisions - by james2464 - 10-18-2022, 10:47 PM
RE: Angle Collisions - by OldMoses - 10-19-2022, 12:23 AM
RE: Angle Collisions - by Pete - 10-16-2022, 12:13 AM
RE: Angle Collisions - by Pete - 10-16-2022, 12:50 AM
RE: Angle Collisions - by bplus - 10-16-2022, 01:01 PM
RE: Angle Collisions - by bplus - 10-16-2022, 01:27 PM
RE: Angle Collisions - by OldMoses - 10-16-2022, 04:02 PM
RE: Angle Collisions - by bplus - 10-16-2022, 06:46 PM
RE: Angle Collisions - by bplus - 10-16-2022, 07:45 PM
RE: Angle Collisions - by james2464 - 10-16-2022, 08:04 PM
RE: Angle Collisions - by James D Jarvis - 10-16-2022, 08:07 PM
RE: Angle Collisions - by bplus - 10-16-2022, 08:47 PM
RE: Angle Collisions - by James D Jarvis - 10-16-2022, 08:55 PM
RE: Angle Collisions - by bplus - 10-17-2022, 10:07 AM
RE: Angle Collisions - by bplus - 10-17-2022, 12:26 PM
RE: Angle Collisions - by OldMoses - 10-17-2022, 12:58 PM
RE: Angle Collisions - by bplus - 10-17-2022, 01:11 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 01:57 PM
RE: Angle Collisions - by OldMoses - 10-17-2022, 02:19 PM
RE: Angle Collisions - by bplus - 10-17-2022, 02:49 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 03:46 PM
RE: Angle Collisions - by bplus - 10-17-2022, 04:53 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 05:27 PM
RE: Angle Collisions - by Dav - 10-18-2022, 02:22 AM
RE: Angle Collisions - by james2464 - 10-18-2022, 03:25 AM
RE: Angle Collisions - by Pete - 10-17-2022, 04:10 PM
RE: Angle Collisions - by bplus - 10-17-2022, 04:55 PM
RE: Angle Collisions - by james2464 - 10-17-2022, 05:23 PM
RE: Angle Collisions - by james2464 - 10-18-2022, 02:00 AM
RE: Angle Collisions - by Pete - 10-18-2022, 02:10 AM
RE: Angle Collisions - by Pete - 10-18-2022, 03:20 AM
RE: Angle Collisions - by james2464 - 10-18-2022, 03:57 AM
RE: Angle Collisions - by bplus - 10-18-2022, 03:27 PM
RE: Angle Collisions - by james2464 - 10-18-2022, 04:11 PM
RE: Angle Collisions - by bplus - 10-18-2022, 08:27 PM
RE: Angle Collisions - by Pete - 10-18-2022, 08:44 PM
RE: Angle Collisions - by bplus - 10-18-2022, 10:10 PM
RE: Angle Collisions - by Pete - 10-18-2022, 10:19 PM
RE: Angle Collisions - by james2464 - 10-20-2022, 12:30 AM
RE: Angle Collisions - by bplus - 10-20-2022, 02:36 AM
RE: Angle Collisions - by james2464 - 10-20-2022, 01:51 PM
RE: Angle Collisions - by Pete - 10-20-2022, 03:48 AM
RE: Angle Collisions - by bplus - 10-20-2022, 02:52 PM
RE: Angle Collisions - by james2464 - 10-20-2022, 04:21 PM
RE: Angle Collisions - by bplus - 10-20-2022, 04:37 PM
RE: Angle Collisions - by james2464 - 10-21-2022, 07:10 PM
RE: Angle Collisions - by Pete - 10-21-2022, 07:20 PM
RE: Angle Collisions - by bplus - 10-21-2022, 09:05 PM
RE: Angle Collisions - by OldMoses - 10-22-2022, 12:09 AM
RE: Angle Collisions - by james2464 - 10-22-2022, 10:29 PM
RE: Angle Collisions - by bplus - 10-22-2022, 10:59 PM
RE: Angle Collisions - by justsomeguy - 10-22-2022, 11:45 PM
RE: Angle Collisions - by Pete - 10-23-2022, 12:37 AM
RE: Angle Collisions - by OldMoses - 10-23-2022, 12:46 AM
RE: Angle Collisions - by james2464 - 10-24-2022, 04:57 PM
RE: Angle Collisions - by james2464 - 10-24-2022, 11:14 PM
RE: Angle Collisions - by bplus - 10-25-2022, 12:37 AM
RE: Angle Collisions - by james2464 - 10-25-2022, 03:25 AM
RE: Angle Collisions - by OldMoses - 10-25-2022, 10:47 PM
RE: Angle Collisions - by james2464 - 10-25-2022, 10:52 PM
RE: Angle Collisions - by OldMoses - 10-26-2022, 03:39 AM
RE: Angle Collisions - by james2464 - 10-26-2022, 03:51 PM
RE: Angle Collisions - by OldMoses - 10-26-2022, 04:18 PM
RE: Angle Collisions - by james2464 - 10-26-2022, 08:41 PM
RE: Angle Collisions - by OldMoses - 10-27-2022, 12:33 AM
RE: Angle Collisions - by james2464 - 10-27-2022, 03:36 PM
RE: Angle Collisions - by OldMoses - 10-29-2022, 12:05 AM
RE: Angle Collisions - by james2464 - 10-29-2022, 01:45 AM
RE: Angle Collisions - by james2464 - 10-30-2022, 04:41 PM
RE: Angle Collisions - by bplus - 10-30-2022, 06:16 PM
RE: Angle Collisions - by james2464 - 10-30-2022, 06:25 PM
RE: Angle Collisions - by bplus - 10-30-2022, 06:31 PM
RE: Angle Collisions - by james2464 - 10-30-2022, 06:37 PM
RE: Angle Collisions - by bplus - 10-30-2022, 06:45 PM
RE: Angle Collisions - by james2464 - 10-31-2022, 01:27 AM
RE: Angle Collisions - by bplus - 10-31-2022, 01:52 AM
RE: Angle Collisions - by TempodiBasic - 11-01-2022, 02:38 AM
RE: Angle Collisions - by bplus - 11-01-2022, 11:31 AM
RE: Angle Collisions - by james2464 - 11-01-2022, 04:15 PM
RE: Angle Collisions - by triggered - 11-01-2022, 03:03 AM
RE: Angle Collisions - by james2464 - 11-03-2022, 06:53 PM
RE: Angle Collisions - by OldMoses - 11-04-2022, 12:56 AM



Users browsing this thread: 19 Guest(s)