Simulating a Bouncing Ball in Python

The Real World in Python: Coding A Bouncing Ball (Bouncing Ball Series #1)

The real world can be a difficult place to understand. Whether you’re trying to make sense of the people that make up the real world and their actions, or the physical world itself, things are never easy. Sometimes, coding can help understand what’s going on and maybe, just maybe, help find a solution to a problem. Perhaps one day, Python programs will be used to solve all the world’s problems! But I’m not that ambitious in this blog post, so I’ll choose to talk about how we can create a simulation of a bouncing ball using Python.

Often in this blog, I use real-world analogies to understand Python topics. Here, I’m using Python to understand better a real-world process. Granted, the physics of a bouncing ball may not be the biggest mystery in the universe, but the exercise of representing real-world processes computationally often helps you understand that particular process better.

Using The turtle Module to Simulate A Bouncing Ball in Python

It’s most fun and most instructive to work on this simulation from first principles without using any "fancy" modules. The turtle module is a brilliant tool to create such physical simulations as it’s relatively straightforward to use, and it gives you full control over whatever happens in your animation. The turtle module is part of the standard library, and therefore, you already have it on your computer if you’ve installed Python!

A very brief primer of turtle basics

The main class defined in the turtle module is Turtle. The "turtle" you create will obey your instructions and move around the screen, drawing lines and other shapes as it goes along. You can create an instance of turtle.Turtle and explore some of its methods:

import turtle

ball = turtle.Turtle()

ball.forward(100)
ball.left(45)
ball.pensize(5)
ball.color("dark salmon")
ball.forward(50)
ball.right(90)
ball.penup()
ball.forward(100)
ball.right(135)
ball.pensize(10)
ball.color("light green")
ball.pendown()
ball.forward(200)
ball.shape("circle")

turtle.done()

I’ll let you try this code out yourself to see the artistic masterpiece it produces! Once you create the instance of the Turtle class, which you call ball, you apply a number of operations that move and steer the turtle, change its colour and the thickness of the line it draws, and more. The final line in this code keeps the program running in a loop until you choose to close the window to terminate the program.

Creating A Ball That Falls

Let’s look at the first steps you’ll need to create this animation. You’ll start by creating a falling ball. You’ll make it bounce later:

  • Create a turtle.Turtle that will represent the ball
  • Change the shape and colour of the Turtle as required
  • Move Turtle by a small step that will represent the speed of the ball
  • Repeat in a while loop

Let’s translate these steps into Python code:

import turtle

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

while True:
    ball.sety(ball.ycor() - 1)

The initial position of a Turtle object is in the middle of the window. This position corresponds to the coordinates (0, 0). Although you can use the method forward() to move the ball, you’re using a combination of the methods sety() and ycor() to move the ball. You’re setting the y-coordinate using sety() to its current value, which is what ycor() returns, minus 1 pixel.

The ball is now falling. However, this is not how real balls fall in the real world. Gravity accelerates the ball towards the ground so that the speed of the ball increases with time.

Taking Into Account The Effects Of Gravity

In this post, I want to focus on the most basic translation from physics to simulation. Rather than using the distance in metres and time in seconds and the physical constants that are required to work out how much a ball accelerates, I’ll use distance in pixels and time measured in iterations of a while loop. By using arbitrary units, I can focus on the key points that make this simulation work. A later post in the Bouncing Ball series will take care of the details.

You can define a variable called velocity which represents the velocity of the ball at any time during the simulation. The velocity will be measured in pixels per iteration rather than metres per second.

The velocity will increase by a fixed amount each iteration of the while loop, which is the base time unit used. The amount the velocity increases by is the acceleration due to gravity:

import turtle

gravity = -0.05   # pixels/(time of iteration)^2
velocity = 0   # pixels/(time of iteration)

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

while True:
    ball.sety(ball.ycor() + velocity)
    velocity += gravity

I’m choosing the value for acceleration due to gravity arbitrarily, as in this version, I’m not using real-world units. I’m also ignoring air resistance to keep things on the simpler side. This is what the simulation looks like at the moment:

The ball starts off with a velocity of 0, but then accelerates downwards. Before turning the ball into a bouncing ball, I’ll say a few words on how to avoid making the animation lag too much.

Better Animation Control

This post is not about animation or the turtle module, so I’ll keep this section brief. When a Turtle moves or turns on the screen, one of the slowest processes is to update the image on the screen. In the turtle module, when a Turtle moves, by default, several steps of that motion are displayed. For example, if you turn a Turtle by 90 degrees, you’ll see the Turtle turn relatively gradually on the screen as it goes from its starting heading to its final one.

When you have a lot of movement occurring in an animation, you would like the coordinates and the values of the angles to change as required "behind the scenes", and then to update the picture only once every so often. The simplest way to do this is to choose to update the frame of the animation only once each iteration of the while loop. Each iteration of the loop represents a frame of the animation.

In the turtle module, you can achieve this with the following steps:

  • Create an instance of a turtle.Screen object. This object is created automatically when you use the turtle module, but creating it explicitly allows you to assign it to a variable.
  • Use the tracer() method of the Screen object using the value 0 as an argument. This turns the animation off. When tracer() is set to 0, the graphics will not be displayed until you call the update() method.
  • Call the update() method of the Screen object within the while loop to update the graphics once per iteration.

The modified code is now as follows:

import turtle

gravity = -0.005   # pixels/(time of iteration)^2
velocity = 0   # pixels/(time of iteration)

window = turtle.Screen()
window.tracer(0)

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

while True:
    ball.sety(ball.ycor() + velocity)
    velocity += gravity

    window.update()

Note that once you set the animation to update only once per iteration, the animation will go faster. Therefore, you’ll need to adjust the velocity value to a smaller number to avoid the ball shooting off the screen too quickly. You may choose a different value to suit what works best on your computer.

Bouncing Ball in Python

You’re getting there, but to create a simulation of a bouncing ball in Python, you now need to make the ball bounce.

The first step is to set the size of the window you’re using for your animation so that you know the coordinates of the floor. You can use the Screen method setup() for this with the width and height in pixels as arguments.

You can then rely on the Turtle method ycor() to return the ball’s y-position in every frame of the animation. An if statement will help you determine whether the ball has hit the floor:

import turtle

gravity = -0.005  # pixels/(time of iteration)^2
velocity = 0  # pixels/(time of iteration)

width = 600
height = 800

window = turtle.Screen()
window.setup(width, height)
window.tracer(0)

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

while True:
    ball.sety(ball.ycor() + velocity)
    velocity += gravity
    if ball.ycor() < -height / 2:
        velocity = -velocity

    window.update()

Recall that as the coordinates at the centre of the screen are (0, 0), the bottom of the screen is represented by -height/2. You now have a bouncing ball in Python:

However, this is still not quite what happens in real life. The ball always bounces up to the same height and will keep doing so forever. You’ll need one more modification.

Losing Some Energy With Every Bounce

Each time the ball bounces on the ground, it loses a bit of energy. This is why the height of a bouncing ball is lower with every bounce in the real world. This is not happening yet in the simulation. You can fix this by taking away some of the ball’s velocity with every bounce:

import turtle

gravity = -0.005  # pixels/(time of iteration)^2
velocity = 0  # pixels/(time of iteration)
energy_loss = 0.95

width = 600
height = 800

window = turtle.Screen()
window.setup(width, height)
window.tracer(0)

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

while True:
    ball.sety(ball.ycor() + velocity)
    velocity += gravity
    if ball.ycor() < -height / 2:
        velocity = -velocity * energy_loss

    window.update()

The simulation of the bouncing ball is looking a lot more realistic now:

At the moment, all you can simulate is dropping a ball vertically downwards. The final step in this simulation will allow you to toss the ball in any direction.

Moving The Ball Sideways

In the first line in the while loop, you’re using sety() to move the ball along the y-axis. You can include a similar line to move the ball along the x-axis. You’ll need to do some refactoring to change the name velocity to y_velocity everywhere in the code, as now you’ll need two velocity components, y_velocity and x_velocity. You can set the initial values of these two velocity components to any values you wish to simulate "tossing the ball":

import turtle

gravity = -0.005  # pixels/(time of iteration)^2
y_velocity = 1  # pixels/(time of iteration)
x_velocity = 0.25  # pixels/(time of iteration)
energy_loss = 0.95

width = 600
height = 800

window = turtle.Screen()
window.setup(width, height)
window.tracer(0)

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

while True:
    ball.sety(ball.ycor() + y_velocity)
    ball.setx(ball.xcor() + x_velocity)
    y_velocity += gravity
    if ball.ycor() < -height / 2:
        y_velocity = -y_velocity * energy_loss

    window.update()

The gravity adjustment only affects the y_velocity component, and the if statement dealing with the bouncing off the ground also only affects the y_velocity.

Bouncing Off The Walls

However, the ball now soon goes off the screen. You need to put some walls in too. I’m also going to add some comments in the code at this stage to make it more readable:

import turtle

# Set key parameters
gravity = -0.005  # pixels/(time of iteration)^2
y_velocity = 1  # pixels/(time of iteration)
x_velocity = 0.25  # pixels/(time of iteration)
energy_loss = 0.95

width = 600
height = 800

# Set window and ball
window = turtle.Screen()
window.setup(width, height)
window.tracer(0)

ball = turtle.Turtle()

ball.penup()
ball.color("green")
ball.shape("circle")

# Main loop
while True:
    # Move ball
    ball.sety(ball.ycor() + y_velocity)
    ball.setx(ball.xcor() + x_velocity)

    # Acceleration due to gravity
    y_velocity += gravity

    # Bounce off the ground
    if ball.ycor() < -height / 2:
        y_velocity = -y_velocity * energy_loss
        # Set ball to ground level to avoid it getting "stuck"
        ball.sety(-height / 2)

    # Bounce off the walls (left and right)
    if ball.xcor() > width / 2 or ball.xcor() < -width / 2:
        x_velocity = -x_velocity

    window.update()

You now have a bouncing ball in Python, using the turtle module.

This simulation is not perfect. There are other refinements you could make, but for the purpose of this blog, this works perfectly fine.

Final Words

Using only relatively basic knowledge of the laws of motion and the effect of gravity on a falling ball, you’ve been able to create a reasonably realistic simulation of a bouncing ball in Python.

In the second blog post in the Bouncing Ball Series, I’ll extend this simulation using object-oriented programming in Python to create many balls all moving at different speeds and in different directions. The class Ball that I’ll discuss in that post can also form the building block of several ball-related games.


Get the latest blog updates

No spam promise. You’ll get an email when a new blog post is published


Leave a Reply