Python PyGame 3.1: Walkthrough the WWII Bombing Pilot Game

PyGame in Python Part 3.1 Walkthrough the WWII Bombing Pilot Game

So, we’ve introduced you to the basics of Python and PyGame over the last several blogs. Now it’s time to get your hands dirty and do something FUN! The next several blogs will be devoted to breaking down the game from Chapter 7 of “Game Programming: The L Line, The Express Line to Learning”.

What you will do: You will put everything together: images (sprites), sounds, user input, classes and objects, moving objects, collisions, etc. My goal will be to break it out in easy chunks.

The story: The story in the book has *obviously* been modified to be politically correct and avoid the subject it rips off: bombing islands in the South Pacific in WWII. I have no editor (clearly), so, I’ve restored the original intent to bombing anti-aircraft facilities scattered over islands. When you fly over an island, you bomb the target successfully. The clouds represent the frak from anti-aircraft cannons. If you touch them, you’ve just had shrapnel rip through parts of your plane. When you’ve been frakked 5 times, your engines fail and you take a short trip into the sea. If you’ve played any games like Modern Warfare… this should be like a trip to the ice cream parlor.

Obviously a game of this size takes a more serious approach to the structure. Additionally there are parts I really don’t care to cover in this blog (designing graphics) so I’m just going to have you take the graphics off the companion site. You could take the whole program, but, there’s no sense of accomplishment there.

So, let’s start by making a new directory under Python27/games (or whatever Python you are running) called 1945. Then go to this link: http://bcs.wiley.com/he-bcs/Books?action=resource&bcsId=3648&itemId=0470068221&resourceId=10183 and drag all the images and sounds over into your folder so we don’t have to worry about them later. Okay, that saves us a lot of trouble and explanations a book cannot avoid.

Ground Rules
1. The bomber plane only moves LEFT and RIGHT, and is controlled through the MOUSE.
2. The background scrolls down forever (seemingly) simulating the plane flying forward.
3. Islands move down screen.
4. When the plane hits an island; we have successfully bombed the enemy and a sound will play. You get a combat bonus of $1,000.
5. Anti-Aircraft fire moves around randomly. If the plane touches it, that’s holes in the fuselage and a sound will play. You’re now 1 step closer to those great white sharks.

First, we’ll make all the sprites…
Create a file called bomber_plane.py

Create a file called bomber_plane.py
""" bomber_plane
    step 1 of 1945 knockoff
    build plane sprite, 
    control it with mouse
"""
    
import pygame
pygame.init()

class Plane(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("plane.gif")
        self.rect = self.image.get_rect()
        
    def update(self):
        mousex, mousey = pygame.mouse.get_pos()
        self.rect.center = (mousex, 430)
		
def main():
    screen = pygame.display.set_mode((640, 480))
    pygame.display.set_caption("Bomber Pilot! bomber_plane.py - creating the Plane sprite")

    background = pygame.Surface(screen.get_size())
    background.fill((0, 0, 255))
    screen.blit(background, (0, 0))
    plane = Plane()
    
    allSprites = pygame.sprite.Group(plane)
    clock = pygame.time.Clock()
    keepGoing = True
    while keepGoing:
        clock.tick(30)
        pygame.mouse.set_visible(False)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
                
        allSprites.clear(screen, background)
        allSprites.update()
        allSprites.draw(screen)
        
        pygame.display.flip()
    
    #return mouse cursor
    pygame.mouse.set_visible(True) 
if __name__ == "__main__":
    main()

Let’s review some things here. At the tope we’ve imported and initialized the PyGame libraries. Then we setup the Plane class with a constructor/initialized and an update function. This is where we capture and respond to the user’s mouse. You can see we have fixed the Y-coordinate to the bottom of the screen but the X-coordinate goes where the user moves it.

In the main we build&blit the background, create an instance of the Plane class, setup the main loop and use the sprite group to manage screen updates. I haven’t gone over the sprites and sprite groups yet, so, let me summarize he explanation from PyGame’s tutorial that’s very well written:
The Sprite class is a base class for game objects. It only has methods to help it work with Group classes. The sprite keeps track of which groups it belongs to.
The Group class is a container. You can pass list of sprites to the constructor (__init__ method) to create a Group instance that contains some initial sprites. The sprites() method returns an object that can be looped on to access every sprite the group contains. The Group also has an update() method, which will call an update() method on every sprite in the group.
http://www.pygame.org/docs/tut/SpriteIntro.html


Next up is the Island Sprite. Hopefully you grabbed the graphics for this as I’m not going to describe the big fun of playing with pixel graphics. If you’re a programmer, I’m sure you don’t enjoy that part. Remember to give your nearest graphic designer a hug for taking on all the pain for you ;-)

Here’s a list of the behaviours we want to accomplish with this sprite:
1. Y-coordinate updates at a constant rate (it moves down)
2. X-coordinate is fixed
3. When it hits the bottom, it is re-drawn at the top
4. When it hits a plane, it is re-drawn at the top

Here’s the code:

class Island(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("island.gif")
        self.rect = self.image.get_rect()
        self.reset()
        
        self.dy = 5
    
    def update(self):
        self.rect.centery += self.dy
        if self.rect.top > screen.get_height():
            self.reset()
            
    def reset(self):
        self.rect.top = 0
        self.rect.centerx = random.randrange(0, screen.get_width())

Pretty basic. Notice in the update(self) function that it checks for the bottom screen “collision”. Notice in the reset(self) function how it randomly decides where to draw it at the top. It would be some kind of geographical miracle if the islands in the archipelago all lined up perfectly. Now we’ll modify the main():

    
def main():
    screen = pygame.display.set_mode((640, 480))
    pygame.display.set_caption("Bomber Pilot! bomber_plane.py - creating the Plane sprite")

    background = pygame.Surface(screen.get_size())
    background.fill((0, 0, 255))
    screen.blit(background, (0, 0))
    plane = Plane()
    island = Island()
    
    allSprites = pygame.sprite.Group(island, plane)
    clock = pygame.time.Clock()
    keepGoing = True
    while keepGoing:
        clock.tick(30)
        pygame.mouse.set_visible(False)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
                
        allSprites.clear(screen, background)
        allSprites.update()
        allSprites.draw(screen)
        
        pygame.display.flip()
    
    #return mouse cursor
    pygame.mouse.set_visible(True) 
if __name__ == "__main__":
    main()

Now the sprite.Group thing is adding some value. We we’ll just continue to add sprites to this and let the Group functions do the heavy lifting of updating all it’s contained sprites.

We’ll end with the third sprite, the Cloud. Again, we need to figure out the rules of the cloud:
1. Y-coordinate will move at random rates (speed)
2. X-coordinate moves (side to side)

class Cloud(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("Cloud.gif")
        self.image = self.image.convert()
        self.rect = self.image.get_rect()
        self.reset()

    def update(self):
        self.rect.centerx += self.dx
        self.rect.centery += self.dy
        if self.rect.top > screen.get_height():
            self.reset()
    
    def reset(self):
        self.rect.bottom = 0
        self.rect.centerx = random.randrange(0, screen.get_width())
        self.dy = random.randrange(5, 10)
        self.dx = random.randrange(-2, 2)

Nothing super new going on here. You can see the only collision we’re coding for is the bottom of the screen when we reset it. We don’t care if they move off the side. You see us having a variable “speed” with the line: self.dy = random.randrange(5, 10). The next line picks a random side to side drift.

def main():
    screen = pygame.display.set_mode((640, 480))
    pygame.display.set_caption("Bomber Pilot! bomber_plane.py - creating the Plane sprite")

    background = pygame.Surface(screen.get_size())
    background.fill((0, 0, 255))
    screen.blit(background, (0, 0))
    plane = Plane()
    island = Island()
    cloud = Cloud()
    
    allSprites = pygame.sprite.Group(island, plane, cloud)
    clock = pygame.time.Clock()
    keepGoing = True
    while keepGoing:
        clock.tick(30)
        pygame.mouse.set_visible(False)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
                        
        allSprites.clear(screen, background)
        allSprites.update()
        allSprites.draw(screen)
        
        pygame.display.flip()
    
    #return mouse cursor
    pygame.mouse.set_visible(True) 
if __name__ == "__main__":
    main()

Again, we’ve added the cloud sprite to the group allSprites and we’re done. Pretty awesome. Okay, so if you run the program now, you’re going to see something that’s not Call of Duty, but, far and away cooler than even the Mandelbrot set (unless you’re a Math person and then Mandelbrot is still way, way cooler):

Next time we’ll move on building sprites and adding sounds to the collissions. Thanks for making it this far. I’m still trying to find the best way to display code in these posts. So far, I like screenshots best for visuals, but it leaves a lot to be desired since you’d have to copy it by hand. I’ll figure it out eventually.

-Mike

Python PyGame: 1

Introduction:

A particular nephew of mine asked if I could help him write a computer game. I said of course, but I really had no idea what this meant. So, I did some quick research on Amazon and came up with a couple of books to run through on the subject. The next few blogs will be working through “Game Programming The Express Line to Learning”. It was written in 2006 fro Python (which you wouldn’t know by the name). Why Python? Because I’m teaching myself Python and I enjoyed my experiences with Django and Python on the more familiar web development side of things. Okay, enough with the chatter, onto some meat.

Assumptions:
This is written assuming you have Python 2.7 installed on your Windows 64bit machine. If not, modify accordingly.
You’re at least a level 1 programmer with a +1 ring of protection… (j/k).

Editors: I have switched to notepad++ for my Python work because my free PyCharm ran out. A major bummer because PyCharm is super awesome. Luckily, notepad++ is pretty good to when you add in the right extensions.

Download the appropriate installer.
If you go to the obvious place [http://pygame.org/download.shtml], you’ll notice there are no Windows 64bit installations.

If you try to install a 32 bit version, then on the next step you’ll get this error:

 
You have to go here for those: http://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame

Run the installer. Select the Entire Features to be installed and change the directory to your Python27 location.

Now open up IDLE and type: import pygame
It should think a bit and then come back to a >>> line.
If it does not you’re probably missing libraries, so go find them and download them.

So, now it’s time to write your first game.
Go ahead and make a folder inside your Python27 folder called games and then put another one in there called idea:

The core idea this book sets us up with surprisingly takes the form of ingenious acronyms! Acronyms are largely responsible for our higher pay and social eschewing. Regardless, they are a constant.
Here’s the SETUP:
IDEA and ALTER
Where A=ALTER
Thus, it’s really: IDE[ALTER]
What does it mean in pseudo-code?
IDEA (the game framework) =
1.Import & Initialize
2.Display Configuration
3.Entities
4.Action (broken into the ALTER steps)
ALTER
1.Assign values to key variables
2.Loop (infinite w/breakout clause)
3.Timer (setup framerate)
4.Event Handling
5.Refresh Display

 
Okay,now that we have a total understanding of what we’ll be diong from the beginning game to the end game, let’s jump right into the intro program that does nothing but display a blue screen:

Create a file called idea.py inside the games/idea folder.
Slap this code in there:

Let’s go over some of the less obvious things. We’re using an infinite loop. True. This appears to be acceptable in the gaming world, whereas I’m used to this being an unforgivable sin in the web world. Pygame is doing most of the heavy lifting. You don’t really need to know that pygame is a wrapper around SDL (Simple DirectMedia Layer: http://www.libsdl.org/ ), but, take it for granted that someone (Pete Shinners) did a lot of heavy lifting for you to make writing games fun and easy. Thanks Pete!
The clock.tick(30) is setting your FPS (FRAMES PER SECOND).
BLIT = Copies data from one rectangle to another (moves objects)
FLIP = displaying graphics on the screen the easiest way will be slow and create a flicker effect. Thus we use the “screen flipping” technique that implements “double buffering” routines (most new systems support this now) that is a special kind of blit which copies the screen object onto the visual display. This reduces screen refresh rates and improves the flicker effect.
And Blue = RGB value 0,0,255.

Open a command prompt and run this file:

You’ll see this:

It’s fairly amazing that something this awesome could be so easy… okay, so it’s not fairly amazing, but it is the foundation for everything from here on out.

Okay, so now lets move a box across a screen so we can see this screen refresh stuff in actions.
Create a new game file called movebox.py and slap this code in there (I made a new folder under the same name):

 

Not much has changed, but we have added another entity. Now we have a background and a box. Then in the Events we have told the box to move positions to the right on the X axis. We’ve also added in a “collision” detection with the edge so it will start over. Nothing mind blowing. Go run it.

 

You’ll see an animated version of this:
 

Okay, that’s a bit cooler than a blue background. Okay, that took us through to chapter 5. So, next blog we’ll get into some more interesting elements around drawing and events. Thanks!

Resources:
http://www.amazon.com/Game-Programming-Line-Express-Learning/dp/0470068221
http://pygame.org
http://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame
http://pygame.org/docs/tut/newbieguide.html
http://notepad-plus-plus.org/
 

© Copyright Duke Hall - Designed by Pexeto