BallSim

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 code format="vb" x = 340 y = 10 ball initial velocity = 200 ft/sec initial angle = 135 degrees velocity retention = 95% simulation speed = 8 code 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
--- code format="vb" '************************************************ '  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 code --- Tom Nally Steelweaver52@aol.com

--- Back to Nally's Code