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.

Sunday, 12 August 2012

Two more demos: Meteor Miner and Platformatic

Here's another couple of PyGame demos. Meteor Miner is a fairly straight clone of an old BBC Micro game, Thrust. Thrust was probably cloned from another platform, but it's not a style of game that has been used much recently. You control a spaceship by turning left or right and accelerating forwards, much like Asteroids, but the goal is to fly inside the structure of a meteor and recover ore. You can also shoot forwards to destroy the guns which will attack you inside the meteor.

Fuel is limited and ore makes you heavier. You can escape the meteor with just one tonne of ore, but the goal is to recover all of it.

This is the first game I've done with sound, although on all the platforms I've tried (Ubuntu, Windows 7 and Android) the sound suffers from an annoying latency. The game works well with the PyGame subset for Android but as PyGame doesn't handle multi-touch devices yet, I can't emulate the buttons on a touchscreen, so it will only be playable with a keyboard.

Platformatic is a puzzle game which looks like a platformer; rather than asking the player to time jumps exactly, it asks him or her to place instruction symbols onto the screen, which the character will follow when it treads on them. This partly came out of my frustration with platform games which require you to make a long sequence of carefully timed actions, often repeating the first ones hundreds of times until you finally get the last one correct.

I'm not particularly pleased with either of these games, but I've forced myself to bring them to a point at which I can publish them, as I otherwise tend to abandon old projects while half-finished and start on new ones.

Both games are available from my 2dgames repository on github and are MIT licenced: https://github.com/jmacarthur/2dgames. As before you'll need PyGame to play them; as I get better at creating games, I'll consider packaging some of them up or porting them so they can be played more easily.

Wednesday, 18 July 2012

Investigating Raspberry Pi performance problems

I bought a Raspberry Pi some time ago and have been trying to run some of my PyGame games on it. I'm going to describe one performance issue I've seen with it. This isn't a criticism of the board in general, which I still think is excellent for the price.

I wanted to show something off at the Raspberry Jam last weekend in Cambridge, so shunted one of my games onto the SD card and started it up. The good news is that the Pi's standard distributions come with Python 2.7 and PyGame already installed, which saves a lot of time and effort. The bad news is that my game, previously running at 120+ frames per second on my desktop was down to 5 FPS on the Pi, which makes it unplayable.

Of course you wouldn't expect a 700MHz ARM1176 to be as quick as my Core i5, but this isn't a particularly taxing game, and I expected it to be well within the Raspberry Pi's capabilities. It's a 2D game, using lots of blits to draw tiled scenery, some bitmap rotates and vector arithmetic for collision detection.

My first suspect was floating point, as my game uses a fair amount to do polygon overlap calculations and I'm using PyGame's libraries to rotate bitmaps. The old Debian linux distribution for the Pi didn't use hardware floating point. Yesterday, the new new Raspbian image was released with hardware floating point support, so I gave that a try. No luck - it's still at about 5 FPS.

Python has a built-in profiler which can be invoked with
python -m cProfile myprog.py

It's best to sort samples by time and save this to a file, so I use:
python -m cProfile -s time myprog.py > profileoutput

(You can also use "-o file" to redirect the profile output to a file, but it's saved in a binary format if you do that, so it's easier to redirect stdout, although this does mix the profiler output with the output from your program)

Here's the profile from the Rasbperry Pi, with some information stripped out for brevity:

   225868   65.576 {method 'blit' of 'pygame.Surface' objects}
        1   47.159 thrust.py:1()
      605    3.082 {method 'fill' of 'pygame.Surface' objects}
      605    2.802 {pygame.display.flip}
    64433    1.967 {range}
    76268    1.741 {shipIntersectsBlock)
    10030    0.977 {pygame.draw.circle}


It's often useful to look at the profile on the well-performing case, so this is the profile from my desktop machine:

   748686   11.493 method 'blit' of 'pygame.Surface' objects}
        1    2.859 thrust.py:1()
     2321    2.523 {pygame.display.flip}
     2321    0.405 {method 'fill' of 'pygame.Surface' objects}
   499709    0.246 (shipIntersectsBlock)
   247663    0.081 {range}

Time at the file level of thrust.py has gone up proportionally on the Pi, but this is probably because the desktop version ran for longer and initialization code wasn't such a significant part. This wasn't a very carefully controlled test. The main thing to note is that 'blit' is what we're spending most of our time on, in most cases. 

To test this, I removed one blit from the code which blits the static background onto the screen every frame. As might be expected, the performance went up from 5.2 FPS to 8.8 FPS. That's small in absolute terms but a very significant chance proportionally.

Now, there's a number of ways to reduce that - the scenery doesn't change often, so it may be more efficient to construct a single scenery image and keep blitting this to the screen rather than blitting each tile individually, each frame. There's also a lot of settings to play with regarding pixel depth.

I've got a suspicion that one of the biggest problems is the resolution I'm running - 1824x1104, which is a lot of work for the graphics hardware. My game only runs at 640x480, but I haven't figured out how to get the Raspberry Pi's framebuffer to use a lower res - using a smaller monitor would be the easiest way, if I had one.

Update 19th July 2012: Tried this on an Android tablet (Asus TF300) and got 25FPS; and on a laptop with an Intel U4100 @1.3GHz; Radeon 4550 - 50 FPS. Both of these devices are quite capable of doing lots of 2D blits at 50FPS without breaking a sweat, so the culprit is likely to be a software problem.