CONGRATULATIONS—YOU’VE REACHED your final adventure! You’ve come a very long way and learned a lot about Python. You’ve learned about Python programming concepts including variables, if
statements, functions, while
loops, for
loops, lists and comparators. You’ve also been introduced to different Python libraries including the turtle
module, Tkinter
and PyGame
.
In this final adventure, you will combine lots of the things you learned about Python in your previous adventures to create a fantastic two-player game. So, what does this program do? It’s a game in which two players compete to collect coins. The coins’ locations are randomly generated and change every time a coin is collected. The players’ scores are displayed next to the player sprites.
Players can move in eight directions (up, down, left, right and diagonally in four ways). If players collide, they bounce in opposite directions. There are walls around the edge of the game that stop the players walking off the edge of the window. There are four doors in the walls, through which players can move. Leaving through one door makes them reappear in the opposite door.
You control the players using a single keyboard. The w, a, s and d keys control player 1, and the up, down, left and right keys control player 2.
You can see the finished game in Figure 10-1.
This is the most complex of all the programs in this book, and it’s a long one—almost 300 lines long! Don’t be put off, though. It’s easier than you think because you’ve seen everything in the program before, in your earlier adventures. The program combines things that you’ve seen with Python and PyGame
, including music, sounds, images and the keyboard.
This adventure requires several files for sprites and sounds. You’ll find instructions on how to set up the files in the Appendix.
You can also design your own sprites and background for the game. Use the default images for the program as a template for designing your own. If you keep the same size of sprites and the same size of background, this program will work exactly the same. If you change the size of anything, however, you will need to modify other things in the program, such as the functions that check whether a player is walking into a wall or touching a coin.
Make sure the images and sounds are in the correct folder. You should have the following files:
background.png
coin.png
coin.wav
light.png
music.mp3
sprite1_standing.png
sprite1_walking1.png
sprite1_walking2.png
sprite2_standing.png
sprite2_walking1.png
sprite2_walking2.png
If you don’t have these files, follow the steps in the appendix to add them before continuing.
Now you can start making the game by following the steps in this section. As the game has two players, it makes sense to make the code reusable using functions. This will make the program more manageable and, as the same functions can be used for each player, it means you won’t have to duplicate the code for each player. The first part of the program defines the functions. Follow the instructions to start creating the game:
bigGame.py
in the Adventure 10
folder.PyGame
module and the random module:
import random
import pygame
pygame.init()
def moveAnimation(image1, image2, count):
if 10 < count % 20 <= 20:
return image2
else:
return image1
There are walls in the game which the player shouldn’t be able to walk through. To handle this, you need to include functions to stop the player moving through the walls. The walls are shown on the background, which you can see in Figure 10-3. This code stops the players from walking over the area of the background where the walls are located. Follow these steps:
def upClear(x, y):
canMove = True
if verticalDoorLeft <= x <= verticalDoorRight and
y - 1 < topWall:
canMove = True
elif y - 1 < topWall:
canMove = False
elif (x < leftWall or x > rightWall) and y - 1 <
middleDoorsTop:
canMove = False
if canMove:
return 1
else:
return 0
upClear()
function, the downClear()
function checks whether the player can move downwards or whether there is a wall in the way:
def downClear(x, y):
canMove = True
if verticalDoorLeft <= x <= verticalDoorRight and
bottomWall < y + 1:
canMove = True
elif bottomWall < y + 1:
canMove = False
elif (x < leftWall or x > rightWall) and y + 1 >
middleDoorsBottom:
canMove = False
if canMove:
return 1
else:
return 0
leftClear()
function checks whether the player can move left or whether there is a wall in the way:
def leftClear(x, y):
canMove = True
if middleDoorsTop <= y <= middleDoorsBottom and
x - 1 < leftWall:
canMove = True
elif x - 1 < leftWall:
canMove = False
elif (y > bottomWall or y < topWall) and x - 1 <
verticalDoorLeft:
canMove = False
if canMove:
return 1
else:
return 0
rightClear()
function checks whether the player can move to the right or whether there is a wall in the way:
def rightClear(x, y):
canMove = True
if middleDoorsTop <= y <= middleDoorsBottom and
x + 1 > rightWall:
canMove = True
elif x + 1 > rightWall:
canMove = False
elif (y > bottomWall or y < topWall) and x + 1 >
verticalDoorRight:
canMove = False
if canMove:
return 1
else:
return 0
The next functions in your program are used to check when the player walks through a door, whether the players have collided and whether the player is touching a coin.
def checkOffscreen(x, y):
if x < -14:
x = windowSize[0] - 14
elif x > windowSize[0] - 14:
x = -14
if y < -20:
y = windowSize[1] - 20
elif y > windowSize[1] - 20:
y = -20
return x, y
def playersTouching():
global pOneX, pOneY, pTwoX, pTwoY
if -32 < pOneX - pTwoX < 32 and -40 < pOneY - pTwoY < 40:
xDiff = pOneX - pTwoX
yDiff = pOneY - pTwoY
for dist in range(abs(xDiff) / 2):
pOneMove = leftClear(pOneX, pOneY) +
rightClear(pOneX, pOneY)
pTwoMove = leftClear(pTwoX, pTwoY) +
rightClear(pTwoX, pTwoY)
if xDiff > 0:
pOneX += pOneMove / 2 * xDiff / xDiff
pTwoX -= pTwoMove / 2 * xDiff / xDiff
else:
pOneX -= pOneMove / 2 * xDiff / xDiff
pTwoX += pTwoMove / 2 * xDiff / xDiff
for dist in range(abs(yDiff) / 2):
pOneMove = upClear(pOneX, pOneY) +
downClear(pOneX, pOneY)
pTwoMove = upClear(pTwoX, pTwoY) +
downClear(pTwoX, pTwoY)
if yDiff > 0:
pOneY += pOneMove / 2 * yDiff / yDiff
pTwoY -= pTwoMove / 2 * yDiff / yDiff
else:
pOneY -= pOneMove / 2 * yDiff / yDiff
pTwoY += pTwoMove / 2 * yDiff / yDiff
True
if they are and False
if they aren’t. This function does not add points to the players’ scores or reset the coin’s position; this is done later in the program. Add this function to your program now:
def touchingCoin(x, y):
return -32 < x - coinPos[0] < 20 and -40 <
y - coinPos[1] < 20
def randomPosition():
x = random.randrange(32, windowSize[0] - 52)
y = random.randrange(32, windowSize[1] - 52)
return x, y
Now that the program has all the functions needed in the game, it’s time to add variables and other Python code to join it all together.
The next part of the program sets up the size of the window, followed by variables for displaying text, player positions, images and sounds:
windowSize = [640, 384]
screen = pygame.display.set_mode(windowSize)
clock = pygame.time.Clock()
# Font for points
pointFont = pygame.font.SysFont("Monospace", 15)
# Variables for position etc.
pOneX = windowSize[0] / 4
pOneY = windowSize[1] / 2
pTwoX = (windowSize[0] / 4) * 3
pTwoY = windowSize[1] / 2
coinPos = randomPosition()
pOnePoints = 0
pTwoPoints = 0
pOneCount = 0
pTwoCount = 0
pOneMoving = False
pTwoMoving = False
# Variables for walls
leftWall = 28
topWall = 16
rightWall = windowSize[0] - 60
bottomWall = 312
middleDoorsTop = 144
middleDoorsBottom = 182
verticalDoorLeft = 284
verticalDoorRight = verticalDoorLeft + 40
# Load images
background = pygame.image.load("background.png")
background = pygame.transform.scale(background, windowSize)
light = pygame.image.load("light.png")
light = pygame.transform.scale(light, windowSize)
pOneMove1 = pygame.image.load("sprite1_walking1.png")
pOneMove1 = pygame.transform.scale2x(pOneMove1)
pOneMove2 = pygame.image.load("sprite1_walking2.png")
pOneMove2 = pygame.transform.scale2x(pOneMove2)
pOneStanding = pygame.image.load("sprite1_standing.png")
pOneStanding = pygame.transform.scale2x(pOneStanding)
pTwoMove1 = pygame.image.load("sprite2_walking1.png")
pTwoMove1 = pygame.transform.scale2x(pTwoMove1)
pTwoMove2 = pygame.image.load("sprite2_walking2.png")
pTwoMove2 = pygame.transform.scale2x(pTwoMove2)
pTwoStanding = pygame.image.load("sprite2_standing.png")
pTwoStanding = pygame.transform.scale2x(pTwoStanding)
coin = pygame.image.load("coin.png")
coin = pygame.transform.scale2x(coin)
# Load music and sound
coinSound = pygame.mixer.Sound("coin.wav")
pygame.mixer.music.load("music.mp3")
pygame.mixer.music.play(-1)
The remaining part of the program runs the game loop. The main purpose of this loop is to respond to the keys pressed by both players, animate the player sprites, check whether the players are touching, check whether a player has collected coins, display the points and blit the images to the window. To do all this, the game loop uses all the functions created earlier in the program.
Once you have added the whole game loop to the program you can run the game!
The first part of the game loop enables the program to check whether any keys have been pressed. It also calls the functions that check whether the player is walking into a wall and determine what sprite is to be used in the animation.
Let’s get started.
# Game loop
done = False
while not done:
# Get movement
# Player 1 movement
pOneMoving = False
keys = pygame.key.get_pressed()
if keys[pygame.K_s]:
pOneY += downClear(pOneX, pOneY)
pOneMoving = True
if keys[pygame.K_w]:
pOneY -= upClear(pOneX, pOneY)
pOneMoving = True
if keys[pygame.K_a]:
pOneX -= leftClear(pOneX, pOneY)
pOneMoving = True
if keys[pygame.K_d]:
pOneX += rightClear(pOneX, pOneY)
pOneMoving = True
pOneX, pOneY = checkOffscreen(pOneX, pOneY)
moveAnimation()
function to determine which sprite should be displayed for the animation. If the player isn't moving, it displays the standing sprite. Add the code now:
# Player 1 animation
if pOneMoving:
pOneCount += 1
pOneImage = moveAnimation(pOneMove1, pOneMove2,
pOneCount)
else:
pOneImage = pOneStanding
# Player 2 movement
pTwoMoving = False
if keys[pygame.K_DOWN]:
pTwoY += downClear(pTwoX, pTwoY)
pTwoMoving = True
if keys[pygame.K_UP]:
pTwoY -= upClear(pTwoX, pTwoY)
pTwoMoving = True
if keys[pygame.K_LEFT]:
pTwoX -= leftClear(pTwoX, pTwoY)
pTwoMoving = True
if keys[pygame.K_RIGHT]:
pTwoX += rightClear(pTwoX, pTwoY)
pTwoMoving = True
pTwoX, pTwoY = checkOffscreen(pTwoX, pTwoY)
# Player 2 animation
if pTwoMoving:
pTwoCount += 1
pTwoImage = moveAnimation(pTwoMove1, pTwoMove2,
pTwoCount)
else:
pTwoImage = pTwoStanding
You can see the coin in the game in Figure 10-4. As the players move around the game they collect the coins, which adds to their score. In the next section, you will add code to do this.
After the player moves, your program needs to check two things: whether the players are touching each other and whether either of them have collected a coin. The playersTouching()
function is used to check whether the players are touching. The touchingCoin()
function is used for both players, alongside if
statements for each player and a final if
statement that sets the coin’s position to a new random location.
# Check touching
playersTouching()
# Check touching coin
if touchingCoin(pOneX, pOneY):
pOnePoints += 1
coinSound.play()
if touchingCoin(pTwoX, pTwoY):
pTwoPoints += 1
coinSound.play()
# Move coin if touching
if touchingCoin(pOneX, pOneY) or touchingCoin(pTwoX,
pTwoY):
coinPos = randomPosition()
Now that all of the game logic has run in the program, all that’s left is to display the points, sprites and background on the window.
PyGame
surface:
# Render points for display
pOnePointLabel = pointFont.render(str(pOnePoints), 1, (255, 255, 255))
pTwoPointLabel = pointFont.render(str(pTwoPoints), 1, (255, 255, 255))
PyGame
surface:
# Update display
screen.blit(background, (0, 0))
screen.blit(coin, coinPos)
screen.blit(pOneImage, [pOneX, pOneY])
screen.blit(pTwoImage, [pTwoX, pTwoY])
screen.blit(pOnePointLabel, [pOneX - 9, pOneY - 9])
screen.blit(pTwoPointLabel, [pTwoX - 9, pTwoY - 9])
screen.blit(light, (0, 0))
pygame.display.flip()
# exit
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
clock.tick(60)
pygame.quit()
Fantastic! You’ve finished that long program. It should look something like Figure 10-5.
All that remains is for you to play the game. Follow these steps to do so:
Have fun! Test to see if everything works. Can you walk through the wall? Do the doors work? Do you gain points when you walk over the coins?
No matter how carefully you copied the code, sometimes things just don’t work right. This is where your debugging skills come in handy.
There are many different things that can go wrong and a few different strategies you can take to debug things. The first question to ask is whether the bug is stopping the game from running, or if the game is running and the bug is making the game run weirdly?
If the game does not start, you probably get an error message. This is very useful as it will help you identify where the error is coming from. Find the bit of the error message that says something like ". . . error on line 35"
. This line is the best place to start looking for the error. Read what type of error you have as well. Did you forget to create a variable? Have you misspelled the name of a function? Did you forget to add a closing bracket or indent some code? Take your time with this and be patient. Even the best of us make mistakes and have to debug our code.
If your game runs and you don’t get any error messages, you might be seeing some weird behaviour in the game. For example, one player might be able to walk through walls or you notice that the points aren’t added to the total score when coins are collected. This type of bug can be harder to trace. The first question you need to ask yourself is when does the error happen? Does the error happen when the player moves up, when a coin is collected, when the players collide, and so on? If you can identify when the error happens, then the piece of code you need to look at is either the function that handles this part of the game or the bit of code in the game loop that handles this part of the game. It also might be the variables that the other parts of the program use. Find these parts and check that your code matches the code in this adventure. Take your time and be patient.
Achievement Unlocked: Amazing adventurer and creator of a cool computer game.
Congratulations! You’ve reached the end of your adventures in this book. During your journey, you’ve had a lot of adventures and learned a lot about Python along the way.
You’ve created programs that use a wide range of fundamental programming concepts with Python. You’ve learned about variables, functions, if
statements, while
loops, for
loops and lists—among loads of other things. Along the way, you’ve also become familiar with the Python’s turtle
module, Tkinter
and PyGame
.
Well done. You should be very proud of yourself for what you’ve achieved during your adventures in Python.
I hope you’ve enjoyed your adventures and have learned a lot along the way. Python programming is a fun and rewarding pursuit, and I wish you all the best in your future adventures! If you’re ready for your next big adventure, don’t forget about these great resources:
www.fullstackpython.com
) is an excellent place for beginners to hone their skills and knowledge. This website has an excellent list of other tutorials you can try with Python, along with other useful programming information.www.pythonweekly.com
) is a weekly newsletter that showcases Python tutorials, projects and news. Although some of it may be a bit complex for beginners, you can find lots of interesting tutorials, such as creating your own games and animations.www.effbot.org/tkinterbook/
) has excellent documentation for the Tkinter library, which is used in some of the adventures in this book. You might find this website really useful for creating your own programs.3.133.130.199