Im creating a game from scratch based on the GNOME game robots. Heres my documentation:
Let’s begin by thinking about what needs to happen when you play the game.
• Position the player and the robots on the screen.
• Repeatedly,
– move all the robots closer to the player
– check for collisions between robots, or between robots and piles of junk
– check also whether the player has lost
∗ (if so, the game is over)
– and whether all the robots are dead
∗ (if so, restart the game at a higher level (more robots!)
– allow the player to move or teleport
There’s a lot of stuff here. We’ll start. as uaual, by writing some easy bits.
Moving the player around
All the action takes place on a grid. Our graphics window is 640 pixels by 480; let’s make the grid 64 by 48 squares, each
10 pixels on a side. That’s a pretty good size.
We need to represent the player by something we can draw using the graphics facilities described in Sheet G (Graphics). I
suggest that a filled-in circle will do as well as anything else.
So, let’s write a simple program that lets you move the player around the screen. This involves a bunch of stuff that’s new,
so I’ll lead you through it carefully.
An outline of the program
To make this program easier to follow (remember that it will be getting bigger and bigger as we add bits to it, until it’s a
program to play the complete game of Robots), we’ll divide it up using functions. (See Sheet 3, and Sheet F (Functions).)
So, begin by typing in the following program.
As usual
from livewires import *
So that we can draw things
begin_graphics()
This is explained later!
allow_moveables()
place_player()
finished = 0
while not finished:
move_player()
We’ve finished
end_graphics()
As the program develops, we’ll add bits to this skeleton (for instance, there’ll be a place_robots() function added
quite soon). For the moment, our task is to define those functions so that the player can move around the screen.
Where to start?
Let’s look at place_player(), which decides where on the screen the player should begin. Remember to put the
definition of place_player before you actually use it.
Well, this at least is easy. Let’s have two variables called player_x and player_y, saying where the player is. You
could either make them contain the player’s coordinates in pixels, or the coordinates in grid squares (which will be 10 times
– Page 2 –
5 The Robots are Coming!
smaller, because each grid square is 10 pixels on a side). Either is perfectly workable. I prefer the latter, though it’s not a
big deal; you should probably go along with my preference, because for the rest of this worksheet I’m going to assume that
you have done!
I’d better explain this business about “grid coordinates” a bit more carefully. The graphics window is made up of 640 × 480
pixels. We’re chopping them up into 64 × 48 squares.
So, the bottom-left pixel of square (17,23) is pixel (170,230) and its top-right pixel is pixel (179,239).
Back to place_player(). It needs to set the variables player_x and player_y randomly. player_x can have
any value from 0 to 63; player_y can have any value from 0 to 47. If you can’t remember how to do that, look back at
Sheet 2 where random_between() was introduced.
And then it needs to put the player on the screen by saying something like circle(player_x, player_y, 5,
filled=1), except that those obviously aren’t the right coordinates for the centre of the circle (because player_x etc
are measured in grid squares, and circle() wants coordinates in pixels). What we actually need is for the centre of the
circle to be in the middle of the grid square. So circle(10*player_x, 10*player_y, 5, filled=1) should
do the trick.
(If you’re confused by the filled=1 bit, you might like to take a look at Sheet F (Functions), which describes “keyword
arguments”.)
– Page 3 –
5 The Robots are Coming!
Moving the player
Now, we need to move that circle around in response to what the player does at the keyboard. This involves two new ideas
– moving graphics, and keyboard handling. Let’s deal with the first one first.
In the “Python Shell” window, type the following:
from livewires import *
>>>
begin_graphics()
>>>
allow_moveables()
>>>
c = circle(320,200,5)
>>>
What allow_moveables() does is to make a small change to the behaviour of functions like circle. That fourth line
still does draw the circle, as you’ll have seen, but it does something else too: it returns a value, and that value can be used
later to move the circle around (or remove it from the window completely).
So, try doing this:
>>> move_to(c, 300,220)
The circle should move when you do that.
Challenge: Write a loop that makes the circle move smoothly from (0,0) to (640,480): in other words, from the bottom left
to the top right of the screen.
One other thing:
>>> remove_from_screen(c)
You can probably guess what that does, but you should try it anyway.
Keys
That’s all very well, but of course no one will play this game if they don’t get to choose where the player moves! The easiest
way to do this is to let the player use the keyboard. We’ll allow movement in 8 different directions . . .
. . . and of course we should allow the player to stay still. So we need a 3 × 3 grid of keys. Your keyboard almost certainly
has a “numeric keypad” on the right: the numbers 1–9 will do fine. So, for instance, pressing “7” should make the player
move upwards and to the left.
Therefore, what we have to do inside move_player() is to test which of those keys (if any) is pressed.
The function keys_pressed() returns a list of the keys that are pressed. Usually this list will either be empty or have
exactly one thing in it. (Keys are represented by the characters they produce. Letter keys are represented by lowercase
letters.
– Page 4 –
5 The Robots are Coming!
If you’re in any doubt about how this works, run the following program, go over to the “Graphics Window” and press some
keys. You may find that it doesn’t respond very well; that’s because the time.sleep() (which tells the computer to do
nothing for a while) interferes with the computer’s ability to watch for new key-presses. (There are better ways of doing the
same thing, but they’re more complicated.) When you’re done, hold down the Q key until the machine notices.
from livewires import *
See Sheet T for more about this
import time
begin_graphics()
while 1:
keys = keys_pressed()
print keys
See Sheet C if you don’t understand this
if ’q’ in keys:
See Sheet L if you aren’t sure what this means
break
Wait half a second.
time.sleep(0.5)
So, now you know how to tell what keys are pressed, and you know how to move an object around. So, put the two together:
Change place_player so that it puts the value returned from circle() in a variable (maybe call it player_shape
or something); and
. . . write a move_player() function that uses keys_pressed() to see what keys are pressed, and moves the player if
any of the keys 1–9 are pressed. Moving the player requires
• Updating player_x and player_y
• Calling move_to to move the player on the screen
Eeek! I bet you find it doesn’t work. Specifically, the move_player() function will say it’s never heard of the variables
you set in place_player(). What’s going on?
If you haven’t already read Sheet F (Functions), now might be a good time to glance at it. The important point is that any
variable you set in a function (e.g., player_x in place_player()) are “local” to that function: in other words, they
only exist inside the function, and when the function returns they lose their values. Usually this is a Good Thing (for reasons
discussed briefly in Sheet F), but here it’s a nuisance. Fortunately, there’s a cure.
Suppose you have a function definition that looks like this:
def f():
blah blah blah
x = 1
blah blah blah
Then x is a local variable here, and calling f won’t make a variable called x that exists outside f:
>>> f()
>>> print x
Blah blah blah ERROR ERROR blah blah
NameError: x
But if you add to the definition of f a line saying global x (just after the def, and indented by the same amount as the
rest of the definition), then the variable x inside f will be “global”: in other words, x will mean just the same inside f as it
does outside. So the print x that gave an error with the other version of f will now happily print “1”.
I hope it’s clear that this bit of magic is what we need to fix the problem with place_player() and move_player().
Add global statments to both definitions.
At this point, you should have a little program that puts a circle on the screen and lets you move it around using the keyboard.
Fair enough, but (1) there’s not much challenge there, without any robots, and (2) you might notice that the player can move
off the edge of the window!
And I am completely stuck. Heres my source so far:
from livewires import *
import time
begin_graphics()
allow_moveables()
player_x = random_between(0,63)
player_y = random_between(0,47)
place_player = circle(10*player_x, 10*player_y, 5, filled=1)
def move_player():
keys = keys_pressed()
move_to(keys)
print keys
if 'q' in keys:
print "shits workin"
time.sleep(0.1)
raw_input()
end_graphics()
Any help would be appreciated.