Sunday, 5 July 2015

BASIC games in Python - 1982 would be proud (Part 3)

Ok, this is it - the one and only part 3, the final chapter.  We looked at pygame in part 1,  we deciphered the BASIC code in part 2,and now we're gonna produce a python version of this simple little 1K ZX81 game.

Why, oh why am I doing this?!

If you've sat through the previous 2 parts, then that's a question you're probably asking...

Is it purely to learn about converting old 1980's programs to python?  Well, in a way yes - its something I've wanted to do given how much python reminded me of my youth.  I am enthralled with the fact I can code games and have fun just as much as I did back at age 11.

But one thing I am hoping to instill on everybody who reads this article is that writing games is a great way to learn to program.  Programming is a a technical art form that has mostly disappeared these days.  Lets face it, nobody really goes and buys a high specced PC or Mac to sit and write programs - its mainly about playing the latest games, running business applications, browsing the web and making media.  And that's not a bad thing, but its also a sad thing.

If you're just getting into programming and need a challenge to help you learn, consider looking at the past (I've provided links at the bottom of this page).  This article is about using that 80's approach of learn through example.  By reverse-engineering a game from another language, you really can learn a LOT. Concepts that were used back in that era to make the most of the hardware (ie. tricks like using boolean logic for scores), the way game logic works and of course you pick up a lot about the programming language you're using by trying to work out how to create code that works the same way.

Don't forget - its a case of practise makes perfect.  In the 80's, typing in games and understanding how they worked was  how I learned to create my own code...  Today, the same concept is just as relevant - the more you do, the more you learn - and the more your expertise grows.

Its these reasons I've written this 3-part project for.  To try and bring a little of the past to the current day, and just show how much fun it can be to code games rather then click-drag them. 

That said, programming is a skill that's started being taught again in schools - and its great to see young people getting this opportunity.  In fact, I'm off to a secondary school in a couple of weeks to teach kids some python!  Very exciting.

So, lets get on with it.

Step 1 - make sure we have those things we can't program...

While the game can be coded, to really achieve that classic look we need to have the classic font and graphics!  There are some great free ZX-style fonts that people have created - I grabbed this one, and unzipped the files into the folder where I was writing my python script.

These are not the droids you are looking for, but definitely that font is...


When files sit in the same folder as your python project, we can load them easily by just specifying the filename - so put those fonts there.  There are two .ttf files - zx81.ttf and zxspectr.ttf...  Great font, and does a great job too.

If you don't want to use a custom font, for a project like this you'll need to consider using a monospaced font - one where all the characters (including space) are identical widths.  Courier for instance works just fine.

However, as great as the font is, we still need those clunky graphic characters.  The best way to handle this is to simply these draw up yourself.  8 pixels high by 16 pixels wide...  The thickness of the black blocks are 4 pixels.


Get the files here...

You can download the extremely tiny graphic (along with the source code for this game) here...  Obviously for permission reasons, I can't re-distribute the font - but here's that link to it again for convenience.

OK - enough natter, lets start to code this game and see how we fare.  I'll be showing code here in this article without my usual python comments in it - but don't fear as I'll be explaining what each part does below the code itself.

Modules

To start off, we'll need to import our modules of course.

import pygame
import pygame.time
import sys
from pygame.locals import *
from random import randint

In this block of code, its worth noting that I've loaded all (indicated by the *) of pygame.locals into the root namespace.  What's meant by this is that rather then referring to a command using its module namespace we can now refer to it directly.  I did this because it saves me having to write pygame.locals before each constant.  Now I can just refer to pygame.locals.QUIT simply as QUIT.

You don't need to do this, mind you. In the end you can just load them as you would otherwise if you prefer, but its worth considering.

Of course, we also need to bring in randint - a function that lets us ask for a random integer (used to determine where the coin would fall).  This I'm also loading into the root namespace from the random module.

Constants


So that our code will be easier to understand, and to save us repeating ourselves (plus in case we wanted to change a value used throughout a program) we will define a few constants here that we can use everywhere.

BLACK = (0,0,0)
WHITE = (255,255,255)
TXT = 16

BLACK and WHITE are defining the RGB values that we can use for drawing text, wiping the screen, etc.  The TXT constant is for text scaling - for instance, using the original pixel size of the ZX81 on a PC with a 1920x1080 resolution will be tiny and hard to look at.  This value will be used to let us change the size of all of our character elements.  In this case, I've used a size of 16 pixels per character.

Getting pygame set up



pygame.init()
fpsClock = pygame.time.Clock()

Obviously before we can use pygame, we need to set it up (see part 1 for an explanation about how this works).  This includes not just the pygame system, but loading in fonts and graphics that we will be using.

gameWindow = pygame.display.set_mode(( 32 * TXT, 22 * TXT ))

The ZX81 screen is 32 characters wide, 22 characters high (each character taking up 8 x 8 pixels).  We therefore need to set up our window appropriately, using our TXT scale constant.

Fonts


We want to import our zx81.ttf font.  Providing you've placed it into the same folder, we can refer to it directly by file name.  If you've instead installed the font into your system - or you want to use an alternate installed font - then you'll need to request the path to the font file itself.  That's fairly easy to do by asking for it using pygame.font.match_font('nameoffont').


bFont = pygame.font.Font('zx81.ttf', TXT)

For now, lets just load up the ZX81 font, and set its pixel size to TXT

Player graphic


pGfx = pygame.transform.scale(pygame.image.load('ZX81_block.png'),
                             (2*TXT,TXT))

We can import our nifty 8 x 16 pixel graphic and then resize it to match the rest of the game as follows.  In this line of code, I'm using pygame's transform.scale command to resize the file that I'm loading from disk...  You could of course break this into two lines - load image, and then scale - if you prefer.

As the width of the players graphic is double the height, we set the scale values to ( 2 * TXT, TXT)

Note : If you are unfamiliar with python, long code that is encapsulated between brackets (such as our parameters for the pygame.transform.scale command) can be broken apart into multiple lines.  This is termed implicit line continuation (python regards anything inside brackets, strings or parentheses as continuous until the brackets/etc are closed.  This includes code that is broken up over multiple lines)

Functions - its where the fun begins...


def bPRINT ( cRow, cCol, cGFX ):
    gameWindow.blit(cGFX, (cCol * TXT, cRow * TXT))

We'll now define some functions...  For our first one, lets define a function that takes care of simulating BASIC's PRINT AT command.  This will make life a lot easier for us.  If we can pass the same settings as the BASIC code, we'll end up making this code a real doddle to complete.

In the case of pygame, text and graphics are treated the same way.  Text, as we'll see in our game code, is rendered to an image first before its drawn (blitted) to the gameWindow.

The Game - a function?


The game itself - that part of the BASIC listing that does 10 rounds of coin catching - is being defined as a function.  Why, you may ask, would we want our game in a function?

Its simple...  Our game loop (which is the infinite loop that we write at the end of the program after the function) needs to be able to restart the game.  By making the game a function, we can call it from our main game loop.  When the game is over, if we then have the function return back to our main game loop (passing the score back as well), we can print the score and wait for a key press to restart the game (ie. call the game function).

playDropout - where BASIC and Python meet...

Get ready because this is where we translate that old BASIC code into its python equivalent.  We'll stick to using the same variable names as well as the FOR loops as the original code so that we can see the similarities...

def playDropout():
    T,P  = 0,0

We start by defining our score, and our players position in the game.  In Python we can do it in one line, rather then then two like BASIC.

    for Z in range(10):
      gameWindow.fill(WHITE)
      bText = bFont.renders("%d" % T, True, BLACK, WHITE)
      bPRINT(12,0,bText)

As in the original version, we have a for loop that gives us our 10 rounds of coin catching.  the gameWindow.fill does the equivalent of the CLS command by filling the display with white.

After that, the score is rendered to an image that is stored in the variable bText, then we draw it to our display using our handy bPRINT function

      R = randint(0,16)

Next we choose our random value we'll use to position our coin at. And then we're ready to catch that coin with our Y loop...

The coin falling...


      for Y in range(10):

Obviously we add in our Y loop.  The coin drops 10 characters downwards from the top of the screen.  Amusingly this does make it impossible to catch coins that fall over 10 characters away from the player... But hey, we'll keep to the original here and retain that particular retro-feature.

          for event in pygame.event.get():
              if event.type == QUIT:
                  pygame.quit()
                  sys.exit()

Before we jump into the game code, the first thing I've added is a test to see if the user has quit the game.  Quitting the game is called when the user closes the window...  We want to make sure we clean up nicely in that case.  Obviously this isn't something that we needed in BASIC - you'd never quit a program since it was the only thing running on the computer of course...


You'd notice that by importing the pygame.locals into the root namespace, I only needed to type the constant name QUIT here.  It looks cleaner, and its easier to type.

          N = P+(pygame.key.getpressed()[K_4])- \
                (pygame.key.getpressed()[K_1])

For the key press - the code is literally the same.  The only difference is that INKEY$ is replaced by pygame's pygame.key.getpressed() function.  As expected, both of these also return a True (1) or False (0) result.

Note : much like the transform.scale code, we've broken up this line with a line continuation character (back slash).  If your code isn't continuously encapsulated between brackets, parentheses or a string, we need this character to indicate the line continues.

          if N < 0 or N > 15:
              N = P
          bText = bFont.render("O", True, BLACK, WHITE)
          bPRINT(Y,R,bText)

Again, almost exactly the same as the original code - we check for our bounds, and then we print the coin (the letter "O") to the screen.  This is just too easy! (which is a good thing)

          bPRINT(11,N,pGfx)

We draw our player graphic...

          pygame.display.update()

Now that we've drawn our graphics, we simply need to update it to show it on screen.

         bText = bFont.render(" ", True, BLACK, WHITE)
         bPRINT(Y,R,bText)
         bText = bFont.render("  ", True, BLACK, WHITE)
         bPRINT(11,N,bText)

Finally we delete our graphics (the coin, and the player) - we can do this by simply printing a space character (or in the case of the players graphic, two spaces).  We can only do this, of course, as long as we are using a monospace font...  Any other type of font tends to have thinner spaces, which will only partially blank out half (or less) of the graphic.


         P = N
         fpsClock.tick(6)

We update our position to use the new position we calculated, and we set the frames per second to delay the game to keep it running at the right speed.  On my PC, I found a frame rate of 6 fps felt the most accurate to embrace the processing power of the ZX81

And that's the end of the Y loop. 

         T = T + (P == R or P+1 == R)

Once the coin has dropped all the way down (10 characters), the loop will end and continue into the next line...  This is where we'll update our score (again using the same logic from the original program) before the Z loop repeats.

    return T

Once the Z loop is complete, the function exits.  As we'll want to print the final score, this function simply needs to return T...

On to the main event, eh, loop

This is the end - our game is written as a function, all our initialisation is finished so we simply need to now put it all together in our game loop...

while True:
    fSc = playDropout()

We call the playDropout() function which will run the game, and then exit on completion of 10 rounds of coin dropping.

    bText = bFont.render("YOU SCORED %d/10" % fSc, True,BLACK, WHITE)
    bPRINT(12,0,bText)

We returned the score back, which will be stored in fSc.  Lets print that back to the player...

    pygame.display.update()

We won't see this until we refresh the display.


    replay = False
    while not replay:
        for event in pygame.event.get():
            if event.type == KEYDOWN:
                if event.key == K_SPACE:
                    replay = True
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

Finally, we want to pause until we press a key - well, in this case I'm going to set it to be the space bar, simply because its possible we may still be holding down a key from playing the game - which of course will jump us straight back into the game.  We also want to make sure we check for the user quitting the application.

This can all be done with a while loop that waits for the space bar to be pressed.

And that's it!  Once the space bar is pressed, the code will jump back into our while loop, running the playDropout() function once more.  Game on!

Final Comparison

If we remove all that additional Python code for rendering text, event catching, etc and look at the core code that actually is the game, we can see the way that the two languages compare - and its really not that different!


Congratulations!


If your catching the letter O and experiencing the excitement of doing that 10 times then you've successfully managed to write your own recreation of an old BASIC game in python!  In fact, what the aim of doing this was to demonstrate that you can code games very easily with python, as easily as kids did 33 years ago using BASIC.

Keep going!

If you don't write games at all - or want to learn more about how to develop your skills as both a programmer and a game developer then don't dismiss the opportunity presented before you.  Learn through typing in others games.

Of course, BASIC was a language found on most home computers.  While the dialect may be different, the logic behind how the language worked is no different - and there were just as many amazing games on other platforms as there were on just the ZX81.  Challenge yourself to find some of the amazing games that were around and learn to convert them into python.  You'll be amazed how much you will discover from looking at how people developed their code.

Resources online

There are lots of BASIC listings to be found online thanks the those people who are passionately preserving the past.  Magazine's are preserved and available from web archives such as retropdfsthe computer magazines archiveAtarimagazinesDPLibrary, etc.

Books, including some that explain how to program in a particular flavor of BASIC can also be found online.  Some other archives and sites worth looking into include Atariarchives, Folkscanomy, and the original publisher of well-loved books - Usborne (who have released a lot of their old 80's computer programming books for free - I wrote an article here).  You can actually read the ZX81 programming guide online if you want to understand the language more.

...and surprisingly the excellent collection of cassette software at ZX81stuff also display basic listings on screen when you click on them.  Back in the day, a lot of early 'commercial' games software was in fact written in BASIC.

So...

I'm definitely happy to be able to see how easy it is to code games the same way I did 33 years ago...  And no - I've no real plans to continue just re-writing old BASIC code in python.  Roll on new, modern games!

Saturday, 4 July 2015

BASIC games in Python - 1982 returns (Part 2)

Welcome to part 2...

We're going to break down an old 1k ZX81 game written in BASIC in 1982.  This code is a scan I made from the first-ever book I bought...  "34 Amazing Games for the 1K ZX81" by Alastair Gourlay.  It taught me a load of techniques that would have taken a long time to pick up on my own, such as reading keys and drawing characters moving on screen.


In the books foreword, written by Tim Hartnell (a name well known in the 80's when it came to programming books), it's pretty clear that the aim of the book is more then just a collection of games to play...

You'll probably want to enter the programs just as they are the first time you read through the book.  We'd like you to adapt them, improve and modify them to put your own stamp on them. And we're sure the programming tricks Alastair has used to compress the programs into 1K can be used by you in other programs.

This book is much more then just a collection of games. It is a guidebook to show you how to make the most of your 1K ZX81


The game - DROPOUT, catching coins


Lets take a look at what's going on here.

This game is, like most of that era (and for that little memory) very simple.  The player gets the chance to catch a coin that drops from the top of the screen (each time positioned randomly across the screen) ten times.  The aim of the game is to get the most catches out of 10.

Its simple, but when you compare the game play to something like the runner game concept that is all over the mobile market where the aim is to just collect as many items while avoiding the obstacles, the concept of simplicity is really no different.  The appeal comes in the whole 'one more go to get a better score' of what is a very basic game play model.


Breaking down the code into blocks, there are 4 things that are happening in here.

(A) We initialise the game by resetting the score, and setting the player starting position.

(B) This is followed by the game in not one, but two loops...  The blue loop (game loop (a)) runs the game 10 times - or in the game, this is the 10 coins that drop down and the player has to catch.

(C) The inner white loop (game loop (b)) is the main game - a coin falls down and the player has to get underneath to catch it.  Once the coin reaches the bottom, the blue loop repeats this game loop until 10 coins have been dropped.

(D) The last section of the game prints the players score - how many coins were caught out of the 10 that dropped, then waits for a key to be pressed before starting a new game.

Onto the code...

So what is happening here... What does all that BASIC code do, and how does this game work?  I'll break down the code into small snippets and explain what each is doing.  Once we've got the whole thing broken down, we'll be ready to jump forward to modern day python and re-create this 33 year old game in mear seconds... Eh, maybe more like between 10-20 minutes...

Is BASIC really basic?  Sure is...



T is a variable that is going to keep track of our score, and P is the horizontal position of our player on screen.  In here, we're setting both to a starting value of 0.  But in line 20, why not just type LET T=0 rather the use LET T=P?  Code takes up precious memory in the computer.  Because of the lack of it (1K), using a variable to set another saves memory (when you've only got 1024 every byte counts).

Memory?  Limits? What?

Today, this level of "optimisation" doesn't really make much sense I'm sure - after all, machines have gigabytes of memory.

As far as the technical explanation goes, a numeric value like "0" is stored in the computer as a binary representation based on its value, and the number of digits (ie. the text characters) entered...  This could be up to 6-8 bytes of memory.

Referencing another variable (P) means no need to store a value - instead just storing the reference to the P variable which takes less memory.  Yes - the 1980's were a very primitive time for computing, and we're talking about things here that you will mostly never-ever have to even think about these days.

Alastair Gourlay, the author of this book, has a section at the back of it that lists a LOT of optimisation tips such as this.  Valuable sage advice for that time!


(Note that the BASIC commands (like LET) were stored as a single byte - a numeric value that represented the command - rather then the 3 characters of the command.  The Sinclair BASIC language had a keyword mode you would use to enter these (usually the first thing BASIC would do, only allowing numbers to be entered first), where all the available program commands were accessed through a single key.  That's why the keyboard of these machines appeared to have a lot of commands and symbols printed on them)

Lets continue...


The game is all about catching falling coins.  Its really a game of getting "best out of 10", and this loop here repeats the game 10 times.


When we start each round, we start by clearing the screen using CLS (CLear Screen)


This line prints the score stored in T into a character location of the screen.  The command AT was followed by the vertical(row) and horizontal(column) positions.  In this case, 12 characters down, and 0 characters (the left side of the screen) across.



R is a random value between 0 and 17.  As with todays languages, INT forces the value to be a whole number and not a floating point number.  And as this game is all about catching one coin at a time, the coin falling down is done by looping from top to bottom (10 characters is how far a coin will travel).  In a way, this is a game-loop within a game loop.


The first line inside this Y loop is to draw a coin (the letter "O") on screen, at Y (vertically - starting at the top) and R (our random location across the screen)

Letter O?  Where's the graphics?!

In the ZX81, there really were almost no graphics capabilities other then some custom graphical characters and the ability to plot a chunky block to a location on screen (something like 64 x 44 blocks (what they called "pixels" but at a (very) low-resolution)). Drawing blocks one at a time was SLOW - so this is why so many games you would use text for their graphics elements.  That is why the letter O is used to represent a coin.

Nuff said, what's next...



N is a new variable that will be used to work out the new position of our player on screen, alongside P which stores the previous location.  Sounds confusing perhaps, but once we get further down in the code, it will probably start to make more sense.  Likewise, instead of using a +/- value here, instead we're relying on the True/False value (which is of course, 1 or 0) of a key check (the command INKEY$ checks if a key has been pressed).  Without using typed-in numbers in our code, we're saving a few bytes of precious memory...

Run me through this...  Hows that work?

Moving the player left and right by one character at a time just means adding or subtracting 1 from its horizontal value (which is currently being stored as N). Only one key can be pressed at a time, so the maths are fairly simple.

If 4 pressed, move P + (1 (True)) - (0 (False)).  That add's 1 to our position
If 1 pressed, move P + (0 (false)) - (1 (True)).  That subtracts 1 from our position

Don't fall off the screen! 



N contains the new location of the player.  This line simply tests the location is within the playing area. If it goes outside left or right then set N back to P (previous location).

Drawing the graphics, ahem, characters...

In Sinclair BASIC, multiple print location's can be placed in one line by separating them with semi-colons (;).  Rather then 3 lines (of course, which would consume memory) we can do three things in one.


The first AT deletes the players graphic by printing 2 spaces over it.  The next AT prints the players graphic (2 graphical characters) at its new location (N) and the last AT deletes the coin from the screen at its current location, ready to be moved and redrawn.

(Unlike modern systems like pygame where all the drawing is done on a surface in memory before its updated to the screen, all screen printing and drawing is done directly - think of the screen as being a "live update".  We delete the players graphic first by printing 2 spaces to blank the previous one out.  We then quickly print the player at the new location.  After that - as we've already seen the coin printed a few lines above - now we have to delete it from screen as we're going to move it and then print it at a new location.

If we don't delete it, we'll get a line of the letter "O" running down the screen. This is why you'll often see old BASIC games have fairly flickery graphics - even more flickery if the machine is very slow).

Update the players previous position



We'll copy the N location into P (to make it the previous location - remembering that N will of course be recalculated again to move it if a key was pressed)

Make the coin fall...



And we jump back and repeat our Y loop.  The loop essentially draws the coin coming down the screen until it reaches the bottom.  While this happens, the player can move left and right to position it underneath to catch the coin.

Did I win the game?  Did I, huh, did I???



Once the Y loop has completed, the code continues...  This is another of those ways to save bytes by using variables and a little math to add 1 to the score if the character was underneath the coin.  Like the INKEY$ calculation used for moving the character, we're again using a boolean (true/false) to add a point to the score.  P is of course our position on screen for the player.  R is the horizontal location of the coin...  Because the player graphic is 2 characters wide, we simply need check whether the coin was lined up with the first or second character to score a point (ie. +1 (if it was True))


We now roll back up to our next coin drop.  And it all happens again 10 times...

Lets play again...



Once we're finished the loop, we print the players score out of 10.  PAUSE 4E4 makes the code pause and wait for a key press, and RUN just executes the BASIC program again (RUN is of course the command for running a program)

Now you're a BASIC wizz-kid!

Sure - the games simple - but for 1982 it was a serious learning exercise and lots of fun (given there was nothing else to compare it to). If you're already savvy with python programming then you have probably already re-written that game in your head without much effort.

In part 3, I'm going to finally show you how I would re-write this in python, using of course pygame to relive the excitement of a 12 year old, some 33 years ago... 

After that, you can grab your mobile devices, play some flappy-roads, or crossy-bird games (with gameplay that is literally no more complex then something from the 80's) and journey back to 2015.

See you soon...

BASIC games in Python - 1982 returns (Part 1)

One thing I always enjoyed back in the 80's, and what made computing just so much fun was
the ability to write my own software - in particular - Games.

It was not just a lot of fun writing the games themselves, it was the exploration of what
the computer was capable of doing through code.  Home computing was all new - the wild west of computer gaming. It was about invention, discovery and mastering the machine and its programming language.

Nothing had really been invented yet.  No optimised game engines, no hardware accelerated
graphics and sound.  You had limited resources when it came to memory and CPU speeds,
which meant some pretty creative ways to make things happen...


Now - some 32+ years later along comes the modern age of computing.  Mobile devices are the
new gaming platform.  Tools to develop games are everywhere - hardware and software has been
honed for performance and the capabilities of the hardware and software are well documented.

There's no real need to invent your own graphics and sound routines, and even some applications
don't need you to understand how to program a computer at all - click a few options, drag in a
few resource file and be creative with the logic - viole!  An awesome game without the technical
requirements pops out.

But I love to code - and I like the simplicity that BASIC used to give...  In fact, I really
enjoyed playing some of those old typed-in games that I was inspired to code them again.  And that's what this post is all about...

What is BASIC?

Its the standard language that came with every home computer.  It was chosen because it was a relatively simple language to learn (in comparison to others around).  One machine (the Jupiter Ace) came with Forth rather then BASIC, but it didn't take off as much as the others.

However, while BASIC is a relatively standard language, each machine had a different 'flavor', or 'dialect' of it which made code incompatible across the range of computers of that time.

Well, hello there to you too, Mister BASIC!

So - tell me more of this BASIC you speak of...

BASIC stands for Beginners All-purpose Symbolic Instruction Code.  Unlike modern languages like Python, it was linear - written line-by-line, each one starting with a line number - each line of code would be executed from one line to the next (though that's how most code works of course - line by line - however without the numbering).  Below is a very simple example of a BASIC program.

10 REM This is a program that says hello to you
20 PRINT "What is your name?"
25 INPUT A$
30 PRINT "Hello "; A$
40 IF A$="Kevin" THEN GOSUB 100
50 GOTO 20
100 REM A subroutine to celebrate
110 PRINT "Awesome Name!  Lets Celebrate!"
120 FOR A=1 TO 100
130 PRINT "Hip-hip-hooooray! ";
140 NEXT A
150 RETURN

There was more to it then just writing programs

These commands were also typed into the computer directly (without line numbers) to operate the computer itself and make it do stuff.  For example, To save a BASIC program, you'd have to type the command SAVE "filename".   To display something on screen, you'd type PRINT "some text".  To reset the computer, you could just type NEW and it would clear the memory.  That said, sometimes you'd just switch the machine off and back on instead to do that!

BASIC could do a lot (it had to - operating the computer relied on it being able to do stuff!),  but compared to modern programming languages it was, eh, basic.

PYTHON

There's one language I feel makes coding as much fun as it was back then, and that's Python.

It really is (for me at least) the home computing language for the modern age.  Its easy to learn - like BASIC was.  Its more human readable then most other languages (such as Java or C++/C#).  The best part for me is that its a lot of fun to program with as well.  This makes it the perfect language (imho) for those new to coding.

Unlike the BASIC days, Python is more standardized - its the same across various platforms - you write a game on Windows, its likely it will work on an Apple Mac, Linux and even on that little Raspberry Pi you may have bought to play around with at home.

But Python has one thing that makes it an even better language for gaming, and that is its modular nature.  Python has all the bells and whistles of a standard language, but additional functions and features can be imported to extend it even further extremely easily...

To write games, then there's one free module you need to get...

Pygame

Pygame is awesome...  Its a game development suite that contains all the commands and features you need to draw graphics, play sounds and read keys/mouse when it comes to gaming.

You can download the installer for it from pygame.org


I also like pygame because not only does it extend the base Python language with a huge library of game-related features, the way games are programmed is literally the same as traditional BASIC games.  In fact, they're so similiar that it does make translating a BASIC program to Python very easy.

A look at the basic structure of a pygame program

Setting up a simple base program to work with pygame is very easy and goes something like this.

We start by importing the modules we need.  Obviously you should install Pygame before you get this far - but I'm sure you already know that...

import pygame
import pygame.time
import pygame.locals
import sys

(Note that I import the sys module mostly for its command sys.exit() - this is needed to help ensure that any game we're running gets properly shut down by Windows)

Next, we initialise pygame itself to make sure its all loaded in and ready to run.

pygame.init()

We'll want to control the speed the game runs at of course - if we're running on a super-fast system then things can of course scream along too quickly.  For that, we create a Clock() object that takes care of maintaining the programs playback speed.

fpsClock = pygame.time.Clock()

Give me something to look at

Games are just no fun if you can't see them on screen.  We next create a window for our game to be displayed in.  In this example, I'm making a 640 x 480 pixel window.

gameWindow = pygame.display.set_mode((640,480))

Note : gameWindow technically defines a surface, (imagine a blank image in memory).  This surface represents the pixel contents of our game window that we see on the screen.  When we want to place things 'on screen', we can draw, or blit them onto this surface.  Because this surface is in memory, this drawing takes place in the background.

Lets play!

And here's where the magic happens - the game loop itself.  Basically the game will repeatedly run until we force an exit from the game.  We create the game inside a while loop - in this case, an infinite one...

while True:

Once we're inside this loop, this is where the fun happens.  We take care of erasing graphics, moving objects, checking for collisions and redrawing graphics back to our window.  We can call functions from inside this game loop to show title screens, update levels, and so forth.  Since this is a generic structure example, I've got no code here (yet) - just know that we'll be developing our game here - honest...

Continuing on...

Next thing is that we should also check for any events - that is, asking pygame to let us know if something occured such as the mouse was clicked, a key was pressed or some other type of event like the user closing the window (essentially quitting the game).  This is done by iterating through a list provided by the function pygame.event.get() and checking if a particular event has occured.  The pygame.locals contains a collection of constants that allow us to check events by some name, rather then an obscure numeric value...

    for event in pygame.event.get():
  if event.type == pygame.locals.QUIT:
exitGame()

In the example above, I've asked a QUIT event to call a function called exitGame() where I will setup code that will cleanly close the game down.

(Note here that I'm referring to pygame.locals.QUIT for the event name.  We could load the locals into the root namespace of our program and just refer to locals using the event name (in this case, I could have just used the word QUIT without the pygame.locals namespace...).  This is easily done at the start of the script by importing the module using from pygame.locals import * )


Anyway...

Once we're done doing the biz of drawing and moving, we just need to tell pygame to update the game window.  This will copy the contents of our gameWindow surface from memory back to the screen.

    pygame.display.update()

Finally, at the very end of this game loop, we can use our Clock we created to force the loop to run at a specific speed in frames-per-second.  In this example, I'm forcing the game to run at 24 frames per second.  For an 80's game, this would be even slower since we'd be forcing the game to run as though its taking time to process on a slow CPU.

    fpsClock.tick(24)

And that in a nutshell is what makes for a generic pygame program structure.  We just need to fill in the gaps of course with our actual game code, but with this in place, we're ready to roll...

Before I finish up

What about that exitGame() function I made my QUIT event call?  Well, its as simple as this...

def exitGame():
    pygame.quit()
    sys.exit()

pygame.quit() unloads the pygame system, and sys.exit() makes sure the python game window is shut down properly.  Without sys.exit(), pygame.quit() will produce an error...  So using both is usually required.

Phew!  That's a lot to take in...

I'll end this article before it becomes immensely long, and let you digest that information.  If you've gotten this far, hopefully you're getting the buzz that you're keen to start writing your own games...  In part 2, I'll look at how we can reverse-engineer an old BASIC game from a ZX81 1kb listing and translate that to Python...  We'll attempt to keep the whole old-school look and style - so groovy retro graphics and all...

See you in the part 2...