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

PSP Surprise

I’ve mentioned before that SZLib presents challenges:

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.

However, its bare-bones approach - it just needs a framebuffer and a way to read a joystick, pretty much - made getting it working on the Dreamcast fairly trivial. Getting it working on other platforms should be simple too, but when choosing a new platform for the library I eliminated everything but the Dreamcast as a potential target.

I was too hasty when I crossed the PSP off that list. The handheld does offer the ability to write directly to the framebuffer. It took about an hour or so to get to this point:

ChuckieEggPSP

By far the hardest part was getting MikMod set up to play sound effects, which took a couple of hours on its own.

There’s a little bit of work to do. The PSP has a physical screen size of 480x272, but for some reason it seems that the frame buffer is 512 pixels wide. The disconnect between the physical and logical sizes means everything is slightly off-center. Also, the “home” button isn’t wired up yet. Overall, though, the game works just as well on the PSP as it doesn on the Dreamcast and NDS.

Excitingly, because they’re based on the same libraries, HankyAlien also now runs on the PSP.

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.

2016-10-05

Hanky Alien Refactored

I’ve been toying with the idea of writing another homebrew DS game using the libraries I developed for Hanky Alien. Unfortunately the existing code has one considerable flaw: the game logic is intimately entwined with the rendering system, to the point that writing a new game unavoidably involves rewriting a bunch of graphics code that really should have been separate.

To fix this I’ve pulled apart Hanky Alien and reassembled it into three distinct pieces:

  • A layering library that handles all of the rect stuff I insist on using instead of just writing a sprite simulator for SDL like any sensible person;
  • An MVC GUI framework with the components necessary to get the game running (view hierarchy, controllers, timers, label views, bitmap views, event-based stylus and button handling, transitions, etc);
  • The game itself.

The game logic is currently included in the same build target as its presentation layer, but those can be trivially separated once I get around to it.

The new structure has a multitude of benefits. In order to place text on the screen, the code no longer needs to figure out where the text will go, figure out if it needs to erase what was previously at those co-ordinates, and then render the text; it just updates the string in a label view and lets the underlying libraries do all of the hard work. There’s a complete separation between the game logic and all I/O. Timer events piped down from the controller kick the game’s update logic, and game events (such as movement, or the addition or removal of objects within the game) are sent up to the controller via delegate callbacks. The controller is responsible for creating, moving, updating and removing views. I can change the game logic without having to think about any rendering. Each scene in the game - the “Simian Zombie” scene, the title scene, and the game scene itself - are all separate controllers. The GUI framework handles animating the transition from one controller to the next, which means a bunch of complex custom state machine logic became redundant. On top of that, the whole shebang is written in pure C.

All of this structure came with a horrible cost, however. Performance was nowhere near acceptable.

One huge benefit of manually managing the layout and redraw of the screen means each situation can be as efficient as possible. A generic approach to updating the framebuffer means there’s no opportunity for taking shortcuts that make sense in one place but would break other code. This forced me to dig through the entire codebase and try to optimize everything.

First step: profiling with Instruments. Hanky Alien builds happily using SDL2, so I can profile it on my Mac. It doesn’t necessarily give me accurate information, obviously; the Mac and DS have wildly different architectures and capabilities. It does give me a starting point, though.

One mistake that quickly became apparent was the amount of boxing and unboxing of rect structs that the layering library was performing. Subtracting one rectangle from another produces an array of leftover rectangles, and those were returned in an array. The array provided by the core library would only store objects, so I’d opted for the naive approach of boxing the leftover rect structs into value objects and sticking those in an array. Unfortunately each boxing operation required a malloc(), and any attempt at using the data in the objects required them to be unboxed back into structs first. The fix for this was easy: create a new array class specifically for storing collections of rect structs. As long as a resize isn’t required - which inevitably demands a realloc() call - appending rects involves nothing more than changing an int and copying a struct.

Creating those arrays was also slow, particularly when multiple rectangles are divided in a tight loop. The code used to look something like this:

for (int i = 0; i < SZRectArrayLength(rectsToDivide); ++i) {
    SZRect r = SZRectArrayRectAtIndex(rectsToDivide, i);
    SZRectArrayRef a = SZRectCreateArrayBySubtractingRect(rect, r);

    // Do stuff with a

    SZRectArrayRelease(a);
}

It now looks like this:

static SZRectArrayRef a = NULL;

if (!a) {
    a = SZRectArrayCreate();
}

for (int i = 0; i < SZRectArrayLength(rectsToDivide); ++i) {
    SZRect r = SZRectArrayRectAtIndex(rectsToDivide, i);
    SZRectSubtractRectAndPopulateArray(rect, r, a);

    // Do stuff with a

    SZRectArrayRemoveAll(a);
}

The “remove all” function just sets the array’s size property to 0. We create a single static array and re-use it in each call of the function and each iteration of the loop. We can get away with this because all of the code is single-threaded.

I’ve been unrolling loops. The code above does a bunch of work in the loop that we could unroll. We can move the variable declarations out of the loop and stop querying the array length on each iteration:

int rectCount = SZRectArrayLength(rectsToDivide);
SZRect r;

for (int i = 0; i < rectCount; ++i) {
    r = SZRectArrayRectAtIndex(rectsToDivide, i);
    SZRectSubtractRectAndPopulateArray(rect, r, a);

    // Do stuff with a

    SZRectArrayRemoveAll(a);
}

We’re passing structs around by value; we should probably stop doing that too:

for (int i = 0; i < rectCount; ++i) {
    r = SZRectArrayRectAtIndex(rectsToDivide, i);
    SZRectSubtractRectAndPopulateArray(&rect, &r, a);

    // Do stuff with a

    SZRectArrayRemoveAll(a);
}

The game logic itself had some inefficiencies. Something I’d annotated with a “todo” in the original game was the alien collision code. In order to check if the player’s bullets were colliding with an alien, the code looped over all aliens in the game. The new version treats each column of aliens as a unit and checks collisions with those before checking against the aliens themselves.

The code uses a huge number of rect calculations, so those needed to be as fast as possible. All of the functions had code to cater for rects with a negative width or height. That would never possible with the data coming out of the various libraries, so I added a bunch of “fast” versions that didn’t do any sanity checking.

The rendering code now uses Cearn’s ARM assembly copy functions for blitting stuff to the framebuffer.

The code is much, much faster than it used to be, but it’s not enough to throw around as many bullets as the older version.

Some of the exciting failures were:

  • Flattening the view hierarchy into a single view and manually handling a bunch of the redrawing logic. Initially it seemed like this would lead to a massive speed boost, but as the redrawing code got more and more complex the game got slower and slower.
  • Replacing bitmaps with solid blocks of color to see if the DMA would help.
  • Using quadtrees to help partition the space and reduce the amount of collision detection being done.
  • Creating my own profiler to record the execution time of various functions.

My final idea was to ditch the DS completely and switch platforms to something with more CPU power. Requirements for the new platform:

  • Must be a console or handheld (rules out anything with a keyboard or without a joypad).
  • An easily-installed homebrew dev kit with great C support (rules out pretty much everything prior to 32 bit).
  • A faster CPU than the DS’ 66MHz ARM9 (no GBA).
  • No fighting firmware upgrades (so long, Vita/3DS/Wii U).
  • Well-designed input devices (no GPH devices).
  • Must be easy to test on the real device.
  • Must have a reasonably capable OSX emulator.

By my estimation, that leaves three potential devices: the PSP, the Wii, and the Dreamcast. I’ve had a look at the dev kits for the PSP and Wii and neither one really seemed to fit with the archaic software rendering that I’m trying to do. The Dreamcast, though, appears to have a wonderfully simplistic framebuffer graphics mode and even supports DS-style RGB555-encoded pixel data. It could use some more homebrew.

One trip to Amazon later and a new (old) NTSC Dreamcast is winging its way to me! After a few evenings of tinkering I managed to get this running in lxdream:

HankyAlien-Dreamcast

Unfortunately, despite the Dreamcast being fantastically more capable on paper (200MHz CPU, 16MB RAM, 8MB VRAM vs the DS’ 66MHz CPU, 4MB RAM and 656KB VRAM), it turns out that in terms of raw CPU performance there’s not a whole lot between them. On a more positive note, programming the Dreamcast looks like it’ll be fun, so once this refactoring project is complete I think I’ll try writing something exclusively for it.

2016-07-24

AGB-101

I need to stop collecting these.

AGB-101

The purple and black GBAs came from eBay, while the yellow version (it looks orange in the photo, but it’s really banana yellow) is from Retro Modding. Like GB modders Deadpan Robot (formerly Gameboy Mods), Retro Modding take used GBAs and refurbish them with a variety of third-party shells and enhancements.

I was very pleased with Retro Modding. In addition to providing great service and doing an excellent job of modifying the GBA - for considerably less than the current prices on eBay - they threw in a neat case and a bunch of stickers.

Aspiring backlit GBA owners should note that a triwing screwdriver may turn out to be an essential purchase. Two of these three handhelds have required adjustments to the voltage potentiometer inside the console in order to fix graphical glitches on the screen. The purple unit displayed flickering colors, whilst the yellow unit was noticably interlaced. There’s a video here that demonstrates where to insert a screwdriver if you don’t mind poking a hole in the sticker on the back of the device, but a triwing screwdriver will allow you to open it up and avoid the hole.

The approach that’s worked best for me is to make small adjustments of around a quarter-turn, testing out the console with each change. It’s a little laborious, as each test requires reassembling the console enough to be able to re-insert the cartridge and batteries, but I’ve seen numerous (unsubstantiated) reports that turning it too far can damage the screen. The purple unit was particularly troublesome to get right because it would work well for a day or so before the flickering re-appeared.

2016-01-13

Collecting GameBoys

In addition to making new homebrew for the DS, I’ve been indulging my passion for all things handheld and retro by amassing a collection of original, refurbished, modded and cloned GameBoys.

I started out with a K1-GBA. This is a GameBoy Advance hardware clone (rather than a software emulation like most GBA knockoffs) that purports to be an almost exact replica:

K1-GBA

It’s a neat little handheld but the buttons are a little stiff and unresponsive, the screen is nothing like the GBA’s (wrong resolution so everything is upscaled) and the battery life isn’t great. On the other hand, it comes with a flash cart (that only works on this device) and the screen is backlit, so it represents a considerable improvement over Nintendo’s own hardware. I’ve found that I can’t use it for very long because the combination of the diminutive SP design and the unresponsive buttons makes my hands ache.

Wanting something a little bit more official, but not something whose condition reflected its age, I got hold of a GameBoy Color from Monster Arcade. They refurbish second-hand handhelds using 3rd-party replacement cases, screen lenses, buttons and button mats to make them look and feel like new:

Monster Arcade GBC

For comparison, here’s the GBC I bought back when they were first released. Note that it is still in its original box from when I bought it back in the late 1990s; this will be important later.

Original GBC

The refurbished model is pretty much indistinguishable from the original. The plastic doesn’t have quite the same feel and the buttons are a little spongier, but unless you play the two side-by-side you’d never know there was any difference (now that I’m looking at the two together, though, it’s obvious that the logo on the refurb’s screen lens is spaced all wrong). It’s close enough that I bought one of their GBAs soon after:

Monster Arcade GBA

I don’t know how close this GBA is to an original, as I have temporarily mislaid mine. However, the controls are a little spongier than the spongy controls on the refurbished GBC.

At this point, let’s talk about why my GBC (and indeed my original GBA) are still in mint condition in their original boxes: those dreadful, dreadful screens. For whatever reason - battery life, weight, heat, cost - Nintendo decided against frontlights and backlights in the GBC and original GBA and used reflective screens instead. It’s hard to tell from the images here, but under anything but ideal lighting conditions those screens are impossible to see. My GBC and GBA are still in mint condition because they’re pretty much unusable.

Clearly unlit handhelds were a bad idea, so I turned to GameboyMods. They provide much the same products as Monster Arcade - second-hand hardware refurbished with new parts - except that they only sell original GameBoys, and they fit them with a range of modifications: backlights in a range of colors, bivert mods (in which the display is inverted electronically, and then inverted again via a polarizing filter, in order to provide better contrast when lit), and fixes to the sound hardware. This is mine:

GameboyMods GB

I wanted the original lens but ended up with something different, unfortunately, but the light is fantastic. I haven’t noticed any drop in battery life from my original GameBoy (DMG) and it’s usable in any lighting conditions. The polarizing filter over the screen has a habit of wrinkling in one corner when the unit warms up, but otherwise it’s a great handheld.

For comparison purposes, this is my original DMG:

Original GB

The backlight in the DMG was such a vast improvement over the original that I was inspired to get a frontlit GBC from 8bitAesthetics:

8bitAesthetics GBC

Take a GBC from Monster Arcade, paint it to look like a DMG and stick a frontlight in it and you’ve got one of these. There’s a whole subculture of GameBoy modders creating custom handhelds like this.

I saw it on their website and couldn’t resist it, but it has a few flaws. I’m a little concerned about how resilient the paint is (there’s already a patch by the link port that’s flaked off and I haven’t done much more with it than switch it on and check that it works); it smells weird due to the paint; and the frontlight washes out the screen and really highlights its low pixel density. It’s nice to have a GBC with a visible screen, and this is definitely the most unique GameBoy in my collection, but it’s probably the one I like least. Perhaps I’m just a Nintendo purist.

I ended up with one of these after seeing it on a website filled with dodgy Chinese console clones:

GB Boy Colour

This is a “GB Boy Colour”, or an imperfect GBC clone. It’s imperfect in just about every way. The d-pad is hideous, the buttons are big and chunky, the screen’s viewing angle is abysmal and it’s the wrong shape, the cartridge port is stiff, the power LED is in exactly the wrong place, the sound is all wrong and the thing that looks like the IR sensor is really just a piece of colored plastic, but it only costs $20 and the screen is backlit. Clearly a vast improvement over an original Nintendo console.

The last GameBoy I bought was this from customers1stgaming on eBay:

customers1stgaming GBA

Now this one is gorgeous. Take a refurbished GBA like those produced by Monster Arcade, replace the screen with one taken from an AGS-101 (backlit GBA-SP) and add a glass screen lens. Again, slightly spongy controls, but the screen is incredible. Unlike the SP that was sacrificed in its creation, it wasn’t designed for tiny child hands. This is the console Nintendo should have released 25 years ago. There are plenty of these on eBay at the moment from numerous sellers, but as the mod kits have dried up it’s possible that backlit GBAs will become harder to get hold of.

Phew, that’s a lot of consoles. So which ones offer the most enjoyable handheld Nintendo experience? The backlit GBA is by far the best option: nicely refurbished with an amazing screen. The backlit DMG is a close runner-up: it retains the classic design but makes the screen visible, and the range of possible customizations make it easy to create something unique. Of the others, the K1’s screen is too dissimilar to the original, the GB Boy Colour is a distorted, nightmare GBC, and it’s impossible for me to recommend anything without a backlight having used the backlit versions. As for the frontlit GBC, it’s beautifully done but possibly more of an art piece than a practical gaming device.

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.