ch10-pag223

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.

image

FIGURE 10-1 In the finished game, two players compete to collect coins.

Writing the Program for the Game

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.

Setting Up the Files

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.

Making the Game

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:

  1. Open IDLE and create a new file with File⇒New Window.
  2. Save the program as bigGame.py in the Adventure 10 folder.
  3. In the file editor, add this code to import the PyGame module and the random module:

    import random
    import pygame
    pygame.init()

  4. The next part of the program adds a function that is used to determine which image will be used in the sprite’s walking animation. Add this to your program now:

    def moveAnimation(image1, image2, count):
        if 10 < count % 20 <= 20:
            return image2
        else:
            return image1

image

FIGURE 10-2 All the player sprites used in the game

Walls

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:

image

FIGURE 10-3 The game’s background

  1. Select the line below the last function in your program.
  2. This first function checks whether the player can move upwards or there is a wall in the way. The function returns 1 if the player can move and 0 if they can’t. These numbers are used later in the program and determine the distance the player moves. The single function will stop the player moving through the top wall as well as through the wall above two of the four doors. Add it to your program now:

    def upClear(x, y):
        canMove = True

        if verticalDoorLeft <= x <= verticalDoorRight and ImageD
          y - 1 < topWall:
            canMove = True
        elif y - 1 < topWall:
            canMove = False
        elif (x < leftWall or x > rightWall) and y - 1 < ImageD
          middleDoorsTop:
            canMove = False

        if canMove:
            return 1
        else:
            return 0

  3. Like the 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 ImageD
          bottomWall < y + 1:
            canMove = True
        elif bottomWall < y + 1:
            canMove = False
        elif (x < leftWall or x > rightWall) and y + 1 > ImageD
          middleDoorsBottom:
            canMove = False

        if canMove:
            return 1
        else:
            return 0

  4. The 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 ImageD
          x - 1 < leftWall:
            canMove = True
        elif x - 1 < leftWall:
            canMove = False
        elif (y > bottomWall or y < topWall) and x - 1 < ImageD
          verticalDoorLeft:
            canMove = False

        if canMove:
            return 1
        else:
            return 0

  5. Finally, the 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 ImageD
          x + 1 > rightWall:
            canMove = True

        elif x + 1 > rightWall:
            canMove = False
        elif (y > bottomWall or y < topWall) and x + 1 > ImageD
          verticalDoorRight:
            canMove = False

        if canMove:
            return 1
        else:
            return 0

Doors, Collisions and Coins

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.

  1. Add a new line below the code you’ve already added to the program.
  2. The first function will check if the player has moved through one of the doors. If the player has moved through a door, it will return new x and y coordinates for the player, which will move the player to the opposite door in the game.

    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

  3. The next part of the program checks whether the players are touching. If they are, they should push each other away in opposite directions. So that the players aren’t pushed through walls, the distance the players move is set using two loops, one for the x coordinates and the other for the y coordinates. Each loop checks whether the player can continue to move in that direction, adding 1 to the distance they travel if they can and 0 if they can’t. Add this code to your program now:

    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) + ImageD
                  rightClear(pOneX, pOneY)
                pTwoMove = leftClear(pTwoX, pTwoY) + ImageD
                  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) + ImageD
                   downClear(pOneX, pOneY)
                pTwoMove = upClear(pTwoX, pTwoY) + ImageD
                   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

  4. The next function checks whether a player is touching the coin by checking if their position is near the coin. The function will return 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 < ImageD
          y - coinPos[1] < 20

  5. The last function generates a random position for the coin. This is used to set its original position and a new position when the coin is collected. In the file editor, add this code to your program:

    def randomPosition():
        x = random.randrange(32, windowSize[0] - 52)
        y = random.randrange(32, windowSize[1] - 52)
        return x, y

Setting Up the Window and Variables

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:

  1. Select the line below the code you added in the section above.
  2. Add this code to set up the window size and the clock for the game:

    windowSize = [640, 384]
    screen = pygame.display.set_mode(windowSize)
    clock = pygame.time.Clock()

  3. The next part of the program sets the font in which the points will be displayed. Each character in a monospace font is the same size, which makes it much easier to know how much space the points will take up when they are displayed above the players’ heads. Add this code to your program now:

    # Font for points
    pointFont = pygame.font.SysFont("Monospace", 15)

  4. The next set of variables sets the players’ starting positions, the coin’s starting position, the points collected by each player and variables that are used when animating the players. Add this code now:

    # 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

  5. The next part of the program sets the values for the wall and door locations. These variables are used in the functions that check whether the players have walked into walls or are going through doors. Add these variables to your program now:

    # Variables for walls
    leftWall = 28
    topWall = 16
    rightWall = windowSize[0] - 60
    bottomWall = 312

    middleDoorsTop = 144
    middleDoorsBottom = 182
    verticalDoorLeft = 284
    verticalDoorRight = verticalDoorLeft + 40

  6. The next set of variables store the loaded images for the background, all the player animation sprites and the coin. All the images are resized to make them look retro and pixelated. The image stored in the light variable is used for lights in the game. Later in the program, it is placed over all the other images so that it looks like a light is shining on them. Add the code to load the images now:

    # 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)

  7. The final set of variables loads the coin collect sound and game music into the program. Add it now:

    # Load music and sound
    coinSound = pygame.mixer.Sound("coin.wav")
    pygame.mixer.music.load("music.mp3")
    pygame.mixer.music.play(-1)

Adding the Game Loop

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!

Character Controls and Animations

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.

  1. Select the line below the code you added in the last section.
  2. The game loop starts in the usual way. Add this code to your program now:

    # Game loop
    done = False
    while not done:

  3. At the start of the game loop, the program checks whether any keys have been pressed. If the w, a, s or d keys have been pressed, the program will move player 1. Add this code to your program now:

        # 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)

  4. To decide which image is displayed for player 1, the program checks whether the player is moving. If it is moving, the program uses the 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, ImageD
              pOneCount)
        else:
            pOneImage = pOneStanding

  5. The code for player 2 is very similar to the code for player 1 but just uses different keys for movement and different images for the animation. Add this code now:

        # 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)

  6. Finally, add the code that animates player 2:

        # Player 2 animation
        if pTwoMoving:
            pTwoCount += 1
            pTwoImage = moveAnimation(pTwoMove1, pTwoMove2, ImageD
                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.

image

FIGURE 10-4 The players collect coins and gain a point for every coin they collect.

Player Collisions and Collecting Coins

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.

  1. On the line below the code you’ve already added to the program, add this code to check whether the players are touching:

        # Check touching
        playersTouching()

  2. The next part of the program checks whether player 1 is touching the coin and adds a point to their total if they are:

        # Check touching coin
        if touchingCoin(pOneX, pOneY):
            pOnePoints += 1
            coinSound.play()

  3. After checking whether player 1 is touching the coin, the next few lines of code check whether the other player is touching the coin:

        if touchingCoin(pTwoX, pTwoY):
    pTwoPoints += 1
    coinSound.play()

  4. If either player is touching the coin, it needs to move to a new random location. Add this code to do that now:

        # Move coin if touching
        if touchingCoin(pOneX, pOneY) or touchingCoin(pTwoX, ImageD
          pTwoY):
    coinPos = randomPosition()

Displaying Points and Updating the Window

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.

  1. Click in the window below the rest of your program and create a new line.
  2. On the new line, add these lines of code to render the players’ points as strings that can be displayed on the PyGame surface:

    # Render points for display
        pOnePointLabel = pointFont.render(str(pOnePoints), 1, (255, 255, 255))
        pTwoPointLabel = pointFont.render(str(pTwoPoints), 1, (255, 255, 255))

  3. The next part of the code blits the background, coin, sprites, points and lighting onto the 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()

  4. The final bit of code allows the window to be closed:

        # exit
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
        clock.tick(60)
    pygame.quit()

Playing the Game

Fantastic! You’ve finished that long program. It should look something like Figure 10-5.

image

FIGURE 10-5 The finished game

All that remains is for you to play the game. Follow these steps to do so:

  1. Click on Run⇒Run Module.
  2. When the program opens, you can play the game.
  3. To move the first player, use the w, a, s and d keys.
  4. To move the second player, use the up, down, left and right keys.
  5. You’ll see the points for each player displayed above the heads of the characters.

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?

Debugging the Game

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.

image

Achievement Unlocked: Amazing adventurer and creator of a cool computer game.

Summary

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:

  • Full Stack Python (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.
  • Python Weekly (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.
  • Effbot (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.
  • The book Adventures in Raspberry Pi, by Carrie Anne Philbin (ISBN: 978-1-118-75125-1), might be your next step if you want to learn all about the Raspberry Pi.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.130.199