Project Case Study: Bouncing Balls: Year Level Band: Description
Project Case Study: Bouncing Balls: Year Level Band: Description
Description:
This project creates a program where five balls bounce at different rates, to build skill in the use of
Object-Oriented programming design and implementation, and data representation. Students will learn
about Object-Oriented programming using existing Classes and Objects, as well in designing and creating
multiple new Classes, making this a good intermediate project.
Resources:
Defining the To create the Bouncing Ball program that draws five differently coloured
Problem balls on the screen, which will bounce as if they are under the influence of
gravitational force. To produce an interesting pattern, the rate of fall is set
differently across the balls. The balls follow the equations of motion and
accelerate the longer they fall and decelerate as they climb back up. The user
may use the arrow keys to increase or decrease the speed at which the
animation runs, to allow them to inspect the movement of the balls.
There is additional context for this as we wish the balls to fall as if they are
under the influence of a gravitational force. Things speed up as they fall under
gravity, that is they accelerate as they fall. On Earth, after 1 second of fall, an
object will be falling at 4.9m/s. After 2 seconds, it would be falling at 19.6m/s.
From Physics, the equations of motion tell us that the distance travelled by
any object under acceleration, which starts at rest, is given by:
On the way down, our ball will be accelerating towards the bottom and it will
travel further and further every second. Once it bounces, the same
gravitational force will slow it down in the same manner.
We have to think about the Classes that we want to build, with the associated
variables and functions that will make sense for the development.
Let's start by looking at the Ball class. The first thing we can see is that it has
to have its own position stored in a variable because we’re going to create
more than one Ball object - every object needs its own copy of the x and y
position of the ball. We’ve talked about the colour of the ball as well so we
probably need that.
Here are the requirements (functional requirements) for how the ball is going
to used.
Some thought on these behaviours will give us the likely functions: __init__ to
set things up, setcolour to change the colour, draw so that we can see it, and
fall to make it fall.
But we know two things: first that the speed at which the ball moves depends
on how long it has been accelerating or decelerating, second that we have
more than one ball and we wish to have some variation in the falling rate.
We probably need a variable in the Class to store how long the ball has been
falling and another variable to keep track of the “local” gravity that we wish the
ball to experience.
We’ll see later that we need one more variable, because of the way that we
choose to implement it, but we’ll come back to this. We certainly have enough
to produce a few coloured balls and start them dropping under whichever
gravity we give them.
We did say we wanted to control the speed of the animation and, whenever
we offer a user control, we often want to offer them a way of seeing what’s
going on. Therefore, we need some way of displaying what the current
animation delay is. We’ll do this in a similar way to how we built the
scoreboard in the worked example. In this case, we’ll create a Class that will
provide a way of storing the current animation rate and displaying it. That
would look like this:
Let's look at how a program to run the whole game might look:
1. Draw the playing area with bounding rectangle, set the delay to zero
and display it.
2. Create some balls.
3. Draw the balls in their starting positions.
4. Start the balls falling.
5. If a user hits up arrow, increase the delay, but if a user hits down
arrow, decrease the delay.
The balls aren’t, of course, actually bouncing. We are using their position and
the relative position of the walls to decide when to reverse direction. In a
game, we refer to this detection of proximity as collision detection. Although
the objects didn’t really collide, in a real world sense, they are ‘touching’ and
we can perform actions based on this.
We will return to a broader discussion of how we could extend this towards the
end of this exemplar. For now, we will move onto working on the data of the
program.
Understanding our Most of the data representation in the program is straightforward. The
Data animation delay is a number. The position of each ball is given by an (x,y)
coordinate pair and its colour is also straightforward. Each ball will keep track
of how it has been either accelerating or decelerating.
Our Display class needs to be told when the delay has changed and this
function will be called whenever the user hits a key.
The whole program is a little more complex because we have multiple balls
that we wish to animate. We could create a number of Ball objects directly,
labelled ball1, ball2, ball3, etc, but this would require us to write a lot of
duplicate code to animate the balls.
Given that we wish to call the draw and fall functions in each Ball, we are
going to create new Ball objects and put them into a Python list (similar to an
array in other languages). That way, we can write small helper functions that
will take a list of Ball objects and call the same function in all of them.
Prototyping and Sketch prototypes are very useful to get a feel for how the game will work.
User Interface These can be actual sketches or small examples using a whiteboard or post-it
Design notes.
This early sketch shows the rough layout on the screen, as well as the idea
that we match some of the accelerations to produce a pattern as the balls
bounce. You can see, from the arrows, that the balls could be travelling in
different directions at different times.
A prototype of the code of this game could be a single ball bouncing, or even
a single ball falling as a very early example, before collision detection is
active.
Implementation The full Python3 code for this is shown below.
In this implementation, we have kept track of the direction that each ball is
moving, up or down, in order to execute the correct change to y. This requires
us to add another variable to the Ball class. You could also choose to make
the ‘ftime’ variable positive or negative to simplify the logic but the ‘direction’
approach makes it easier for students to work on a falling ball first and then
extend their logic to the other direction.
The following code shows the entire implementation. This is one way to solve
the problem but there are many others.
class Ball:
x=0 # X coordinate
y=0 # Y coordinate
colr=(255,0,0) # Colour
direction=1 # 1: Ball going down,
#-1: Ball going up
ftime=0 # Time in this direction
droprate=0 # "local gravity"
pygame.draw.circle(main,self.colr,(self.x,self.y),10,0)
pygame.draw.circle(main,(200,200,200),(self.x,self.y),10,0)
if self.direction==1:
self.y=int(self.y+(self.droprate*(self.ftime*self.ftime)))
# increase the time spent falling by 1
self.ftime+=1
else:
# We bounced! Change direction!
self.direction=-1
self.ftime-=1
else:
# We're bouncing back up
self.y=int(self.y-(self.droprate*(self.ftime*self.ftime)))
self.ftime-=1
else:
# Start falling again
#(this is a bounce off the top)
self.direction=-1
if (self.ftime==0):
self.ftime=1
self.direction=1
def fallBalls(alist):
for ball in alist:
ball.fall()
class Display:
slowspeed = 0 #Animation delay
def __init__(self):
self.slowspeed=0 # Initially set to zero.
def setslow(self,setspeed):
self.slowspeed=setspeed
def Main():
balllist.append(Ball(100,100,1))
balllist.append(Ball(200,100,2))
balllist.append(Ball(300,100,4))
balllist.append(Ball(400,100,2))
balllist.append(Ball(500,100,1))
balllist[1].setcolour((0,128,128))
balllist[2].setcolour((255,128,128))
balllist[3].setcolour((255,255,128))
balllist[4].setcolour((0,255,255))
drawBalls(balllist)
# Redraw them
drawBalls(balllist)
if __name__ == '__main__':
The first thing we want to do is to make sure that we can draw at least one ball
and see it fall on the screen. So our testing for correct function will be:
1. Can I display the ball?
2. Does it move towards the bottom of the screen?
3. Does it appear to speed up?
4. What happens when it hits the bottom?
If we identify an error in the Ball, because it's a Class, we will go into the Ball
class and fix it there. The next step for the Ball will be checking what happens
when the Ball collides with the bottom of the screen. Does it change direction?
Does it slow down as it climbs? Does it reach the same height as before? Can
we produce multiple balls at different fall rates with different colours? We'd
then continue to test the program until we've tested all of the individual
elements and their interactions together.
One useful test case is to see if everything is being drawn where you expect.
Are the balls are starting at the same point and then falling the correct way?
Testing the non-functional requirements often falls into the realm of playability.
We noted before that we can ask students whether the controls are obvious
and responsive, and whether the animation delay changes slow the game
down.
Project Extensions There are many ways this could be extended. Some that we have thought of
include:
● Could you make the balls move in the x direction as well? How do
they bounce and could you make them collide with the sides?
● Can you make this more realistic by modelling a ball that isn’t perfectly
elastic - one that slows down?
● Can you introduce the balls at lots of different angles and have them
collide with each other?
Project Reflection
In this project, students will undertake an extensive design and implementation process. The project is
well suited to be taught over a number of sessions, and using group work. While we have not included
explicit assessment information here, we have provided a discussion of how these sessions might be
structured, and how students might be able to demonstrate their learning.
For a more extensive discussion of assessment possibilities within Digital Technologies at this level,
please join us in our online community and course: www.csermoocs.adelaide.edu.au
Encourage students to help each other - and look for help on the internet.
Ask a friend. Ask Google. Then ask the teacher.
While students are working in groups, ask questions to give them the
opportunity to demonstrate their thinking and understanding:
Learning demo
What challenges have you faced in developing this design?
How did they decide how to store the data?
Learning reflection Remind students that this is a very simple program but that the program we
have been developing has a development process that you would find in
real-world game development. Simulation of the real world is one of the
most useful aspects of computing and, although it is very simple, this is a
simulation of how things bounce in the real world. The steps that they have
taken can be applied to many other larger projects
● Can you think of any simulations that they want to build that they
might use to build games, like Pool, Billiards or Snooker, for
example?
● What would the addition of sound do to this project?
● Can we use this to predict things in the real world?
Teacher/Student Instructions:
Download the latest version of Python 3 from http://python.org .
When this has been installed, follow the instructions at http://pygame.org/wiki/GettingStarted to install the
Pygame library.
IMPORTANT: You must use python3 to run the pygame library on many platforms.
Further Resources:
1. Information about Python, including tutorials: http://python.org
2. Information on the pygame library: http://pygame.org
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International
License. Computer Science Education Research (CSER) Group, The University of Adelaide.