Simulate a Bouncing Ball in VPython
Build a 3D bouncing ball simulation with real-time energy graphing.
Introduction
30 Second Summary
Drop a basketball and watch it bounce. Each time it hits the ground, it comes back a little lower. Energy is quietly leaking out of the system with every impact.
In this project, you will build a 3D bouncing ball simulation that brings Newton's laws to life. You will watch gravity pull the ball down, see it lose energy on each bounce, and track exactly where that energy goes using a real-time graph.
What You'll Build
A 3D animated bouncing ball simulation in Web VPython that applies gravity, handles collisions with energy loss, and plots kinetic, potential, and total energy over time.
By the end of this project, you'll have:
- A 3D scene with a ball and floor that you can rotate and zoom in your browser.
- A physics engine that applies gravity, updates velocity and position each time step, and handles floor collisions with energy loss.
- A real-time energy graph showing kinetic energy, potential energy, and total energy as the ball bounces.
- A secret mission where you add horizontal motion and wall collisions to make the ball ricochet around a 3D box.
Are there any prerequisites?
None. This project introduces Python basics as you go. All you need is a Google account and a modern browser (Chrome, Firefox, Safari, or Edge).
Before We Start
Before We Start...
Set Up Web VPython
Before you can simulate anything, you need a place to write and run your code. Web VPython is a free, browser-based tool built specifically for physics simulations.
You write a few lines of code, click run, and a 3D scene appears right in your browser. No downloads, no installs, no setup headaches.
In this step, get ready to:
- Sign in to Web VPython with your Google account.
- Create a new program and understand the editor.
- Build your first 3D scene with a floor and a ball.
Open Web VPython and sign in
Web VPython runs entirely in your browser. All you need is a Google account and a modern browser like Chrome, Firefox, Safari, or Edge.
- Open your browser and go to webvpython.org.
- Click Sign in in the top-right corner of the page.
- Sign in with your Google account.
After signing in, you should see a sentence that says "You are signed in as [your name] and your programs are here."
- Click here in that sentence to open your programs folder.
You should see two folders: MyPrograms and Private.
Can't see the Sign in link?
Make sure you are at webvpython.org, not a different VPython site.
Try a different browser if the page does not load. Internet Explorer is not supported. Use Chrome, Firefox, Safari, or Edge.
Help me sign in to Web VPython.
Create a new program
- Click Create New Program.
- Type Bouncing Ball as the program name and press Enter.
A code editor opens with a single line already filled in: Web VPython 3.2.
What is this first line?
Every Web VPython program must start with Web VPython 3.2 as its first line. This tells the browser which version of the VPython library to use.
Never delete this line. If you erase it, your program will not run.
Build your first 3D scene
Time to create something you can see. You will add a title to the scene, a green floor, and a red ball.
- Click on line 2 in the editor (the line below Web VPython 3.2) and paste the following code:
# Set the title that appears above the 3D scene
scene.title = "Bouncing Ball Simulation"
# Create a flat green box to act as the floor
floor = box(pos=vec(0, -0.5, 0), size=vec(10, 0.1, 10), color=color.green)
# Create a red ball above the floor
ball = sphere(pos=vec(0, 5, 0), radius=0.5, color=color.red)
What does this code do?
- scene.title sets the text that appears above the 3D canvas.
- box() creates a 3D box. The pos attribute sets its center position using a 3D vector. The size attribute sets its length, height, and width.
- sphere() creates a 3D sphere. It starts at position (0, 5, 0), which is 5 units above the center of the scene.
- vec(x, y, z) creates a 3D vector. The x-axis runs left to right, the y-axis runs up and down, and the z-axis points toward you.
- Click Run this program at the top of the editor.
You should see a 3D scene with a green floor and a red ball floating above it. The title "Bouncing Ball Simulation" appears above the canvas.
Don't see the 3D scene?
- Check that you did not accidentally delete the Web VPython 3.2 line at the top. Your code must start on line 2.
- Look for a red error box below the canvas. VPython error messages tell you the line number where the problem is.
- Make sure color is spelled the American way (not "colour"). VPython uses American spelling.
Help me fix my Web VPython scene.
Now try navigating around your 3D scene with your mouse.
- Right-click and drag (or Ctrl-drag on a single-button mouse) to rotate the camera around the scene.
- Scroll the mouse wheel to zoom in and out. On a trackpad, pinch or extend two fingers.
- Hold Shift and drag to pan the view left, right, up, or down.
Pro tip: keyboard shortcuts
Press Cmd+1 (macOS) or Ctrl+1 (Windows) to run your program without clicking the button. This saves time as you iterate on your code.
- Click Edit this program to return to the code editor.
Why Web VPython instead of Matplotlib or Pygame?
Web VPython was designed for introductory physics courses at universities like Georgia Tech and Carnegie Mellon. You write sphere() and get a 3D ball. No boilerplate, no window management, no install.
Alternatives like Matplotlib or Pygame require local Python installs, more setup code, and are limited to 2D. Web VPython lets you focus on the physics, not the graphics plumbing.
Your 3D scene is ready with a floor and a ball hanging in the air. Next up, you will give that ball some gravity and watch it fall.
Make the Ball Fall with Gravity
In the last step, you created a 3D scene with a ball and a floor. Right now, the ball just floats in midair. In the real world, gravity would pull it down immediately.
In this step, you will write the physics engine that makes the ball fall. You will translate Newton's 2nd Law (F = ma) into code and watch the ball respond to gravity in real time.
In this step, get ready to:
- Define physics constants like gravity, velocity, and a time step.
- Build an animation loop that updates the ball's velocity and position every frame.
- Understand how the Euler method turns physics equations into working code.
Define physics constants and initial conditions
Before the ball can move, it needs three pieces of information: how fast it is going, what force is acting on it, and how much time passes between each frame of the animation.
- In your Web VPython program, find the line where you created the ball (ball = sphere(...)).
- Add the physics constants below that line by pasting the following code:
# Give the ball a starting velocity of zero (it starts from rest)
ball.vel = vec(0, 0, 0)
# Gravity pulls downward at 9.8 meters per second squared
g = vec(0, -9.8, 0)
# Time step: how much time passes per frame of the animation
dt = 0.01
What do these constants mean?
- ball.vel = vec(0, 0, 0) creates a custom attribute on the ball to store its velocity. Starting at vec(0, 0, 0) means the ball begins at rest.
- g = vec(0, -9.8, 0) represents gravitational acceleration. The -9.8 is in the y-direction because gravity pulls downward.
- dt = 0.01 is the time step. Each loop iteration simulates 0.01 seconds of real time. A smaller dt gives a more accurate simulation.
What is a vector?
A vector is a value that has both a size and a direction. In VPython, vec(x, y, z) creates a 3D vector with three components.
The x-axis goes left and right, the y-axis goes up and down, and the z-axis goes forward and backward. So vec(0, -9.8, 0) means "9.8 in the downward direction, with no sideways or forward motion."
You won't see a change yet. These constants are used by the animation loop you will write next.
Write the animation loop
The animation loop is the heart of your physics simulation. It runs over and over, updating the ball's velocity and position on every frame to create smooth motion.
- Add the animation loop at the bottom of your program by pasting the following code below everything you have written so far:
# Animation loop: runs forever, updating physics each frame
while True:
rate(100) # Limit to 100 frames per second
# Update velocity: gravity accelerates the ball downward
ball.vel = ball.vel + g * dt
# Update position: move the ball based on its current velocity
ball.pos = ball.pos + ball.vel * dt
What does this code do?
- while True: creates an infinite loop. The simulation keeps running until you stop it.
- rate(100) limits the loop to 100 iterations per second. This gives VPython time to redraw the 3D scene. Without rate(), the screen never updates and your browser tab may freeze.
- ball.vel = ball.vel + g * dt is Newton's 2nd Law in action. Since F = ma and the only force is gravity, the acceleration equals g. Each frame, gravity adds a little more downward speed.
- ball.pos = ball.pos + ball.vel * dt moves the ball based on its current velocity. The faster the ball is going, the more it moves each frame.
- Click Run this program to start the simulation.
You should see the ball drop from its starting position and fall straight through the floor. It disappears below the scene because there is no collision detection yet.
Ball not moving?
- Make sure your while True: loop is at the bottom of your program, after all the object creation code.
- Check that rate(100) is the first line inside the loop. Without it, the screen never redraws and your browser tab may freeze.
- Confirm that ball.vel, g, and dt are defined above the loop, not inside it.
- If your browser tab froze, close the tab and reopen your program. Help me debug why my ball isn't moving in Web VPython.
Understand the Euler method
Those two update lines inside your loop are doing something powerful. They are using a technique called the Euler method to simulate physics.
What is the Euler method?
The Euler method is the simplest form of numerical integration. It breaks continuous motion into tiny discrete steps.
In each step, you calculate the new velocity from the current acceleration. Then you calculate the new position from the current velocity. The two formulas are:
- v_new = v_old + a * dt (velocity changes because of acceleration).
- pos_new = pos_old + v * dt (position changes because of velocity).
This is the foundation of every physics simulation, from bouncing balls to rocket launches to video game engines. The smaller your dt, the more accurate the simulation becomes.
Why does the ball fall through the floor?
Your code updates the ball's position every frame, but it never checks whether the ball has hit the floor. The ball does not "know" the floor exists. You will fix this in the next step by adding collision detection.
Awesome, I've got everything!
Great. Double check you have saved your program before moving on.
I'd like to double check the full code
Here is what your full program should look like so far:
Web VPython 3.2
# Set up the scene title
scene.title = "Bouncing Ball Simulation"
# Create a green floor
floor = box(pos=vec(0, -0.5, 0), size=vec(10, 0.1, 10), color=color.green)
# Create a red ball above the floor
ball = sphere(pos=vec(0, 5, 0), radius=0.5, color=color.red)
# Give the ball a starting velocity of zero (it starts from rest)
ball.vel = vec(0, 0, 0)
# Gravity pulls downward at 9.8 meters per second squared
g = vec(0, -9.8, 0)
# Time step: how much time passes per frame of the animation
dt = 0.01
# Animation loop: runs forever, updating physics each frame
while True:
rate(100) # Limit to 100 frames per second
# Update velocity: gravity accelerates the ball downward
ball.vel = ball.vel + g * dt
# Update position: move the ball based on its current velocity
ball.pos = ball.pos + ball.vel * dt
Your ball is now responding to gravity. Next up, you will add collision detection and energy loss so the ball bounces off the floor and gradually comes to rest.
Add Bouncing and Energy Loss
In the last step, you got the ball to fall under gravity using Newton's 2nd Law and the Euler method. The problem? Your ball plummets straight through the floor into the void.
In this step, you'll teach the simulation what a floor actually means. You'll detect when the ball hits the ground, bounce it back up, and make each bounce lose a little energy so the ball gradually settles down.
In this step, get ready to:
- Add collision detection so the ball bounces off the floor.
- Apply a coefficient of restitution so the ball loses energy on each bounce.
- Add a trajectory trail and experiment with different energy loss values.
Add collision detection
Right now, nothing in your code tells the ball that the floor exists. You need a way to detect the moment the ball reaches the floor and react to it.
The floor sits at y = 0, and the ball has a radius. So the ball touches the floor when its center drops to y = ball.radius. When that happens, you reverse the ball's vertical velocity to send it back up.
- Inside your while True loop, add this collision check after the two lines that update velocity and position:
# Collision detection: check if ball has reached the floor
if ball.pos.y < ball.radius:
ball.pos.y = ball.radius # Reset ball to sit on the floor
ball.vel.y = -ball.vel.y # Reverse the vertical velocity
What does this code do?
- ball.pos.y < ball.radius checks whether the bottom of the ball has touched or passed through the floor. Since the ball's position is measured from its center, the bottom of the ball is at pos.y - radius.
- ball.pos.y = ball.radius snaps the ball back to sit exactly on the floor. Without this, the ball could sink a little deeper into the floor each frame.
- -ball.vel.y flips the direction of the vertical velocity. If the ball was moving downward (negative y), it now moves upward (positive y).
- Click the Run this program button to see the result.
The ball should drop, hit the floor, and bounce back up to exactly the same height. It bounces forever because no energy is being lost.
Ball still falling through the floor?
- Make sure the if block is inside the while True loop. It needs to be indented at the same level as the velocity and position update lines.
- Check that the two lines inside the if block are indented one level deeper than the if line itself. Python uses indentation to know which lines belong to the if statement.
- Help me debug my collision detection code.
Add the coefficient of restitution
A ball that bounces forever is not realistic. In the real world, every bounce loses some energy to heat, sound, and deformation. The coefficient of restitution (COR) captures this. It is the ratio of the ball's speed after a bounce to its speed before the bounce.
What is the coefficient of restitution?
A COR of 1.0 means a perfectly elastic bounce. The ball keeps 100% of its speed and bounces forever. A COR of 0.0 means the ball sticks to the floor on impact.
Real-world balls fall somewhere in between. A tennis ball has a COR around 0.5 to 0.8. A basketball is about 0.7 to 0.8. A super bouncy rubber ball can reach 0.9. You'll use 0.85 for this simulation.
- At the top of your program, right below the line where you defined dt, add the COR variable:
# Coefficient of restitution: fraction of speed kept after each bounce
cor = 0.85
What does this value mean?
Setting cor = 0.85 means the ball keeps 85% of its speed after each bounce. Since kinetic energy depends on velocity squared, the ball actually loses about 28% of its kinetic energy per bounce (0.85 * 0.85 = 0.7225).
- Now update your collision detection code inside the while True loop. Find this line:
ball.vel.y = -ball.vel.y # Reverse the vertical velocity
- Replace it with this line that applies the COR:
ball.vel.y = -ball.vel.y * cor # Reverse velocity and reduce by COR
- Click Run this program to see the result.
The ball should now bounce lower and lower with each impact, gradually settling toward the floor. Each bounce is 85% as fast as the one before it.
Ball still bouncing to the same height?
- Double check that you replaced the old line (-ball.vel.y) with the new one (-ball.vel.y * cor). If both lines exist, the old one runs first and the COR line has no effect.
- Make sure cor = 0.85 is defined before the while True loop, not inside it.
- Help me fix my coefficient of restitution code.
Add a trajectory trail and experiment
A trail lets you see the ball's entire path drawn behind it as it moves. This makes the decreasing bounce heights visible all at once.
- Scroll up to the line where you created the ball (sphere()). Find this line:
ball = sphere(pos=vec(0, 10, 0), radius=0.5, color=color.red)
- Add make_trail=True to the sphere so the line now looks like this:
ball = sphere(pos=vec(0, 10, 0), radius=0.5, color=color.red, make_trail=True)
- Click Run this program to see the trail in action.
You should see a continuous curve tracing the ball's path. The arcs get shorter and shorter as the ball loses energy with each bounce.
What does make_trail do?
When make_trail=True is set on an object, Web VPython draws a curve behind the object every time the scene renders. Each new position gets added to the trail automatically. You can also use retain=50 to limit the trail to the last 50 points, which keeps things tidy for longer simulations.
Now try experimenting with different COR values to see how they change the simulation.
- Change cor to 0.95 and run the program. The ball barely loses energy and bounces for a long time.
- Change cor to 0.5 and run the program. The ball loses energy fast and settles quickly.
- Change cor to 0.7 and run the program. This is close to a real basketball.
- Set cor back to 0.85 before moving on to the next step.
Not seeing a trail?
- Make sure make_trail=True is inside the sphere() parentheses, separated from the other parameters by a comma.
- If the trail looks like it is missing points, check that your rate() value is not higher than 100. Web VPython renders the scene about 60 times per second, so very high rates can skip trail points.
- Help me fix the trail on my bouncing ball.
Awesome, I've got everything!
Double check that you have saved your program with cor set back to 0.85 before moving on.
I'd like to double check the full code
Here is the full program so far. Compare it with yours to make sure everything matches.
Web VPython 3.2
# Set up the scene
scene.title = "Bouncing Ball Simulation"
# Create the floor and ball
floor = box(pos=vec(0, 0, 0), size=vec(20, 0.1, 20), color=color.green)
ball = sphere(pos=vec(0, 10, 0), radius=0.5, color=color.red, make_trail=True)
# Physics constants
ball.vel = vec(0, 0, 0) # Initial velocity
g = vec(0, -9.8, 0) # Gravitational acceleration
dt = 0.01 # Time step
cor = 0.85 # Coefficient of restitution
# Animation loop
while True:
rate(100)
# Update velocity using Newton's 2nd Law (F = ma, so a = g)
ball.vel = ball.vel + g * dt
# Update position using velocity
ball.pos = ball.pos + ball.vel * dt
# Collision detection: check if ball has reached the floor
if ball.pos.y < ball.radius:
ball.pos.y = ball.radius # Reset ball to sit on the floor
ball.vel.y = -ball.vel.y * cor # Reverse velocity and reduce by COR
Your ball now bounces realistically, losing energy on every impact. Next up, you'll add a real-time energy graph that tracks exactly where that energy goes.
Graph the Energy in Real Time
Your ball is bouncing and losing height with every impact. You can see the energy draining, but how much energy is the ball losing at each bounce?
In this step, you will add a real-time graph that tracks kinetic energy, potential energy, and total energy as the simulation runs. The graph makes the physics visible: energy swaps between KE and PE in mid-air, and drops at every collision.
In this step, get ready to:
- Create a live energy graph with three color-coded curves.
- Calculate kinetic, potential, and total energy inside the animation loop.
- Analyze the graph to see conservation of energy in action.
Set up the energy graph and curves
Web VPython has a built-in graphing system. You create a graph() object to define the chart area, then add gcurve() objects for each data series you want to plot.
To display the graph beside the 3D scene instead of below it, you need to set align='left' on both the canvas and the graph.
- First, update the scene line at the top of your program. Find this line:
scene.title = "Bouncing Ball Simulation"
- Replace it with this line, which adds align='left' so the 3D scene moves to the left side of the page:
scene = canvas(title="Bouncing Ball Simulation", align='left')
What does this change?
Previously, you set scene.title on the default canvas. Now you are creating the canvas explicitly with canvas() so you can pass align='left'. This pushes the 3D scene to the left, leaving room for the graph on the right.
- Now add the graph and three curves. Place this code after the scene line but before the floor and ball lines:
# Create an energy graph next to the 3D scene
energy_graph = graph(title="Energy vs. Time",
xtitle="Time (s)", ytitle="Energy (J)",
align='left')
# Three curves: one for each type of energy
ke_curve = gcurve(color=color.red, label="Kinetic Energy")
pe_curve = gcurve(color=color.blue, label="Potential Energy")
te_curve = gcurve(color=color.green, label="Total Energy")
What does this code do?
- graph() creates a 2D chart area with a title and axis labels. Setting align='left' places it next to the 3D canvas.
- Each gcurve() is a data series on the graph. You will plot points onto these curves inside the animation loop.
- The label text appears in the graph legend so you can tell the three curves apart.
- Click Run this program to confirm the graph appears beside the 3D scene.
You should see the 3D bouncing ball on the left and an empty graph on the right. The graph has axis labels and a color-coded legend in the upper right corner.
Graph appearing below the scene instead of beside it?
- Make sure both the canvas and the graph have align='left'. If either one is missing this setting, they stack vertically.
- If your browser window is too narrow, the graph drops below the scene. Try making your browser window wider.
- Check that the graph() line comes after the canvas() line in your program.
- Help me fix my graph layout.
Calculate and plot energy inside the animation loop
The graph is ready, but it is empty because you are not plotting any data yet. You need to calculate the three energies on every frame of the animation and add a point to each curve.
What are the three energy formulas?
- Kinetic energy is the energy of motion: KE = 0.5 * m * v². The faster the ball moves, the more kinetic energy it has.
- Potential energy is stored energy from height: PE = m * g * h. The higher the ball, the more potential energy it has.
- Total energy is KE + PE. While the ball is in the air, total energy stays constant because KE and PE trade back and forth. At each bounce, some total energy is lost.
- You need a time counter to track the x-axis of the graph. Add this line with your other variables at the top of the program, near dt and g:
# Track elapsed time for the graph's x-axis
t = 0
- You also need a mass for the ball. Energy formulas require mass, so add this line near your other constants:
# Mass of the ball in kilograms
m = 1
Why didn't we need mass before?
Gravity accelerates all objects equally regardless of mass (F = ma, but a = g for gravity). So the ball's motion did not depend on mass. Energy calculations do depend on mass, which is why you are adding it now.
- Now add the energy calculations and plotting inside your while True loop. Place this code at the end of the loop, after the collision detection block:
# Calculate the three energies
KE = 0.5 * m * mag(ball.vel)**2 # kinetic energy: half * mass * speed squared
PE = m * 9.8 * ball.pos.y # potential energy: mass * g * height
TE = KE + PE # total energy: sum of KE and PE
# Plot each energy value at the current time
ke_curve.plot(t, KE)
pe_curve.plot(t, PE)
te_curve.plot(t, TE)
# Advance the time counter
t = t + dt
What does this code do?
- mag(ball.vel) returns the speed of the ball (the magnitude of the velocity vector). Squaring it gives v² for the kinetic energy formula.
- ball.pos.y is the ball's height above the origin. This is the h in the potential energy formula.
- Each .plot(t, value) call adds a single data point to the curve. Because this runs every frame, the graph builds up smoothly over time.
- t = t + dt advances the clock by one time step so each point lands at the correct position on the x-axis.
- Click Run this program to see the energy graph populate in real time as the ball bounces.
You should see three colored lines drawing across the graph. The red line (KE) and blue line (PE) oscillate as the ball rises and falls. The green line (total energy) stays flat while the ball is airborne, then drops at each bounce.
Graph lines not appearing?
- Make sure the energy calculation lines are indented inside the while True loop. If they are not indented, they only run once (before the loop starts) and plot a single point.
- Check that you defined t = 0 and m = 1 before the loop. Missing either variable causes an error.
- Confirm that the curve variable names in .plot() match the names you used when creating the gcurve() objects (ke_curve, pe_curve, te_curve).
- Help me debug my energy graph.
Analyze the energy graph
The graph tells a clear physics story. Take a moment to read what it is showing you.
- Watch the graph as the ball bounces. Focus on the green total energy line.
What is the graph telling you?
- Between bounces, the green line (total energy) is flat. KE and PE trade back and forth perfectly. This is conservation of energy in action.
- At the top of each arc, the ball is momentarily still. KE drops to zero and PE is at its maximum.
- At the bottom of each arc (just before impact), PE is near zero and KE is at its maximum.
- At each bounce, the green line drops suddenly. That drop is the energy lost to the collision, controlled by your coefficient of restitution.
- Try changing the cor value to 0.95 and run the program again. Notice how the total energy drops more slowly.
- Try cor = 0.5 and watch how quickly the ball loses energy and comes to rest.
- Set cor back to 0.85 when you are done experimenting.
Extra for Experts: what happens at COR = 1.0?
A COR of 1.0 means a perfectly elastic bounce. No energy is lost at all. If you try it, the green total energy line stays perfectly flat forever. In the real world, no material achieves a COR of exactly 1.0. A steel ball on a steel plate gets close at around 0.95.
Awesome, I've got everything!
Double check you have saved your program in Web VPython.
I'd like to double check the full code
Here is the complete program with everything from Steps 1 through 4. Compare it to your code to make sure nothing is missing.
Web VPython 3.2
# Set up the 3D scene, aligned left so the graph fits beside it
scene = canvas(title="Bouncing Ball Simulation", align='left')
# Create an energy graph next to the 3D scene
energy_graph = graph(title="Energy vs. Time",
xtitle="Time (s)", ytitle="Energy (J)",
align='left')
# Three curves: one for each type of energy
ke_curve = gcurve(color=color.red, label="Kinetic Energy")
pe_curve = gcurve(color=color.blue, label="Potential Energy")
te_curve = gcurve(color=color.green, label="Total Energy")
# Create the floor and ball
floor = box(pos=vec(0, -0.5, 0), size=vec(10, 0.1, 4), color=color.green)
ball = sphere(pos=vec(0, 5, 0), radius=0.3, color=color.red, make_trail=True)
# Physics constants and initial conditions
ball.vel = vec(0, 0, 0) # ball starts at rest
g = vec(0, -9.8, 0) # gravitational acceleration
dt = 0.01 # time step in seconds
cor = 0.85 # coefficient of restitution
m = 1 # mass of the ball in kilograms
t = 0 # elapsed time for the graph
# Animation loop
while True:
rate(100)
# Update velocity using Newton's 2nd Law: a = g
ball.vel = ball.vel + g * dt
# Update position using velocity
ball.pos = ball.pos + ball.vel * dt
# Collision detection: has the ball hit the floor?
if ball.pos.y < ball.radius:
ball.pos.y = ball.radius # prevent sinking into the floor
ball.vel.y = -ball.vel.y * cor # reverse and reduce y-velocity
# Calculate the three energies
KE = 0.5 * m * mag(ball.vel)**2 # kinetic energy
PE = m * 9.8 * ball.pos.y # potential energy
TE = KE + PE # total energy
# Plot each energy value at the current time
ke_curve.plot(t, KE)
pe_curve.plot(t, PE)
te_curve.plot(t, TE)
# Advance the time counter
t = t + dt
You now have a complete physics simulation with a real-time energy graph. You can see exactly how energy moves between kinetic and potential forms, and how the coefficient of restitution controls how quickly the system loses energy. Next up, you will tackle a secret mission to make the ball ricochet around a 3D box.
Secret mission
Add Horizontal Motion and Wall Collisions
Your ball only bounces up and down right now. What if it could ricochet off walls in every direction? In this secret mission, you'll build a 3D box enclosure and give the ball horizontal velocity so it bounces around like a ball inside a squash court. Watch as it gradually loses all its energy and comes to rest.
Before you go
Clean Up Your Resources
This project runs entirely in the browser using Web VPython, so there are no ongoing costs or cloud resources to worry about. Decide whether to keep your program saved, or delete it from your Web VPython account.
Resources you used:
- Your "Bouncing Ball" program saved in your Web VPython account at webvpython.org.
- Your Google account (used to sign in to Web VPython).
Keep everything running
No action needed. Choose this if you want to keep experimenting with your bouncing ball simulation or build on it further.
- Your program stays saved in your Web VPython account and you can access it anytime by signing back in.
- There are no running processes or costs associated with keeping it.
Pause - I'll come back to this later
Your program is already saved in the cloud through your Google account. There is nothing to pause since Web VPython does not run anything in the background.
- Close your browser tab. Your program is saved automatically.
- When you are ready to return, go to webvpython.org, sign in with Google, and your program will be right where you left it.
Delete - I don't want to use this again
Remove your program from Web VPython entirely. Choose this if you are done with the project and do not plan to revisit it.
- Go to webvpython.org and sign in with your Google account.
- Find your "Bouncing Ball" program in your program list.
- Delete the program from your account.
- If you no longer need Web VPython, you can revoke its access from your Google account under your Google security settings.
Mission accomplished
That's a Wrap!
Nice work! You just built a real physics engine from scratch using Web VPython.
A ball drops, accelerates under gravity, slams into the floor, and bounces back up a little lower each time. Your real-time energy graph proves exactly where that energy goes.
Here's what you learned:
- Implemented Newton's 2nd Law (F = ma) and the Euler method to simulate gravity, updating velocity and position each time step.
- Used the coefficient of restitution to model energy loss at each bounce, making the ball settle realistically over time.
- Built a real-time energy graph tracking kinetic, potential, and total energy to visualize conservation of energy in flight and dissipation at each collision.
- Added horizontal motion and wall collisions to create a full 3D ricochet simulation inside a box.
Ready to quiz yourself?