Part 3¶
Starting point¶
At this point your code should look like this:
TITLE = 'Flappy Bird'
WIDTH = 400
HEIGHT = 708
def update():
barry_the_bird.y += barry_the_bird.speed
top_pipe.x += scroll_speed
bottom_pipe.x += scroll_speed
if top_pipe.right < 0:
top_pipe.left = WIDTH
bottom_pipe.left = WIDTH
def draw():
screen.blit('background', (0, 0))
barry_the_bird.draw()
top_pipe.draw()
bottom_pipe.draw()
def on_mouse_down():
print ('The mouse was clicked')
barry_the_bird.y -= 50
barry_the_bird = Actor('bird1', (75, 350))
barry_the_bird.speed = 1
gap = 140
top_pipe = Actor('top', (300, 0))
bottom_pipe = Actor('bottom', (300, top_pipe.height + gap))
scroll_speed = -1
Flying back to the start¶
What happens when Barry falls off the bottom of the screen? Right now you probably lose him forever. Let’s try to do something better.
- Add this new function after the on_mouse_down function:
def reset():
print ("Back to the start...")
barry_the_bird.speed = 1
barry_the_bird.center = (75, 350)
top_pipe.center = (300, 0)
bottom_pipe.center = (300, top_pipe.height + gap)
Each line in this function is assigning a value. First it sets Barry’s speed back to what it started as, then puts his center at an x,y position. It also moves the pipes back to their starting points. If you try the game now you’ll see that nothing has changed. Remember that a function won’t do anything until you call it. Let’s call it from the update function if Barry goes off the screen.
- Add this to the end of the update function:
if barry_the_bird.y > HEIGHT:
reset()
- Make sure you indent it so that it’s part of the update function, but not part of the previous if statement. Indenting means adding the right number of spaces to the beginning of the line.
- Check that everthing resets if Barry falls off the bottom of the screen.
Ask a mentor for help if you have trouble getting this to work.
We also need to reset the game if Barry goes off the top of the screen.
- Change your code to make this happen.
Hint: you will need the or
keyword.
Time to Flap!¶
At the moment, Barry the bird seems to teleport upwards when you click the screen (play the game now if you don’t remember). We’d really like him to move a bit more smoothly. The reason he seems to move instantaneosly is this line:
barry_the_bird.y -= 50
This makes him move a whole 50 pixels all at once. Not very smooth! When a real bird flaps its wings it changes the bird’s speed, not its position. Change in position is just a side effect of having speed.
- Change your
on_mouse_down
function to this:
def on_mouse_down():
barry_the_bird.speed = -6.5
Did that work? Try it and you’ll see that when you flap now he’ll just go up and hit the top of the screen.
We need some gravity to pull him back down again after each flap!
- Create a variable called gravity at the end of your file:
gravity = 0.3
And we’ll use this to change the bird’s speed every frame.
- Add this to the beginning of the update function:
barry_the_bird.speed += gravity
Try changing the value of gravity to see what effect it has
Now this bird is more flappy! Controlling him now takes a bit more skill. You can try to fly through the gaps, but we still haven’t done anything to stop you flying straight through the pipes. We’ll fix that soon. But first…
Being a lazy coder¶
You might have noticed that there are some lines of code that we’ve had to type in twice in different places. For example, barry_the_bird.speed = 1
. We do it once in the game setup code, and then again in the reset()
function, which is called when Barry dies and the game starts again. Well maybe it would make sense to just use the reset()
function at the beginning of the game as well! Then we’d only need the code in one place.
- Add a call to
reset()
at the very end of the file. - Now we can delete the
barry_the_bird.speed = 1
call that happens in the game setup code.
Can you figure out a way to specify the position of everthing in just one part of the code?
Hint: You should be able to remove 3 position values. One of them looks like: (75, 350)
Check the everything still works the same as before.
Giving Barry a head start¶
Let’s give the player a bit more time to flap before they fall off the screen. We can move the start point to just 50 pixels away from the top of the screen. Find this line in the reset function:
barry_the_bird.center = (75, 350)
- Change the 350 to something much smaller. Maybe 50? Try it and find a value that seems right to you.
Isn’t it great this number is only in one place in the code? If we hadn’t done the last section (Being a lazy coder) we would have to change two different numbers! It would have been very easy to forget about one of them.
Collisions¶
In PyGameZero there’s nothing to stop you drawing multiple sprites (images) on top of each other. So if we want certain behaviour when things collide we need to take care of it ourselves. Add this code to the end of the update function:
if (barry_the_bird.colliderect(top_pipe)):
hit_pipe()
The colliderect
function checks if two objects are touching. Because this is inside the update function it will get checked every frame. This won’t work yet because we haven’t created the hit_pipe
function. Let’s create it after the reset
function…
def hit_pipe():
print ("Hit pipe!")
barry_the_bird.image = "birddead"
Try this out. Now Barry should become a ghost when you hit the top pipe, but it looks like there are still three problems:
- Barry stays as a ghost even when the game resets.
- Barry can still fly through the bottom pipe!
- You can still flap and fly along even as a ghost.
- Try to fix problems 1 & 2 now. We’ll look at 3 together.
Hint for number 1 : Barry started with the “bird1” image, but it changes to “birddead” when he hits a pipe. Find the right place to change it back.
Hint for number 2 : Remember the or
keyword.
Now might be a good time to try changing the size of gap
to tune the difficulty of the game. You might want to make it very big while testing, so you can focus on testing and not on flying!
Now we’d like to stop Barry from flapping while he’s a ghost. The code which makes him fly needs a way of knowing if he’s still alive. We could use the barry_the_bird.image
variable, because that changes when he dies. But it’s better to add a new variable to make our code cleaner and less likely to break if we make changes later.
- Add this line to the
reset
function (Being a lazy coder pays off again!):
barry_the_bird.alive = True
We’re creating the new variable alive
and setting it to true. Now we need to make sure barry only flaps when he’s alive.
- Add this line to the beginning of the on_mouse_down function:
if (barry_the_bird.alive):
Don’t forget to change the indentation (number of spaces at the beginning) of the line that changes the speed, so that it’s part of the if statement. We only want to change the speed (in other words flap) if the bird is alive!
The next thing to do is to change barry to not be alive when he hits a pipe.
- Add a line to change barry’s
alive
variable toFalse
when he hits a pipe.
Well done. That’s the end of part 3. In the next part we’ll look at a few finishing touches such as adding a flapping animation, randomizing the pipe positions, and keeping score.
Go to Part 4.
Extra Challenges¶
- Turn physics upside down! Make gravity pull Barry upwards, and make flapping push him downwards
- Add a cheat key that makes the player invincible
Hint: Try adding this function and see what happens when you press a key:
def on_key_down(key):
print(key)
- Add a secret tiny flap that the player can do using the right mouse button
Hint: you will need to add a parameter to your on_mouse_down
function, so it becomes on_mouse_down(button)
. Try use the print
function like you did in the last challenge to see what values button
has.