Saturday 4 July 2015

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...

0 comments:

Post a Comment