Making Bacon

A simple maze game that demonstrates some cool things we can do with actors. Create a new file named bacon.py and start with our standard first three lines of code:

Prerequisites

You'll need to have the Predigame platform installed, a trusty text editor handy, and the command prompt (or terminal) open to complete this tutorial. Visit http://predigame.io for installation instructions.

Download Existing Game (Optional)

We have a version of this game already done and ready to go. Just run the following command:

pred pull bacon

Then read the rest of the tutorial and follow along.

Getting Started

To get things started, we're going to create a new Predigame game. This can be done by typing the following the command in the terminal:

pred new bacon

Now in the text editor, find and open the file bacon/game.py. Fix up your code so it looks like the example below:

WIDTH = 30
HEIGHT = 18
TITLE = 'Making Bacon'

Like before, these lines doesn't do much just yet. Here's a line to add a simple background (remember backgrounds are retrieved from the backgrounds/ directory)

# use a grass background
BACKGROUND = 'grass'

Next we'll define a constant for the number of piggies to create. This line of code will not have any impact just yet.

# how many piggies to create
PIGGIES = 10

Now let's create a maze with stone images. Remember that we must have a stone in image in our images directory.

maze(callback=partial(image, 'stone'))

CHECKPOINT - try saving and running your code at this point. You should see something like the below picture.

alt text

Alternatively, it's also possible to create a maze with just black rectangles instead of stone images.

maze(callback=partial(shape, RECT, BLACK))

If all looks good with the maze, let's add our player actor. We're going for Soldier-2. The actor will be assigned to move on keyboard arrows and every keyboard movement will call the evaluate callback. This is code that we can use to "evaluate" each move to make sure the player can't walk through walls.

# a callback that keeps the player from running
# into walls.
def evaluate(action, sprite, pos):
    obj = at(pos)
    if obj and obj.tag == 'wall':
        return False
    else:
        return True

# create a soldier on the bottom left grid cell
player = actor('Soldier-2', (0, HEIGHT-1), tag='player', abortable=True)

# have the solider attach to the keyboard arrows
# each move is "evaluated" to make sure the player
# doesn't walk through the wall
player.keys(precondition=evaluate)

# player moves at a speed of 5 with an animation rate of 2
# which flips the sprite image every other frame
player.speed(5).rate(2).move_to((0, HEIGHT-1))

Let's give this a shot. Try running the code to ensure that the player can navigate the maze maze without being able to walk through walls.

The Predigame platform includes an abstraction for respecting maze walls, so defining an evaluate function isn't necessary. Instead you an have the line:

# have the solider attach to the keyboard arrows
# each move is "evaluated" to make sure the player
# doesn't walk through the wall
player.keys(precondition=player_physics)

If this works, try adding some piggies. Here is one case where the PIGGIES constant will be used.

# create a piggy function
def create_piggy(num):
    for x in range(num):
        pos = rand_pos()
        piggy = actor('Porter', pos, tag='piggy')
        piggy.move_to((pos))
        # graze is a random walk
        piggy.wander(partial(graze, piggy), time=0.75)

# create some piggies
create_piggy(PIGGIES)

Porter is an animated actor. There is a special callback function wander that allows the computer to control the movement of an actor. The wander is called for every movement, in the case of our piggy, calls the Predigame internal graze callback function which is a random and undirected movement.

Try running saving these updates and running the game. We'll see the maze, our player, and now some piggies! It's possible to speed up the piggies by adjusting the time attribute for the random walk.

alt text

The final part of our game is shooting! We'll create a shoot callback that is assigned to the space bar. It looks a little like an air shot, but the piggy effects are pretty cool.

# shoot a weapon
def shoot():
    player.act(SHOOT, loop=1)

    #find the next object that is facing the player
    target = player.next_object()

    # if it's a piggy and that piggy is alive
    if target and target.tag == 'piggy' and target.health > 0:
        # kill the piggy and make it disappear in 3 seconds
        target.kill(delay=3)
        # tally the kill
        score(1)

    # check to see if there are any piggys left
    if len(get('piggy')) == 0:
        text('Time for some BACON!! (%s secs)' % time(), color=BLACK)
        gameover()

# register space to shoot
keydown('space', shoot)

#we're keeping score
score()

# register the 'r' key for resetting the game
keydown('r', reset)

Notice we use the PIGGIES constant a second time? That's why we made it a constant. Our game needs to track all the piggies and will stop playing when PIGGIES piggies have been killed. NOTE: this code will not work if more points are assigned for each dead piggy!