2016-11-19

Chuckie Egg Releases

Just in time for the holidays, here are final versions of Chuckie Egg for DS and PSP, and an almost-final version for the Dreamcast:

Chuckie Egg DS

Post Mortem

PSP

The PSP has a huge screen. Well, relative to the DS; maybe not so huge if you compare it to a modern phone. What do you do with all that space if you’re remaking a game that fits in 256x192 pixels? The obvious thing to do is double up the pixels and make the graphics twice the size. But wait; at 272 pixels tall the PSP’s screen is only 70% larger vertically than the Dragon 32, which means we can’t double up the resolution without losing 30% of the game’s display. I imagine it’s possible to wrap the game’s bitmap onto a quad and get the GPU to stretch it, but I eventually decided just to centre the game at its native resolution.

The PSP’s screen is 480 pixels wide but its default framebuffer is 512 pixels wide. Trying to change the width of the framebuffer to match the screen does not work (it results in the display being smeared horizontally, which always means “the dimensions of your bitmap do not match the layout of memory”). I had to add in the concept of “usable” vs “available” framebuffer space (“physical” vs “logical”, I suppose) and base the layout of the various screens on that.

It’s possible to push the PSP’s “home” button and quit from a game back to the launcher. Making this work entails creating a background thread and wiring up a callback that the OS can use to signal to the game that it needs to quit. It’s very simplistic; if the game doesn’t implement the callback then the system just hangs forever. The OS doesn’t appear to forcibly quit rogue processes. I’m not even sure that it’s really a multi-process system. I imagine Sony handled errors like this in their QA process so they didn’t bother with anything more elaborate to catch badly-implemented games.

Different geographic regions have different PSP button layouts. I don’t quite know what Sony thought the advantage of swapping the O and X buttons was, but it means well-behaved homebrew has to work around it. Games typically either allow the buttons to be remapped or come in different builds for different layouts. Official games were region-locked so that wasn’t an issue; it was probably fixed during localization. I’m too lazy to deal with it.

Getting sound working was troublesome. The basic PSPSDK libraries offer a way - I think - to craft PCM data and play it back, which really doesn’t help if you just want to play a WAV and not put any thought into it. I ended up using libmikmod, which has some peculiarities. Its MikMod_Update() function must be called regularly in order for sounds to work, but that can be stuffed into another background thread and forgotten about. It offers two ways to play back samples: Sample_Play(), which will automatically choose a channel to play back on, and Voice_Play() which lets you choose the channel. I found that Sample_Play() always chose exactly the wrong channel and ended up stopping sounds that I wanted to continue playing, so I switched to the alternative function. Voice_Play() doesn’t have any useful documentation. Inspecting the library’s code reveals that the trick is to set the volume, frequency and panning of the voice each time a new sample begins:

Voice_Play(channel, sound, 0);
Voice_SetVolume(channel, sound->volume << 2);
Voice_SetPanning(channel, PAN_CENTER);
Voice_SetFrequency(channel, sound->speed);

DS

The DS has a second screen. What do you do with two screens when remaking a game designed for one? I had a few ideas:

  • Level editor;
  • Chuckie Egg title screen;
  • Simian Zombie logo;
  • Dragon 32 image.

In the end the SZ logo was simplest, so I went with that. Otherwise, the DS is my default platform, so there aren’t any surprises here.

Dreamcast

It appears that calling snd_sfx_stop() on a channel playing a stereo WAV file will only stop one of the channels, which explains why sounds weren’t behaving themselves in the beta. Switching to mono files fixed it. Another problem was caused by limitations of the audio hardware: the Dreamcast can only play back the first 65534 samples in a WAV file, which is far shorter than several of the sounds in the game. To work around this I halved the sample rates of the longer samples. That fixed most of them, but the title song and Spectrum loading sound were still too long. I converted those to MP3 and used the streaming API, but that created problems of its own. Sounds still cut out or don’t play, and the emulator I’ve been using to help development crashes whenever I call mp3_stop(). There’s still some work to do there.

The DC has a similar problem to the PSP: I’m using the 320x240 NTSC graphics mode, but a good portion of that is off-screen on my TV. The “usable” framebuffer space concept helped out here.

The DC feels noticeably faster than the other two platforms, which is odd, as I’d expect them to run at identical framerates. Perhaps it’s just because it runs on such a massive display.

The Dreamcast’s reversed ARGB ordering means I’ve had to convert bitmaps into both DS and DC sourcecode and use #ifdefs to choose the right version of the data for the current target platform at compile time.

Cross Platform

What was most surprising was how little effort I had to put into Chuckie Egg in order to make it performant on these different platforms. The effort that went into Hanky Alien presumably helped a lot. I was testing HankyAlien with up to ~140 views on screen at once and up to ~45 of those updating simultaneously. In contrast, despite superficially being a more complex game, Chuckie Egg has ~45 views on screen at once and only ~10 updating simultaneously. (It’s interesting to note that, while both the DS and DC struggled with the HankyAlien test scenario and their framerates suffered, the PSP sauntered through it without a hitch. I really must write something specifically for the PSP in future.)

Writing object-oriented C is fun, but sometimes I look at the amount of boilerplate necessary to create a new “class” and decide to do things another way, particularly if I’m creating a base class. The most simple class requires:

  • A static metaclass struct, which forms a linked list back through the chain of superclasses (it enables the program to determine the type of an object at runtime).
  • A static callback struct that includes pointers to equality/comparison/hash/copy/dealloc functions.
  • Declarations of those functions.
  • Implementations of those functions.
  • A struct with the member variables of the class.
  • A typedef that defines a pointer to the struct, allowing the struct to be hidden.
  • A constructor that calls the allocator and initializer methods of the class.
  • An initializer function that sets up the members of class instances and calls back to the superclass’ initializer.
  • A convenience release method that wraps the basic release method.

If the class is intended to be subclassed it must also:

  • Provide an additional private header including:
    • A callback struct definition that nests the superclass’ callback struct and enables “methods” to be “overridden” (really it’s the template pattern with function pointers).
    • The struct itself, so subclasses can directly access properties of the struct and include the struct as the first item in their own structs.
  • Call the functions in the callback struct when appropriate (including those for the superclass).

Every time I create a new class I do so by copying-and-pasting an existing class and modifying it rather than start it from scratch and have to retype all of the boilerplate. Sometimes I’ll think about the work involved in setting one of these things up, pine for C++ or Objective-C, and then use a different structure that’s less “correct” but will still get the job done without smelling too badly. The grain and eggs, for example, should really inherit from a single “collectible item” class, but the correctness of that design doesn’t in any way compensate for the amount of work involved in setting it all up.

Keeping a strict separation between the model (game logic), the views (the stuff you see on screen) and the view controller (delegate of the model; updates the views to match incoming events) results in some beautifully clean code but makes prototyping difficult, especially early on when none of the infrastructure is in place. I did most of the early prototyping in the view controller before moving it into a separate model.

Each level renders its static content (ladders, platforms and bird cage) as a bitmap when it begins. It passes that up through the model to the view controller, which uses the bitmap as the background view for the game. That eliminated the need to create dozens of views to represent tiles that never change during the course of a level.

There are now 134,000 lines of code in the project, but a sizable number of those are included in bitmaps that have been converted to C.

2016-11-10

Chuckie Egg

Back in the early eighties, when the home computer boom was booming, my parents decided to buy themselves a computer. Following the advice of various computing magazines of the era they ended up with what was supposedly the best of the bunch: the Dragon 32. It featured 32K of RAM, a real keyboard and a Centronics parallel port. It was powered by Bill Gates’ favourite 8-bit CPU, the Motorola 6809. Unfortunately for my parents and their new Dragon, the manufacturer ran into financial troubles and collapsed not long after.

The unusual choice of the 6809 CPU meant very little software was written for or ported to the platform. One of the few games that made it was the BBC and Spectrum classic “Chuckie Egg”. This obscure port (the World of Spectrum doesn’t list it) is by far my favourite version, and it’s the game I spent the most time playing on our Dragon. There has never been a remake of it. Worse, neither the Dreamcast nor the Nintendo DS has a native version of Chuckie Egg. Let’s fix that.

Here’s a beta version of my remake of the Dragon 32 version of Chucky Egg for Nintendo DS and Dreamcast:

A couple of screenshots:

Chuckie Egg Logo Chuckie Egg Game

The game itself is fully playable, but there’s still some polishing to do:

  • Sound on the Dreamcast is misbehaving;
  • The Dreamcast version runs faster than the DS, so some timings are off;
  • Later levels do not have increased numbers of hens or faster moving hens;
  • Hens don’t eat grain;
  • The high score table is not functional (it’s just a bitmap);
  • There’s no “game over” screen;
  • The score/timer/etc display layout and font is all wrong;
  • Remaining lives aren’t displayed;
  • The font in the title screen scroller is wrong.

This is an inexhaustive list of bugs I spotted in the original game while making this:

  • On the first level, climb the largest ladder to the third platform on the right (the start of the staircase). Stand on the ladder just below the top of the floor and jump right. Instead of bouncing off the first step in the staircase, Harry lands inside it. Now press right and Harry will fall through the platform on the right. (The remake fixes this.)

  • On level 7, stand next to the two blocks immediately on the right when the level starts. Face them, hold “right”, and jump. Harry stands in the middle of the upper block. (The remake reproduces this.)

  • Animation frame doesn’t reset when Harry stands on an elevator. (The remake fixes this.)

  • When a new level rolls in the remaining time is set to 999; it immediately jumps to 898 when the level starts. After dying it resets to 899.

  • Harry gets killed if the elevator he is standing on hits the top of the screen, but if he is jumping then he falls through the elevator. (The remake doesn’t kill Harry; he just drops down when the elevator disappears.)

  • There are a bunch of inconsistencies with ladder behavior. Sometimes it is possible to walk from a platform all the way across a ladder; sometimes Harry falls through half-way along the ladder. This looks more like a bug than desired behavior.

  • One of the extra hens on level 3 (at the bottom of the twin ladders) starts one block below where it should do.

Here are some of the differences between the remake and the original:

  • Jump isn’t quite the same.
  • Frame rate is much better.
  • No flickering.
  • Hen patterns aren’t the same (but the Dragon doesn’t match the BBC or ZX, and they don’t match each other, so that’s OK).
  • Duck moves smoothly.
  • Hens move more smoothly.

I think this will be the last remake for a while. This is the list of remakes I’ve managed to complete (more or less) so far:

  • Pong (Blitz Basic/C/C++/Java/Flash; Amiga/Cybiko/GBA/DS)
  • Asteroids (Flash)
  • Mario Bros (Flash)
  • Tetris (Flash)
  • IK+ (Flash)
  • PacMan (Java; Linux)
  • Space War (Java; web applet)
  • Earth Shaker (C++; DS/SDL)
  • Super Foul Egg (C++/Objective-C; DS/SDL/OSX/iOS)
  • BioShock sub game (C++; DS/SDL)
  • Space Invaders (C; DS/SDL/DC)
  • Chuckie Egg (C; DS/SDL/DC)

This is the list of remakes I started but abandoned:

  • World Grand Prix (Flash)
  • Trick or Treat (Java; web applet)
  • Atic Atac (C/C++; Cybiko/DS/SDL)
  • Defender (C/C++; DS)
  • Dan Dare (C; DS/SDL)

2016-10-13

HankyAlien v20161013

New releases of HankyAlien for Dreamcast and Nintendo DS!

Changes for Dreamcast are:

  • Added sound;
  • Fixed palette;
  • Improved performance;
  • Fixed layout for NTSC TVs.

Note that the sound doesn’t work at all well with lxdream.

Aside from the massive behind-the-scenes rewrite, there shouldn’t be anything noticeably different between this DS version and the last release.

2016-10-10

HankyAlienDC

A few more evenings of reorganising things for the Dreamcast and here’s HankyAlienDC:

HankyAlienDC

The archive contains a .elf version that will run in lxdreams, and presumably other emulators, and a .bin version that will run via an SD adaptor and DreamShell RC4. It will presumably run if you somehow burn it to a CD, but it’s been so long since I’ve made a CD of Dreamcast homebrew that I’ve completely forgotten how to do it. Plus I’m on a different OS and don’t have an optical drive any more.

There are still a few issues to be fixed:

  • The colors are wrong. The components in DS pixels are ordered ABGR; DC pixels are ordered ARGB.
  • Elements at the top and bottom of the screen are cropped out. The display is set to 320x240@60Hz, but of course NTSC TVs don’t display 240 vertical pixels; they display 200.
  • There’s no sound yet.

Here’s my Dreamcast test hardware, acquired from Amazon and eBay:

Dreamcast

Things I was surprised to learn about the Dreamcast:

  • There were multiple revisions of the hardware. The final US revision doesn’t support homebrew because Sega removed support for the “Mil-CD” multimedia disc format that had enabled all piracy on the system. There was only one PAL revision, which did support Mil-CD, which explains why I’d never heard of incompatible hardware before.
  • On a modern flatscreen TV - or at least, on my TV - the quality of the composite video output is awful. Really, really awful.
  • The performance of the emulator isn’t at all representative of the performance of the hardware.

2015-09-13

HankyAlien Updated

Here’s an update to HankyAlien:

Changes include:

  • Big refactor of the dirty rect erasing system to make it much cleaner and faster (it had zero effect on observable performance, though);
  • Added an ARGB8888 frame buffer for massive SDL performance gains;
  • Number of extra lives is limited to 5;
  • Sound system is started up when the game is loaded, not when the first sound is played (slight SDL performance improvement);
  • UFO sound loops on DS as the UFO moves across the screen;
  • Restored the “Simian Zombie” intro screen that was accidentally disabled in the first release;
  • Difficulty gradually increases as player completes each wave of aliens;
  • Fixed flickering score titles;
  • Improved the ship explosion animation.

Getting the UFO sound working was far more involved than it should have been. The only way to loop sounds in Maxmod, the NDS homebrew audio library of choice, is to add loop markers to the WAV file. Unfortunately the standard for loop markers in the WAV format is either badly documented or badly designed, because almost nothing supports it (certainly no OSX sound editors that I could find). Maxmod offers no way to know when a sound has finished playing so there’s no easy way to make the sound loop (short of counting frames and replaying the sample when we think it should have stopped based on its length). In fact, the only way to achieve a looped sample is to load up MilkyTracker, set up a loop in the sample editor, then make a virtually empty XM mod that loops. Insane. The mod approach worked, but for some reason the mod wouldn’t stop playing when told to do so. Eventual solution? Copy-and-paste in a sample editor to extend the length of the sample so it lasts as long as the UFO’s traversal of the screen.

More HankyAlien trivia follows…

It took a year to develop the game, but that included only a few weeks of real work. According to the Git logs, there was a six month stretch where I didn’t touch it at all. I only have time for coding or writing, not both, hence the lack of a regular game diary during its development.

I completely forgot about Grit (the bitmap conversion utility supplied with devKitARM) so I painstakingly created all of the graphics except for the title screen in SublimeText as grids of 5 digit ARGB1555-format integers.

Back-porting bits of WoopsiGfx to C exposed some interesting bugs, including:

  • The DMA-enabled copy routines never use the DMA hardware because of a broken bounds check.
  • The hash function used in Woopsi’s bonus hash table class has a copy-and-paste error that means it always returns a wrong value.

Up until a few seconds before I released the first version of the game, there was no code to handle the situation in which the aliens collide with the player. Oops.

The name comes from my youthful mispronunciation of “Heiankyo Alien” back when the Game Boy was the handheld to own. I figured there should be a game called “Hanky Alien”.

The game is really just a test of the library. It was originally going to be a remake of Ultimate’s Atic Atac, but I changed my mind before I got too far along.

Including the libraries it is testing, HankyAlien weighs in at around 25,000 lines of code.

2015-09-07

HankyAlien - A New DS Game

HankyAlien Title HankyAlien Game

Here’s a new homebrew game for the Nintendo DS. You should be able to tell exactly what the game is from the screenshots. Download it here:

Diary of a Game

It occurred to me that I’d never written a large project exclusively in C. I’ve written little utilities and libraries in C, and used it occasionally in C++ and Objective-C programs, but a whole project that’s just C? Nope. I’d promised myself I was done with remakes and DS programming, so why not try writing a new remake for the DS in C?

The first thing I needed to do was write my own core libraries from scratch, because that’s always the interesting part. Abstract away some of the C nastiness. First of all, I wanted to use reference counting everywhere. The model used in Woopsi, in which the framework tries to own everything, is efficient for the CPU but eventually results in some really nasty problems for the programmer. I still have no idea who owns a Woopsi font object.

SZLib

Reference counting is very easy to implement (it is the way I implemented it, anyway). Start off with a basic object that looks something like this:

typedef struct __SZObject {
    unsigned int refCount;
} SZObject;

Next, add a few functions to create/retain/release them:

SZObject *SZObjectCreate() {
    SZObject *ref = malloc(sizeof(SZObject));
    ref->refCount = 1;

    return ref;
}

void SZObjectRetain(void *ref) {
    SZObject *object = (SZObject *)ref;
    ++object->refCount;
}

void SZObjectRelease(void *ref) {
    SZObject *object = (SZObject *)ref;
    assert(object->refCount > 0);

    --object->refCount;

    if (object->refCount == 0) {
        free(object);
    }
}

It’s easy to embed reference counts into any object by taking advantage of a feature of C’s layout of structs in memory:

typedef struct __SZThing {
    SZObject object;
    char *data;
} SZThing;

I can cast a variable of type SZThing* to an SZObject* and treat it as though the former is an instance of the latter. The SZThing struct has all of the properties of the SZObject since the first field in the struct is an SZObject. Neat.

There’s a little more to it than this, of course. If the constructor function for the SZThing object mallocs its data property, then the release function needs to free that memory. This is all done with a callback struct that looks something like this:

typedef struct __SZObjectCallbacks {
    int (*equals)(const void *, const void *);
    int (*compare)(const void *, const void *);
    unsigned long (*hash)(const void *);
    void *(*copy)(const void*);
    void (*dealloc)(void *);
} SZObjectCallbacks;

Whenever an object includes an SZObject in its struct it is expected to create and populate one of these structs. The function pointers are called at the appropriate times if they are not NULL (dealloc is called by the SZObjectRelease() function, for example) and this sets us up for a bunch of exciting functionality: copying, comparisons, and hashing, in addition to worry-free memory management (not thought-free; there’s still a requirement to retain and release, but there’s no agonising over whether a given piece of code should free a block of memory or not).

With reference counting in place, the next thing to do is write a bunch of collection classes that take advantage of this functionality. I call them “classes”, even though C doesn’t support classes, because the idea is similar: a group of associated data that can only be accessed via a well-defined set of functions. Achieving this requires “opaque types”, which are basically structs with hidden definitions. An opaque type is created by adding a typedef to a header file and a struct definition to a .c file. Here’s a snippet of the header file:

typedef struct __SZHashMap *SZHashMapRef;

int SZHashMapCount(SZHashMapRef hashmap);

Here’s part of the .c file:

typedef struct __SZHashMap {
   SZObject object;
   void **data;
   int size;
   int reservedSize;
 SZHashMap;

int SZHashMapCount(SZHashMapRef hashmap) {
    return hashmap->size;
}

It seems to me to be extremely counter-intuitive that the compiler doesn’t go nuts when it encounters a typedef for something that doesn’t exist yet, but it works. The code to create and use one of these hashmaps looks like this:

SZHashMapRef hashmap = SZHashMapCreate();
printf("%d", SZHashMapCount(hashmap));
SZObjectRelease(hashmap);

Outside of the hashmap’s .c file there’s no way to create a plain SZHashMap struct or poke at its internals (short of looking through the raw bytes in RAM).

Other than a hashmap (which I didn’t need to use) the base library includes a bunch of other things I didn’t really need or use: a set (which is currently backed by a binary tree that can quickly become unbalanced, so it needs to be replaced with a self-balancing tree structure), a linked list, an autorelease pool, a number wrapper (like a boxed int/float/double in Java), a value wrapper (slightly more versatile than a number) and a data wrapper (wraps a byte array; essentially just a very versatile value). Things I wrote and then did use were a string (ASCII only), a range (a struct containing a start and a length) and an array.

SZGeometry

Once the core library was done I could move onto slightly more interesting things: a geometry library. This is mostly based on WoopsiGfx, and includes code for managing points, sizes, rects, lines and circles.

The most interesting features are the circle and line point enumerator functions. In modern languages with new-fangled features like closures it would be possible to do something like this:

SZRect rect = SZRectMake(0, 0, 10, 10);
[SZCircle enumeratePointsInRect:rect block:^(SZPoint point) {
    // Do stuff with point here
}];

In C that’s not possible, so we’re forced to use function pointers and a context object to simulate closures instead:

void enumerate() {}
    SZRect rect = SZRectMake(0, 0, 10, 10);
    SZCircleEnumeratePoints(rect, NULL, __callback);
}

void __callback(const void *context, SZPoint point) {
    // Do stuff with point here
}

It achieves the same thing, but it’s less elegant. Closures are probably the feature I’ve missed most when coding C. In either case, we’ve split up enumerating the points of a circle from rendering the circle (in WoopsiGfx they were part of the same operation), so we can do more interesting things with the circle’s description now.

SZGraphics

With the geometry library in place, we can add a graphics library. Again, this is all back-ported from the C++ WoopsiGfx library (with the occasional bugfix). It includes a few different types of bitmap, a font class, and a graphics class for drawing to those bitmaps.

Achieving different types of bitmap without inheritance was tricky. The library uses a kind of base class that all of the other bitmaps include as the first field in their structs:

typedef struct __SZBitmap {
    SZObject object;
    SZSize size;
    SZBitmapCallbacks callbacks;
} SZBitmap;

typedef struct __SZMutableBitmapWithInternalBuffer {
    SZBitmap object;
    SZColor *bitmap __attribute__ ((aligned (4)));
} SZMutableBitmapWithInternalBuffer;

We’re starting to nest structs: the mutable bitmap contains a bitmap, and the bitmap contains an SZObject. I can therefore treat a mutable bitmap as a bitmap and as an SZObject and get all of the functionality of the combined set of 3 objects.

A very truncated version of the SZBitmapCallbacks struct looks like this:

typedef struct __SZBitmapCallbacks {
    SZColor (*pixelAtCoordinates)(SZBitmapRef, SZPoint);
} SZBitmapCallbacks;

Meanwhile, SZBitmap offers a function that does this:

SZColor SZBitmapPixelAtCoordinates(SZBitmapRef bitmap, SZPoint point) {
    return bitmap->callbacks.pixelAtCoordinates(bitmap, point);
}

Therefore, all a “subclass” of SZBitmap has to do is fill out its SZBitmap’s callback struct and, even if it has some wildly crazy internal representation of a bitmap, it can be treated like any other SZBitmap. All of the standard functions will work.

Making this subclassing scheme possible means working around the opaque types idea, unfortuntely, since each subclass needs to include an SZBitmap (the struct, not a pointer to a struct) in its own struct. I got around this by moving the struct definition to a “private” header file (you can tell it’s supposed to be private; its filename is suffixed with “_private”).

Fonts are based on Jeff Laing’s monochrome packed fonts from Woopsi, with one significant change. Rather than the SZFont being responsible for rendering itself to a bitmap, the font has a function for testing if the point at a given set of co-ordinates within a character glyph is set (1) or unset (0). The graphics class uses that information to render to a bitmap. This way all of the rendering logic is in one place and there’s no coupling between SZFont and SZBitmap. I haven’t bothered with multiple types of font or unicode because they’re two more things I won’t use.

The final piece of the graphics library is the class that does all of the drawing work. It includes the usual set of drawing functions: lines, text, rectangles, circles, flood fill, etc. The API is a vast improvement over WoopsiGfx because it takes advantage of all of the available primitives created in the lower-level libraries like rects and points, greatly reducing the number of arguments passed to each function. All of the functions accept a graphics context struct that includes a bitmap to draw to and a clipping rect, meaning all of the drawing functions are clipped. The clipping code is much saner in the new library.

SZHAL

The last library is a hardware abstraction library. It includes a framebuffer class, a couple of functions for doing DMA-boosted memset() and memfill(), and code for interacting with the stylus, buttons, vblanks, and hardware setup and teardown. The library uses #ifdefs to switch between DS and SDL implementations where necessary. I started abstracting out the DS’ sprite system but quickly abandoned it when I realized how awkward it would be to get the graphics working in SDL.

The Game

The downside to completely ignoring the capabilities of the DS hardware and doing all of the graphics work with just the CPU and a framebuffer is that it is insanely expensive. Early on it looked like HankyAlien wouldn’t work because drawing all of the aliens at 60fps wasn’t possible. Then I realised that the original game moved one alien at a time, so I’d only ever need to draw one alien at once.

Although the game’s background is black, in theory it would be trivial to drop a background image in with no meaningful drop in performance. Every time a sprite is drawn to the screen the game pushes a rect that describes the sprite onto a dirty rects array. Each time the game iterates it erases all of the dirty rects and flushes out the array. To get a background working, we’d just need to perform a bitmap copy for that rect from the background image to the framebuffer instead of drawing a black rect.

The code was starting to get a little unwieldy and I found myself wishing that I could somehow implement the delegate pattern to tidy it up. After some thought, I figured out that delegates are very easy to implement in C. First of all we have to define a delegate struct:

typedef struct __SZGameSpriteDelegate {
    void *delegate;
    void (*spriteDidFinishExploding)(void *, SZGameSpriteRef);
} SZGameSpriteDelegate;

We can create one of these structs like so:

SZGameSpriteDelegate delegate;
delegate.delegate = game;
delegate.spriteDidFinishExploding = __SZGameSpriteDidFinishExploding;

In this snippet, __SZGameSpriteDidFinishExploding is a static function within the SZGame class that we want to call when the sprite explosion animation ends. The game variable is a pointer to the SZGame instance that wants to receive the callback. We call it like this:

void SZGameSpriteFinishExploding(SZGameSpriteRef sprite) {
    if (sprite->delegate.delegate && sprite->delegate.spriteDidFinishExploding) {
        sprite->delegate.spriteDidFinishExploding(sprite->delegate.delegate, sprite);
    }
}

The function in SZGame looks like this:

static void __SZGameSpriteDidFinishExploding(void *game, SZGameSpriteRef sprite) {
    SZGameRef gameRef = (SZGameRef)game;

    // Do stuff with gameRef
}

Therefore, the SZGameSpriteDelegate struct holds two pieces of information: the object that wants to respond to callbacks, which we pass as the first argument to the callback functions, and the set of optional functions that the delegate can respond to.

The shields are only drawn once per game. The game maintains a bitmap representation of each shield and does two-stage collision detection with other sprites: do the sprites intersect, and if so, do any pixels overlap? If there’s a collision it erases the other sprite’s rect from the shield bitmap. We erase the other sprite from the screen and the two representations are therefore kept in sync.

2014-01-26

Sparky 1.0 - A New DS Game

A new Nintendo DS game!

Sparky

This is a little version of the hacking subgame from the original Bioshock game. I started it waaay back in 2010 but got sick of trying to imitate the pipe filling graphics using nothing but Woopsi’s drawing primitives. The completed version uses a spark that travels along a line instead. Much easier to code.

I’d intended to improve on the original by only producing levels that were possible to complete. However, the recursive algorithm I wrote didn’t like the DS (probably a stack overflow issue) so that feature didn’t make the cut.

2013-06-21

Super Foul Egg for iPad Released

Finally, after months of procrastination:

This one got straight into the App Store.

Obvious changes from the OSX version are:

  • Two player mode removed (still got a bug in the garbage transmission code);
  • Controls designed for the iPad touch screen;
  • Controls displayed via icons on the menu screens;
  • Pause and exit buttons whist in-game.

Less obvious changes are:

  • Multithreaded AI;
  • All code refactored.

I’ll open up the source code soon.

Give the game a try and let me know what you think!

EDIT:

Source code can be found here:

Apologies for its current scrappiness; adding networking support has meant changes all over the place. I remember reading an article years ago by a developer who suggested that networking should be built into a game from the start rather than added later as it’s a huge pain. I definitely agree with him.

2012-08-21

Super Foul Egg In The App Store

Super Foul Egg is now available from the Mac App Store!

This version includes the final menu screen, allowing players to choose the number of egg colours in a game, the drop speed, the starting number of garbage egg rows, and best of 3, 5 and 7 games. It also includes a “Controls” menu item that opens a window that shows the keyboard controls and a new icon.

It’s free, so give it a try!

The current version has one known bug. The text in the menu screens doesn’t render properly on retina Macs; it’s a known problem with Cocos2d’s TTF support. I’ve fixed this in the BitBucket repository by switching to a BMFont instead of TrueType, so I hope to get a new version up soon.

Now that’s out of the way I can write the usual grumble about the process of getting software into the App Store. My iMac refused to codesign the binary so I couldn’t release it on that machine. It kept insisting that there weren’t enough teams (or some similarly meaningless error). It was right - my provisioning profiles in the Xcode Organiser had “Unknown” listed as their team. Trying to refresh via the Organiser didn’t work. I eventually discovered that the way to fix the problem was to delete absolutely everything from the “login” keychain and refresh in the organiser, but not before I’d spent two hours fighting with the damned thing and switched to my MacBook instead.

On the MacBook, I discovered that I had too many teams. My last employer didn’t get around to revoking my access to their iOS developer team. I removed myself, but it seems that removing access doesn’t remove me from the team. I apparently have to contact Apple to do that, which I assume is because Apple love their developers so much they want to interact with them whenever possible. It’s not that they hate their developers and can’t be bothered to make a UI for that function.

In total, giving Apple $99 for the developer licence probably took about 10 minutes. Getting codesigning to work took about 3 hours. The approval process took exactly 2 weeks. Going from “ready for sale” status to appearing in app store searches took 6 hours.