Python & Perl
Department of Computer Science
Utah State University
Build a simple game
Games are one of the most applicative areas of
To write even the simplest games, you have to get into
graphics, math, physics and even AI.
It’s a great and fun way to practice programming.
A complete simulation of creeps, round creatures that
move around the screen, bouncing off walls and
changing their direction from time to time.
We want to have creeps moving around the screen
The amount of creeps and their appearance should be
The creeps will bounce off walls correctly
To make things more interesting, the creeps will exhibit
So what is a creep ?
A creep is a small image that will be moved around the
screen and rotated using Pygame’s capabilities
In gaming terminology they are known as sprites
We limit the rotations to quantas of 45 degrees
(meaning that creeps will move up, down, left, right or in
How do creeps "move" ?
Movement is an illusion. Nothing really moves on a
Rather, the program displays a sequence of images with
small displacements fast enough for the human eye to
The rule of thumb is that anything with 30 updates per
second or faster is good enough and looks smooth to
the average person.
How often does this loop run ?
This is decided by the call to clock.tick.
clock is a pygame.time.Clock object.
The call to tick basically says this: sleep until the next
1/50 second boundary, at most. This limits the game
speed to 50 FPS, which is a good thing, because we
want the game to be smooth on one hand, and not eat
up most of the CPU on the other hand.
The Creep is provided with a random image from the list
of images (choice is a function from Python’s standard
It is set in a random position on the screen (randint is
also from random)
A random direction (more about the direction later)
The speed is set to 0.1 px/ms (0.1 pixels per
millisecond), or 100 pixels per second
Vectors and directions
Vectors are the chief mathematical tool for making
computations related to movement on the screen
We’ll use vectors for two things:
Vectors and directions
A point on the XY plane can be represented by a 2D
The difference between two vectors is the velocity
In other words, adding the velocity vector to the original
position vector yields the new position.
In almost all graphical drawing interfaces, the top-left
corner is (0, 0), X increases to the right, and Y increases
to downwards. In other words, the screen drawing XY
Surprisingly, Pygame doesn’t have a "standard" vector
implementation shipping with it.
So game writers have to either roll their own or find
vector modules online.
We will use the vec2d.py file, a 2D vector
implementation the Pygame Wiki.
Updating the creep
The most interesting function of this demo is the update
method of Creep
def update(self, time_passed)
This method is called periodically by the main loop and
is passed the amount of time passed (in milliseconds)
since the previous call.
Rotating the creeps
transform.rotate rotates a given surface
counterclockwise by the provided angle.
self.image = pygame.transform.rotate
We give it a negation of the angle because of the
inverted "screen XY plane"
Rotating the creeps
Suppose our rotation direction is 45 degrees (that is,
south-east in our screen coordinates)
If we give 45 degrees to rotate, it will make the creep
point north-east (as its rotation is counterclockwise). So
to perform the correct rotation, we have to negate the
Next in update method we have
displacement = vec2d(self.direction.x * self.speed *
time_passed,self.direction.y * self.speed * time_passed)
self.direction is a normalized vector that tells us where
the creep points to
The displacement is computed from the basic rule of
motion that distance equals speed multiplied by time
Blitting is the game programmers’ jargon for transferring
an image (or a pattern) onto a drawable surface. In
Pygame this is implemented with the blit function
Blitting, like many other things in Pygame, uses the
versatile pygame.Rect class
The call to blit accepts an image (a surface, actually)
and a rectangle that specifies where this image will be
blitted to the surface on which blit is invoked
We provide the drawing position as the creep’s current
position (self.pos) but with a small adjustment
When images are rotated in Pygame, their size
Since the image is square, Pygame has to include all of
its information in the rotated image, so the rotated image
has to grow in size. This only happens for rotations that
are not multiples of 90 degrees
Whenever a creep turns, its image size changes.
Without a special adjustment, the creep will shift with
each turn and the animation won’t be smooth and pretty.
We center the creep when we draw it
The draw position is computed to be the center of the
creep’s image. Even when the image rotates and grows,
its center stays in the same place, so there will be no
noticeable shift in the creep this way.
Bouncing off walls
First, the screen boundary itself is computed, by taking
the rectangle representing the screen and adjusting it to
the image size
Then, for each of the 4 walls we compute whether the
creep collides with it, and if it does, the creep’s direction
is inverted in the axis perpendicular to the wall
if self.pos.x < bounds_rect.left:
self.pos.x = bounds_rect.left
self.direction.x *= -1
This is for the bounce off the left wall. The creeps always arrives to
it from the right, so when we negate the X component of its
direction vector while keeping the Y component intact, it will start
moving to the right but with the same vertical direction.