BallSim1 - The Bouncing Ball Simulator! Released as open source.


It's more fun than PONG! Or not.

BallSim simulates the motion of a ball bouncing around within an enclosed box. The box is 250 feet tall by 350 feet wide. A strong measure of reality is lent to the simulation by including the effects of gravity in the motion of the ball, and by loss of velocity as the ball collides with the walls, ceiling, and floor. The program terminates the simulation when the ball has a velocity of 6 feet/sec or less, combined with an elevation of 6 feet or less.

Controls


The user operates the simulation with 10 controls. Two combo boxes are used to input the initial location of the ball at the beginning of the simulation. A second combo box allows the user to set the initial velocity of the ball. A third combo box sets the initial angle of flight.

Typically during the simulation, the ball will collide with the walls, ceiling and floor on multiple occasions. Since collisions are never perfectly elastic, there is a measure of energy loss during a collision. BallSim1 allows the user to control the energy loss during a collision by providing another combo box to set the percent of velocity retained after a collision with a barrier. At most, the ball will retain 95% of it's velocity after a collision. At the bottom end, the user can set the program to retain only 50% of the ball's velocity after a collision. When velocity retention is this low, the ball looks like a deflated basketball barely careening around the box, and the simulation will end very quickly.

A pair of radio buttons allows the user to set "Ball Tracking". If Ball Tracking is set to "Ball trail is preserved", then the ball leaves a series of set pixels along its trail as it careens around the box. If the Ball Tracking is set to "Ball trail not preserved", then no pixel trail is left by the ball. I often run a simulation without tracking, then with tracking. Both are fun.

BallSim1 includes a combo box control for setting the plotting speed, with the fastest speed represented by the number 10, and the slowest speed represented by the number 1. When I use LB2 ("The Deuce") on my 266mHz system, I will always set this control to fastest. However, when I use LB3 on my 266mHz system, I typically set the speed to 8 or 7. I recommend that the user experiment with simulation speeds, and set the speed to whichever one best allows appreciation of the movement of the ball.

The right-hand side of the application is dominated by the graphicbox where the simulation is plotted. Below the graphic box reside three buttons. The left-most button is used to clear the graphic box. Sometimes the graphic box looks messy at the conclusion of a simulation with ball trails criss-crossing all over the place. Even if the user doesn't manually clear the box, however, it will automatically clear itself prior to the next simulation.

The center button is used to Run the simulation. The right-most button will stop the simulation in progress. The stop button is most useful during either the first or fourth parts of the simulation, as described below. One might want to stop the simulation if the doggone thing is just taking too long! For instance, if you set the simulation speed to "Slowest", it could continue for five minutes or more.

The Simulation Sequence


The simulation has four parts. In the first part, the position of the ball is calculated every 0.03 seconds from the moment it is launched until the simulation reaches its terminating conditions. Nothing fun happens during this part, but the status text box provides a report to let the user know that calculation progress is being made.

During the second part of the simulation, all the position values are stuffed into a string array so that string conversion of the numeric values need not take place during plot time.

The third part of the simulation is merely a countdown. The countdown gives the user an opportunity to direct his eyes to the graphic box so that he can catch the simulation from the very beginning. Remember, the ball moves very quickly right after launch, and if the user yawns, he may miss the first third of the simulation.

The fourth part is the graphic simulation itself.

A "Good Sim"


I tend to like simulations that use up the entire screen, and tend to decay slowly. For instance, set
x = 340
y = 10
ball initial velocity = 200 ft/sec
initial angle = 135 degrees
velocity retention = 95%
simulation speed = 8
That's a good simulation in my view. Do it once with ball tracking, and once without ball tracking. A no-fun simulation is probably anything with a low initial velocity, and a low velocity retention after collision.

Demo Program


'************************************************
'   Ball Simulation
'   First Version by Tom Nally + April 2002
'   Released as open source
'   Rereleased June 2006 for Just Basic users
'
'   Made with Liberty Basic
'   http://www.libertybasic.com
'
'   Made with Liberty Basic Workshop
'   http://www.alycesrestaurant.com
'************************************************

 
pi = 4*Atn(1)
 
'Define Arrays from GUI project
'------------------------------
Dim BallInitx(34)
Dim BallInitx$(34)
For i = 1 to 34
    BallInitx(i) = 10*i
    BallInitx$(i) = "x = " + Str$(BallInitx(i)) + " ft"
Next i
 
Dim BallInity(24)
Dim BallInity$(24)
For i = 1 to 24
    BallInity(i) = 10*i
    BallInity$(i) = "y = " + Str$(BallInity(i)) + " ft"
Next i
 
Dim BallInitV(20)
Dim BallInitV$(20)
For i = 1 to 20
    BallInitV(i) = i*10
    BallInitV$(i) = Str$(BallInitV(i)) + " ft/sec"
Next i
 
Dim BallInitAngle(359)
Dim BallInitAngle$(359)
For i = 0 to 359
    BallInitAngle(i) = i
    BallInitAngle$(i) = Str$(BallInitAngle(i)) + " degrees"
Next i
 
Dim VelRetained(10)
Dim VelRetained$(10)
For i = 1 to 10
    VelRetained(i) = (100 - 5*i)/100
    VelRetained$(i) = Str$(100 - 5*i) + " %"
Next i
 
Dim EndingEnergy(10)
Dim EndingEnergy$(10)
For i = 1 to 10
    EndingEnergy(i) = 5*i
    EndingEnergy$(i) = Str$(5*i) + " ft•lbs"
Next i
 
Dim SimSpeed(10)
Dim SimSpeed$(10)
For i = 1 to 10
    SimSpeed(i) = 100*i
Next i
SimSpeed$(1) = "Fastest"
SimSpeed$(10) = "Slowest"
For i = 2 to 9
    SimSpeed$(i) = Str$(11 - i)
Next i
 
 
 
'Define Variables from GUI project
'---------------------------------
BallInitxIndex = 5
BallInityIndex = 15
BallInitVIndex = 12
BallInitAngleIndex = 46
VelRetainedIndex = 1
EndingEnergyIndex = 1
 
SimSpeedIndex = 1
SimSpeed = 100
 
BallInitx = 50
BallInity = 150
BallInitV = 120
BallInitAngleDegs = 45
BallInitAngleRads = (BallInitAngleDegs/360)*(2*pi)
VelRetained = 0.95
EndingEnergy = 5
 
TrailPreserved = 1
 
'Define Variables from ENGINE project
'------------------------------------
Dim Ballx(15000)
Dim Bally(15000)
Dim SetX$(15000)
Dim SetY$(15000)
 
g =      32.2   'Acceleration due to gravity
Rball =  3.000  'Radius of the ball, which is 2'
Rball$ = " " + Str$(Rball)
Mass = 1
 
LeftWallx    = 0.00
LeftWallyLO  = 0.00
LeftWallyUP  = 250.00
LeftImpactBoundaryX = LeftWallx + Rball
LeftImpactBoundaryTop = LeftWallyUP - Rball
LeftImpactBoundaryBot = LeftWallyLO + Rball
 
TopWally   = 250.00
TopWallxLE = 0.00
TopWallxRI = 350.00
TopImpactBoundaryY = TopWally - Rball
TopImpactBoundaryL = TopWallxLE + Rball
TopImpactBoundaryR = TopWallxRI - Rball
 
RightWallx    = 350.00
RightWallyLO  = 0.00
RightWallyUP  = 250.00
RightImpactBoundaryX = RightWallx - Rball
RightImpactBoundaryTop = RightWallyUP - Rball
RightImpactBoundaryBot = RightWallyLO + Rball
 
BottWally   = 0.00
BottWallxLE = 0.00
BottWallxRI = 350.00
BottImpactBoundaryY = BottWally + Rball
BottImpactBoundaryL = BottWallxLE + Rball
BottImpactBoundaryR = BottWallxRI - Rball
 
True = 1 : False = 0
 
[InitColors]
    ForegroundColor$ = "Black"
    BackgroundColor$ = "Lightgray"
    TexteditorColor$ = "White"
    TextboxColor$    = "White"
    ComboboxColor$   = "White"
    ListboxColor$    = "White"
 
[WindowSetup]
    NoMainWin
    WindowWidth = 730 : WindowHeight = 475
    UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
    UpperLeftY = Int((DisplayHeight-WindowHeight)/2)
 
[ControlSetup]
 
Graphicbox  #main.graphicbox1, 295, 20, 410, 300
Groupbox    #main.TrackingGroupBox, "Ball Tracking", 15, 230, 230, 80
Statictext  #main.statictext1, "Ball initial location", 20, 20, 110, 20
Statictext  #main.statictext2, "Ball initial angle", 20, 110, 100, 20
Statictext  #main.statictext3, "Ball initial velocity", 20, 80, 110, 20
Statictext  #main.statictext4, "Simulation plot speed", 20, 340, 125, 35
Statictext  #main.statictext5, "Ball initial total energy =", 20, 140, 145, 20
Statictext  #main.statictextA, "Velocity retained after collision with wall or floor", 20, 170, 100, 60
Statictext  #main.BallEnergy, "Energy", 170, 140, 45, 20
Statictext  #main.statictext7, "ft•lbs", 220, 140, 35, 20
Statictext  #main.statictext8, "Simulation Status:", 20, 410, 115, 20
Button      #main.ClearBox, "Clear Graphic Box",[ClearBox.click],UL, 295, 330, 130, 35
Button      #main.RunSimulation, "Run Simulation",[RunSimulation.click],UL, 435, 330, 130, 35
Button      #main.StopSimulation, "Stop Simulation",[StopSimulation.click],UL, 575, 330, 130, 35
Button      #main.About, "About...",[About.click],UL, 490, 400, 105, 30
Button      #main.Quit, "Quit",[Quit.click],UL, 600, 400, 105, 30
 
Textbox     #main.HLine01, 20, 380, 680, 4
TextboxColor$    = "Cyan"
Textbox     #main.txtSimStatus, 145, 405, 320, 24
Radiobutton #main.TrailPreserved, " Ball trail is preserved",[TrailPreserved.click],[loop], 25, 250, 175, 25
Radiobutton #main.TrailNotPreserved, " Ball trail is not preserved",[TrailNotPreserved.click],[loop], 25, 280, 190, 25
Combobox    #main.InitialX,BallInitx$(,[InitialX.click], 130, 15, 95, 160
Combobox    #main.InitialY,BallInity$(,[InitialY.click], 130, 45, 95, 160
Combobox    #main.InitialV,BallInitV$(,[InitialV.click], 130, 75, 95, 160
Combobox    #main.InitialAngle,BallInitAngle$(,[InitialAngle.click], 130, 105, 95, 160
Combobox    #main.VelRetained,VelRetained$(,[VelRetained.click], 130, 185, 95, 160
Combobox    #main.SimSpeed,SimSpeed$(,[SimSpeed.click], 160, 335, 85, 160
 
Open "Ball Simulation" For Window As #main
 
    Print #main, "trapclose [Quit.click]"
    Print #main.graphicbox1, "down; fill White; flush"
    Print #main, "font arial 10"
    GoSub [Establish.Initial.Control.Values]
 
[loop]
    Wait
 
 
[Establish.Initial.Control.Values]
 
    Print #main.InitialX, "selectindex " + Str$(BallInitxIndex)
    Print #main.InitialY, "selectindex " + Str$(BallInityIndex)
    Print #main.InitialV, "selectindex " + Str$(BallInitVIndex)
    Print #main.InitialAngle, "selectindex " + Str$(BallInitAngleIndex)
    Print #main.VelRetained, "selectindex " + Str$(VelRetainedIndex)
    Print #main.TrailPreserved, "set"
    Print #main.SimSpeed, "selectindex " + Str$(SimSpeedIndex)
    Print #main.txtSimStatus, " ...Idle..."
 
    GoSub [Calculate.and.print.initial.energy]
 
    GoSub [Draw.Wall.Boundaries]
    GoSub [Plot.Xhairs.at.Starting.Point]
 
    Return
 
 
[StopSimulation.click]
 
    GoTo [loop]
 
[About.click]
 
    Notice "Ball Simulation" + Chr$(13) + _
           "First Version by TJ Nally - April 2002" + Chr$(13) + _
           "Released as Open Source" + Chr$(13) + _
           "Rereleased June 2006" + Chr$(13) + _
           "for Just BASIC users" + Chr$(13) + _
           "+   +   +   +   +   +   +   +   +   +   +   +         " + Chr$(13) + _
           "Made with Liberty Basic" + Chr$(13) + _
           "http://www.libertybasic.com" + Chr$(13) + _
           "Compatible with Just Basic" + Chr$(13) + _
           "http://www.justbasic.com" + Chr$(13) + _
           "+   +   +   +   +   +   +   +   +   +   +   +         " + Chr$(13) + _
           "Made with Liberty Basic Workshop" + Chr$(13) + _
           "http://www.alycesrestaurant.com"
 
 
    GoTo [loop]
 
 
[Quit.click]
 
    Close #main : End
    GoTo [loop]
 
[ClearBox.click]
 
    Print #main.graphicbox1, "fill white"
    GoSub [Draw.Wall.Boundaries]
    GoSub [Plot.Xhairs.at.Starting.Point]
    GoTo [loop]
 
[TrailPreserved.click]
 
    TrailPreserved = 1
 
    GoTo [loop]
 
[TrailNotPreserved.click]
 
    TrailPreserved = 0
 
    GoTo [loop]
 
[InitialX.click]
    Print #main.InitialX, "selectionindex? BallInitxIndex"
    BallInitx = BallInitx(BallInitxIndex)
    GoSub [Plot.Xhairs.at.Starting.Point]
 
    GoTo [loop]
 
[InitialY.click]
    Print #main.InitialY, "selectionindex? BallInityIndex"
    BallInity = BallInity(BallInityIndex)
    GoSub [Calculate.and.print.initial.energy]
    GoSub [Plot.Xhairs.at.Starting.Point]
 
    GoTo [loop]
 
[InitialV.click]
    Print #main.InitialV, "selectionindex? BallInitVIndex"
    BallInitV = BallInitV(BallInitVIndex)
    GoSub [Calculate.and.print.initial.energy]
 
    GoTo [loop]
 
[InitialAngle.click]
    Print #main.InitialAngle, "selectionindex? BallInitAngleIndex"
    BallInitAngleDegs = BallInitAngle(BallInitAngleIndex - 1)
    BallInitAngleRads = (BallInitAngleDegs/360)*(2*pi)
 
    GoTo [loop]
 
[SimSpeed.click]
    Print #main.SimSpeed, "selectionindex? SimSpeedIndex"
    SimSpeed = SimSpeed(SimSpeedIndex)
 
    GoTo [loop]
 
[VelRetained.click]
    Print #main.VelRetained, "selectionindex? VelRetainedIndex"
    VelRetained = VelRetained(VelRetainedIndex)
 
    GoTo [loop]
 
[RunSimulation.click]
 
    VelocityDecay = VelRetained 'This is the velocity that remains
                                'after a collision occurs
                                'as a percentage of the velocity of the
                                'ball just prior to the collision.

 
    Vi = BallInitV  '............Initial velocity

    Pos = 0         '............This is the position counter, and represents the
                    '            position of the ball between 0 and 2000.

    x0 = BallInitx '.............Initial x coordinate of the ball
    y0 = BallInity '.............Initial y coordinate of the ball
    LastBallx = x0
    LastBally = y0
 
    Phi.i.deg = BallInitAngleDegs  '.........Initial angle in degrees
    Phi.i.rads = (Phi.i.deg)/360*(2*pi) '....Initial angle in radians

    TI =      0.030 '............Time interval in seconds
    Tc =      0.00  '............Represents the current time
    Tacum =   0.00  '............Represents the total accumulated time

 
'Begin Ball Motion

    Tc = Tc + TI
    Tacum = Tacum + TI
    'Find the initial velocity in the y direction
    Vy0 = Vi * Sin(Phi.i.rads)
 
    'Find the initial velocity in the x direction
    Vx0 = Vi * Cos(Phi.i.rads)
 
[Next.Ball.Position]
 
    'Use a counter to track the sequence; report
    'progress to the status box
    Pos = Pos + 1
 
    'Allow the user to stop the simulation if things
    'are getting carried away, if you know what I'm sayin'

    Scan
 
    'Find the position of the ball, both x and y coordinates
    Bally = y0 + Vy0*(Tc) - (1/2)*g*(Tc)^2
    Ballx = x0 + Vx0*(Tc)
    Bally(Pos) = Bally
    Ballx(Pos) = Ballx
 
    'Determine true angle of flight using ATAN2()
    xChange = (Ballx - LastBallx)
    yChange = (Bally - LastBally)
    FlightAngleRads = ATAN2(xChange,yChange)
    FlightAngleDegs = (FlightAngleRads*360)/(2*pi)
 
    'Find the instantaneous y velocity = dy/dt
    Vyinst = Vy0 - g*Tc
 
    'Find the instantaneous x velocity = dx/dt
    Vxinst = Vx0
 
    'Find the instantaneous velocity without regard
    'to direction = sqrt(Vx^2 + Vy^2)
    Vinst = (Vxinst^2 + Vyinst^2)^0.5
 
    'Find the slope of the path of the ball at this instant in time
    'AA = -1*g/(2*Vx0^2)
    'BB = (Vy0/Vx0) + (g*x0/(2*Vx0^2))
    'CC = y0 - Vy0*x0/Vx0 = g*x0^2/(2*Vx0^2)
    'Slope.inst = 2*AA*Ballx + BB

    'Determine the ball's velocity energy
    Evel = (1/2)*Mass*Vinst^2
 
    'Determine the ball's gravitational potential energy
    Egrp = Mass*g*Bally
 
    'Determine the ball's total energy
    Etot = Evel + Egrp
    Print #main.txtSimStatus, "Calculating: P="; Pos; " E="; Int(Etot); " V="; Int(Vinst); " X="; Int(Ballx); " Y="; Int(Bally)
 
    'Check to see if the ball has entered any of the four impact zones
    LeftIzoneEntry  = 0
    TopIzoneEntry = 0
    RightIzoneEntry  = 0
    BottIzoneEntry = 0
    ULCornerEntry = 0
    URCornerEntry = 0
    LRCornerEntry = 0
    LLCornerEntry = 0
    WallContactMade = 0
 
    'Check the Left Impact Zone
    If (Ballx <= LeftImpactBoundaryX) and (Bally >= LeftImpactBoundaryBot) and (Bally <= LeftImpactBoundaryTop) Then
 
        WallContactMade = 1
        LeftIzoneEntry  = 1
        Ballx = LeftImpactBoundaryX
 
        NewFlightAngleRads = (pi - FlightAngleRads)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check the Top Impact Zone
    If (Bally >= TopImpactBoundaryY) and (Ballx >= TopImpactBoundaryL) and (Ballx <= TopImpactBoundaryR) Then
 
        WallContactMade = 1
        TopIzoneEntry  = 1
        Bally = TopImpactBoundaryY
 
        NewFlightAngleRads = (2*pi - FlightAngleRads)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check the Right Impact Zone
    If (Ballx >= RightImpactBoundaryX) and (Bally >= RightImpactBoundaryBot) and (Bally <= RightImpactBoundaryTop) Then
 
        WallContactMade = 1
        RightIzoneEntry  = 1
        Ballx = RightImpactBoundaryX
 
        NewFlightAngleRads = (pi - FlightAngleRads)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check the Bott Impact Zone
    If (Bally <= BottImpactBoundaryY) and (Ballx >= BottImpactBoundaryL) and (Ballx <= BottImpactBoundaryR) Then
 
        WallContactMade = 1
        BottIzoneEntry  = 1
        Bally = BottImpactBoundaryY
 
        NewFlightAngleRads = (2*pi - FlightAngleRads)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check entry into the Upper Left Corner
    If (Bally >= TopImpactBoundaryY) and (Ballx <= LeftImpactBoundaryX) Then
        WallContactMade = 1
        ULCornerEntry  = 1
        Bally = TopImpactBoundaryY
        Ballx = LeftImpactBoundaryX
 
        NewFlightAngleRads = (FlightAngleRads + pi)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check entry into the Upper Right Corner
    If (Bally >= TopImpactBoundaryY) and (Ballx >= RightImpactBoundaryX) Then
        WallContactMade = 1
        URCornerEntry  = 1
        Bally = TopImpactBoundaryY
        Ballx = RightImpactBoundaryX
 
        NewFlightAngleRads = (FlightAngleRads + pi)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check entry into the Lower Right Corner
    If (Bally <= BottImpactBoundaryY) and (Ballx >= RightImpactBoundaryX) Then
        WallContactMade = 1
        LRCornerEntry  = 1
        Bally = BottImpactBoundaryY
        Ballx = RightImpactBoundaryX
 
        NewFlightAngleRads = (FlightAngleRads + pi)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
    If (WallContactMade = 1) Then [Finished.Checking.Impact.Zones]
 
    'Check entry into the Lower Left Corner
    If (Bally <= BottImpactBoundaryY) and (Ballx <= LeftImpactBoundaryX) Then
        WallContactMade = 1
        LLCornerEntry  = 1
        Bally = BottImpactBoundaryY
        Ballx = LeftImpactBoundaryX
 
        NewFlightAngleRads = (FlightAngleRads + pi)
        If (NewFlightAngleRads > 2*pi) Then
            NewFlightAngleRads = NewFlightAngleRads - 2*pi
        End If
        If (NewFlightAngleRads < 0) Then
            NewFlightAngleRads = 2*pi + NewFlightAngleRads
        End If
        NewFlightAngleDegs = (NewFlightAngleRads/(2*pi))*(360)
        NewVinst = Vinst * VelocityDecay
 
    End If
 
 
[Finished.Checking.Impact.Zones]
 
    'If wall contact has been made, then reset the initial velocity,
    'reset x0 and y0, and reset Tc to zero, but not Tacum
    If (WallContactMade = 1) Then
        x0 = Ballx
        y0 = Bally
        LastBallx = x0
        LastBally = y0
        Vx0 = NewVinst * Cos(NewFlightAngleRads)
        Vy0 = NewVinst * Sin(NewFlightAngleRads)
 
        Tc = 0  'This must be done to properly calculate the position after wall contact
                'However, accumulated time is *not* reset.

    End If
 
    'End the calculation of the ball position if
    'the ball's velocity and y position have reach
    'the minimum threshholds; or if the number
    'of calculated postions has reached 9999.

    If (abs(Vinst) <= 6.0) and (Bally <= 6.0) Then [Stop.Calculating.Ball.Position]
    If (Pos > 14999) Then [Stop.Calculating.Ball.Position]
 
        LastBallx = Ballx
        LastBally = Bally
        Tc = Tc + TI
        Tacum = Tacum + TI
        SetX$ = " " + Str$(45 + Ballx)
        SetY$ = " " + Str$(260 - Bally)
        'Print #main.graphicbox1, "set" + SetX$ + SetY$

        GoTo [Next.Ball.Position]
 
 
[Stop.Calculating.Ball.Position]
 
    Print #main.graphicbox1, "fill white"
    GoSub [Draw.Wall.Boundaries]
    GoSub [Plot.Xhairs.at.Starting.Point]
 
 
    Print #main.txtSimStatus, "Building ball position array..."
 
    For i = 1 to Pos
        Scan
        SetX$(i) = " " + Str$(45 + Ballx(i))
        SetY$(i) = " " + Str$(260 - Bally(i))
    Next i
 
    Print #main.txtSimStatus, "Counting down..."
    Timer 1000, [In.3.seconds]
    Wait
    [In.3.seconds]
    Print #main.txtSimStatus, "Simulation in 3 seconds..."
    Timer 1000, [In.2.seconds]
    Wait
    [In.2.seconds]
    Print #main.txtSimStatus, "Simulation in 2 seconds..."
    Timer 1000, [In.1.seconds]
    Wait
    [In.1.seconds]
    Print #main.txtSimStatus, "Simulation in 1 second..."
    Timer 1000, [In.0.seconds]
    Wait
    [In.0.seconds]
    Timer 0
 
    Print #main.txtSimStatus, "Simulation plot in progress..."
 
    If (TrailPreserved = 1) Then SetCode$ = "set"
    If (TrailPreserved = 0) Then SetCode$ = "place"
 
    Print #main.graphicbox1, "rule XOR"
 
    i = 1
        'waste a little time in this j-loop
            k = 0
            [Increment.k.By.1]
            k = k + 1
            If (k < SimSpeed) Then [Increment.k.By.1]
        'Enough wasting time in the loop.  Plot the ball location
        Print #main.graphicbox1, SetCode$ + SetX$(i) + SetY$(i)
        Scan
 
        Print #main.graphicbox1, "circle 3"
 
    [Plot.Next.Ball.Location]
    i = i + 1
        'waste a little time in this j-loop
            j = 0
            [Increment.j.By.1]
            j = j + 1
            If (j < SimSpeed) Then [Increment.j.By.1]
        'Enough wasting time in the loop.  Plot the ball location
        Print #main.graphicbox1, SetCode$ + SetX$(i) + SetY$(i)
        Scan
 
        Print #main.graphicbox1, "circle 3"
        Print #main.graphicbox1, "place" + SetX$(i-1) + SetY$(i-1)
        Print #main.graphicbox1, "circle 3"
 
    If (i < Pos) Then [Plot.Next.Ball.Location]
 
    Print #main.txtSimStatus, " ...Idle..."
 
    GoTo [loop]
 
 
[Draw.Wall.Boundaries]
 
    Print #main.graphicbox1, "rule OVER"
    Print #main.graphicbox1, "place 44 9"
    Print #main.graphicbox1, "size 2"
    Print #main.graphicbox1, "box 396 261"
    Print #main.graphicbox1, "size 1"
    For i = 44 to 394 step 50
        xx1$ = " " + Str$(i): xx2$ = xx1$
        yy1$ = " 260": yy2$ = " 270"
        Print #main.graphicbox1, "line" + xx1$ + yy1$ + xx2$ + yy2$
    Next i
    For i = 259 to 9 step -50
        xx1$ = " 35": xx2$ = " 45"
        yy1$ = " " + Str$(i): yy2$ = yy1$
        Print #main.graphicbox1, "line" + xx1$ + yy1$ + xx2$ + yy2$
    Next i
 
    Print #main.graphicbox1, "font courier_new 8"
    Print #main.graphicbox1, "place 10 285"
    Print #main.graphicbox1, "|x = 0      50     100    150    200    250    300    350"
 
    Print #main.graphicbox1, "place 5 262"
    Print #main.graphicbox1, "|y=  0"
    Print #main.graphicbox1, "place 5 212"
    Print #main.graphicbox1, "|y= 50"
    Print #main.graphicbox1, "place 5 162"
    Print #main.graphicbox1, "|y=100"
    Print #main.graphicbox1, "place 5 112"
    Print #main.graphicbox1, "|y=150"
    Print #main.graphicbox1, "place 5 62"
    Print #main.graphicbox1, "|y=200"
    Print #main.graphicbox1, "place 5 14"
    Print #main.graphicbox1, "|y=250"
 
    'For i = 0 to 250 step 50
    '    Print #main.graphicbox1, "place 5 " + Str$(280 - i*50)
    '    Print #main.graphicbox1, "|" + Str$(i*50)
    'Next i

    Print #main.graphicbox1, "flush"
 
 
    Return
 
 
[Calculate.and.print.initial.energy]
 
    InitialEnergy = (1/2) * Mass * BallInitV^2 + (Mass * g * BallInity)
    Print #main.BallEnergy, Str$(Int(InitialEnergy))
    Return
 
[Plot.Xhairs.at.Starting.Point]
 
    xx1$ = " " + Str$(45 + BallInitx)
    yy1$ = " " + Str$(260 - BallInity - 5)
    xx2$ = xx1$
    yy2$ = " " + Str$(260 - BallInity + 5)
    Print #main.graphicbox1, "line" + xx1$ + yy1$ + xx2$ + yy2$
    xx1$ = " " + Str$(45 + BallInitx - 5)
    yy1$ = " " + Str$(260 - BallInity)
    xx2$ = " " + Str$(45 + BallInitx + 5)
    yy2$ = yy1$
    Print #main.graphicbox1, "line" + xx1$ + yy1$ + xx2$ + yy2$
 
    Return
 
    Function ATAN2(x, y)
    pi = 3.14159265
    Result$ = "Undetermined"
    If (x = 0) and (y > 0) Then
        ATAN2 = pi / 2
        Result$ = "Determined"
    End If
    If (x = 0) and (y < 0) Then
        ATAN2 = 3 * pi / 2
        Result$ = "Determined"
    End If
    If (x > 0) and (y = 0) Then
        ATAN2 = 0
        Result$ = "Determined"
    End If
    If (x < 0) and (y = 0) Then
        ATAN2 = pi
        Result$ = "Determined"
    End If
 
    If Result$ = "Determined" Then [End.of.function]
 
 
    BaseAngle = Atn(abs(y)/abs(x))
    If (x > 0) and (y > 0) Then ATAN2 = BaseAngle
    If (x < 0) and (y > 0) Then ATAN2 = pi - BaseAngle
    If (x < 0) and (y < 0) Then ATAN2 = pi + BaseAngle
    If (x > 0) and (y < 0) Then ATAN2 = 2*pi - BaseAngle
 
    [End.of.function]
 
    End Function

Tom Nally
Steelweaver52@aol.com


Back to Nally's Code