Linux Format

Create Pac-man games in Python

Download from linuxforma­t. com/ archives Pac-man has earned its place in video gaming history. Calvin Robinson shows how you create your own version of the iconic arcade title.

- Calvin Robinson is a former assistant principal and computer science teacher with a degree in computer games design and programmin­g.

Calvin Robinson shows how you make your own version of the iconic arcade title.

Pac-man is arguably one of the most famous video game characters in the world. First shooting to fame in 1980 with the release of the arcade version, Pac-man has seen many iterations, remakes and sequels over the years, but nothing compares to the original.

It’s a simple premise, really. Pac-man is a yellow, disk-shaped, mainly feature-less character, who roams around a 2D environmen­t collecting dots. The player has to collect all the dots in the room without being touched by any of the four enemy characters in the form of ghosts. Pinky, Blinky, Inky and Clyde are brightly coloured to stand out against the black background, being pink, red, cyan and orange, respective­ly. Pac-man must avoid the ghosts and collect all the dots to progress to the next level.

Pac-man can only move up, down, left or right, through the maze of dots, but does have some advantages in his arsenal. By collecting large ‘power pellets’ Pac-mac becomes energised and the ghosts all turn blue, enabling him to eat them on impact. The more blue ghosts you eat, the more points you get. As with all arcade games, the aim of the game is to get the highest score on the leader board.

Originally called Puck Man in Japan because of the main character looking like a hockey puck, Pac-man was renamed for Western audiences to avoid any dodgy naming issues. It’s fun and friendly, and potentiall­y the first ‘inclusive’ video game, what with Pac-man being designed to appeal to girls as well as boys, and to attract a younger audience.

Working in Python

Likewise, Python is an incredibly accessible programmin­g language. In LXF262 we used Python to create a Lunar Lander Module game, and in LXF263 we created a side-scrolling game in Python. The original Pac-man game was released between the two, Lunar Lander being 1979 and the first side-scroller being 1981. Python is perfect for our retro gaming projects. So let’s begin…

We will, of course, need Python installed. We’ll use Python 3 for this tutorial. If you’re on a Debian-based distro you can get set up with sudo apt-get update , followed by sudo apt-get install python3 . We’ll also be taking advantage of a vector graphics module

linuxforma­t.py which can be found at the source code link on our Archives page at www.linuxforma­t.com/ archives. Once downloaded or copied, ensure

linuxforma­t.py is saved in the same directory as the Python project we’re about to develop.

Start a new Python file. Using your favourite text editor create an empty file and save it in the same folder as linuxforma­t.py, which we’ll be using as a reference module for vector graphics. When it comes to programmin­g, there’s no point reinventin­g the wheel every time. Start your new document off with a new modular imports:

from random import choice from turtle import * from linuxforma­t import vector

Next, we’ll want to declare and initialise all of our global variables:

state = {‘score’: 0}

path = Turtle(visible=false) writer = Turtle(visible=false) aim = vector(5, 0) pacman = vector(-40, -80) ghosts = [[vector(-180, 160), vector(5, 0)], [vector(-180, -160), vector(0, 5)],[vector(100, 160), vector(0, -5)],[vector(100, -160), vector(-5, 0)],] tiles = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1,1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,] Here we’re setting the spawn coordinate­s for our Pac-man and all four ghosts and settings the score to start on zero. Aim sets the movement direction of Pacman on game launch, with (x,y). By default we’re moving in a positive direction on the x-axis, which will take us right at the normal speed of 5. Stating zero for the y-axis means our Pac-man won’t be moving up or down on game start. We’re also create a couple of Turtles which we’ll use later: one for drawing the game world (Path) and the other for writing the score (Writer).

Finally, we’re creating the game world. Every 1 is a collectabl­e dot or floor space, and a 0 is a black wall. Our game world is 20x20, so it may be easier to organise the above Python list by creating a new line every 20th value. We haven’t done so here to save space in print, but it’ll look a lot better in Python if you do – well, more recognisab­le to the human eye, anyway.

Turtly good

Time to put those Turtles to good use. Let’s make a function to draw squares, which will be used to create squares (and rectangles) in our game, for the walls:

def square(x, y): path.up() path.goto(x, y) path.down() path.begin_fill() for count in range(4): path.forward(20) path.left(90) path.end_fill()

We’ll also need a couple of functions to work out the maths. Even though Pac-man is a relatively simple game, there’s still an element of physics involved, mainly in collision detection and ensuring our Pac-man doesn’t walk through the walls and out of the game world.

def offset(point):

x = (floor(point.x, 20) + 200) / 20 y = (180 - floor(point.y, 20)) / 20 index = int(x + y * 20) return index

This will return the offset. We’ll also need to check if moves are valid: def valid(point): index = offset(point) if tiles[index] == 0: return False index = offset(point + 19) if tiles[index] == 0:

return False return point.x % 20 == 0 or point.y % 20 == 0

Let’s use that Turtle again to draw our game world:

def world(): bgcolor(‘black’) path.color(‘blue’) for index in range(len(tiles)): tile = tiles[index] if tile > 0: x = (index % 20) * 20 - 200 y = 180 - (index // 20) * 20 square(x, y) if tile == 1: path.up() path.goto(x + 10, y + 10) path.dot(2, ‘white’)

Of course we can change the colours to suit, but to start with we’re using the traditiona­l black and blue environmen­t of the 1980 version of Pac-man. That final colour ( path.dot ) is assigned to our dots on the path. You’ll notice we’re taking advantage of the square function we set up previously.

Our one major function, move, will be used to move both our Pac-man and our ghosts around the game.

def move(): writer.undo() writer.write(state[‘score’]) clear() if valid(pacman + aim):

pacman.move(aim) index = offset(pacman) if tiles[index] == 1: tiles[index] = 2 state[‘score’] += 1 x = (index % 20) * 20 - 200 y = 180 - (index // 20) * 20 square(x, y) up() goto(pacman.x + 10, pacman.y + 10) dot(20, ‘yellow’) for point, course in ghosts: if valid(point + course):

point.move(course) else: options = [ vector(5, 0), vector(-5, 0), vector(0, 5), vector(0, -5), ] plan = choice(options) course.x = plan.x course.y = plan.y

up() goto(point.x + 10, point.y + 10) dot(20, ‘red’) update() for point, course in ghosts: if abs(pacman - point) < 20:

return ontimer(move, 100)

In this function we’re drawing the scores first, then we’re checking if a movement is valid before allowing it. The second if statement is what controls the eating of dots. If we wanted to take things a step further and introduce an animation, sound effect or other notificati­on we would introduce it after square(x,y) . Try adding print(“munch”) as an example.

Movement is all well and good, but we’ll need to be able to change the direction our Pac-man is aiming in. We’ll start be seeing if that direction is valid, thanks to our previous function, then we’ll go ahead and switch the x and y accordingl­y:

def change(x, y): if valid(pacman + vector(x, y)): aim.x = x aim.y = y

Our last function is for the floor calculatio­n, which takes into considerat­ion the offset we made earlier:

def floor(value, size, offset=200):

return float(((value + offset) // size) * size - offset)

With this we can work out the floor value given its size and offset. To explain the floor function we can use a number line diagram:

-200 -100 0 100 200 <--|--x--|-----|--y--|--z--|-->

The number line shown has offset 200 denoted by the left-hand tick mark at -200 and size 100 denoted by the tick marks at -100, 0, 100, and 200. The floor of a value is the left-hand tick mark of the range where it lies. So for the points show above: floor(x) is -200, floor(y) is 0 and floor(z) is 100. Some examples would be floor(10, 100) = 0.0 , floor(120, 100) = 100.0 , floor(-10, 100) = -100.0 , floor(-150, 100) = -200.0 , floor(50, 167) = -33.0 .

And finally, we can get our game going. We’ll need to set a resolution, hide the Turtles, write the score, listen for keyboard presses (we’re using lambda for this) and monitor the up, down, left and right keys for our aim changes. We’ll then draw the world, start the move function and we’re done!

setup(420, 420, 370, 0) hideturtle() tracer(false) writer.goto(160, 160) writer.color(‘white’) writer.write(state[‘score’]) listen() onkey(lambda: change(5, 0), ‘Right’) onkey(lambda: change(-5, 0), ‘Left’) onkey(lambda: change(0, 5), ‘Up’) onkey(lambda: change(0, -5), ‘Down’) world() move() done()

Our version of Pac-man is pretty basic, utilising 2D vector graphics and Python’s turtle graphics to draw shapes and dots on our screen. This art style is very much in-line with the look and feel of the original incarnatio­n of the game in the 1980. This simplistic artistic direction also meant we were able to code an entire game in a magazine article.

However, programmin­g techniques and computers have moved on incredibly since the time of the first Pacman release and if we wanted to take things a step further we could introduce graphical sprites into our game. For instance, we might want a more accurate representa­tion of our ghost antagonist­s in full colour, with features such as eyes.

Repl.it user Anurag Gowda has developed a relatively simple solution to take our Python game to the next level, by introducin­g said sprites. A sample of his code can be found at https://repl.it/talk/share/ Pacman/12194 which is fully forkable. Repl.it is an online IDE (Integrated Developmen­t Environmen­t) that enables you to code Python on even the most basic of machines, using cloud resources instead of your local hardware. All you need is an Internet connection. Using a fork of Anurag’s code on Repl.it you can code a visual Pac-man in the cloud – fancy!

 ??  ??
 ??  ?? A vector based Pac-man game developed in Python.
A vector based Pac-man game developed in Python.
 ??  ??
 ??  ?? Pac-man after collecting all the dots in the game.
Pac-man after collecting all the dots in the game.
 ??  ?? A ghost colliding with Pac-man ends the game.
A ghost colliding with Pac-man ends the game.
 ??  ?? Type in the final few lines of code, before launching the game.
Type in the final few lines of code, before launching the game.
 ??  ?? A beige and green game environmen­t shows up the black line of our score-writing turtle.
A beige and green game environmen­t shows up the black line of our score-writing turtle.

Newspapers in English

Newspapers from Australia