No longer updated!

My blogspot site is no longer updated. Most of the posts here are archived at www.srimech.com along with new content.

Thursday 31 January 2013

Reimplementing TinyHack in PyGame

This is a small exercise I did today. It's a reimplementation of Rob Beschizza's TinyHack in PyGame. Of course, I don't expect anyone to download and play a game which you can play a better version of in your browser. This is just for fun and possibly as a starting point for other Roguelikes.

It's a reimplementation rather than a port; Rob did provide the source, but it's in Flash format which I've no idea how to read. The 'artwork', levels and sounds are remade from scratch, using SFXR again for the latter. It's stripped down somewhat - the world is smaller, only having three 'dungeons', there's no magic, and no village, although the pub still exists.

Behind the scenes, there are two main global stores of information in the game. There's a large map, a 2D array of integers, which changes occasionally (squares which represent gold or items are replaced with empty squares when the player moves over them). The second part is a 1D array of 'Entity' objects which contains the mobile things; the player and any enemies. Entities have an x and y position and HP (health) as well as a few other bits. To make things simple, the player is always at index 0 in the entity array. To draw the screen, it's only necessary to draw the map around the player and then the entities. Timing is basic; the game waits for a keystroke to do a player move, and then does an enemy move if the player did actually move anywhere. Enemies have very basic AI, and will just move towards the player if they can. When trying to move in any direction, the game needs to check both the map and the entity list for space. If there's an entity blocking the target square, the entity may attack the target. Enemies are marked as one team which is different to the player, so they won't attack each other. Finally, the player has the extra option of moving into 'teleporters' which are the red squares on the map.

Items and gold aren't part of the movement routine, but are checked for after moving. Gold just disappears and a counter is incremented. Items need to do different things, so there's a static Python dictionary which maps coordinates of items to types. (39,14) is the shield, for example. A similar dictionary maps teleporters to their destinations. There are also some special teleporters, such as the pub and the jetty, which are marked as special by having a destination x coordinate of 0. The y coordinate in these is an action index which is taken instead of moving the player. 1 is the pub which restores the player's health and 2 is the jetty which ends the game.

The map and teleporter/object data could be coded directly in Python, however it's a lot more convenient to do it in Tiled. As well as making the base map, it's also possible to use Tiled to specify the teleporter relationships and other bits using an object layer. The collectible items, for example, are marked by small objects on the map with the 'item' property set to either 'hp', 'sword' or 'boat'. The code to read this data out of Tiled's XML and into Python structures is in the separate file 'tilereader.py'.

TinyHack removed a lot of common Roguelike features to make it work in a simple graphical environment: Lighting, line of sight, decent enemy AI, inventory, statistics, skills, fine-grained turn timing and random level creation are all missing. It's still a fun game though. As I said, MicroHack is a starting point, and I'd like to add to it. The question is, which of the missing features are actually important?

As usual, the code is in github at https://github.com/jmacarthur/2dgames, in the 'microhack' directory.