08 Feb 2014

It’s been a while since the last update, but fortunately that doesn’t mean I haven’t made any progress. Over the last 2 weeks I’ve tried to spend an hour or so every now and then, setting up some skeleton classes based on the preliminary data model introduced in the previous post.

As expected, I ran into some oversights and deficiencies of this first attempt at a data model, so I made some adjustments and got a relatively clean set of skeleton classes representing the game world (which I decided to refer to as ‘planet’ from now on), and the various entities (actors only, at this point) of the game. I concentrated only on the data model class methods concerned with constructing and initializing a planet, and populating it with the first batch of actors, which I decided to limit to the player ship, fuel pods, turrets and the nuclear reactor present on each planet.

My primary goal at this point is to get to a more-or-less minimal API that allows setting up the first planet of the original game excluding the orb (which I think will be a static entity that may need some special treatment), including any necessary Box2D setup required to start stepping through the physics simulation. Right now, I guesstimate that I’m about halfway to this goal. Before I get into specifics, let’s first have a look at what this fabled ‘planet 0’ looks like.

Planet 0

As you can see, planet 0 is kind of boring, which makes it a perfect environment for our experiments. There’s a simple, easy to replicate surface, exactly one of each of the initial set of actor entities, and no switches or traps.

First thing I did before writing any code was to install a Commodore 64 emulator and find a tape image of the game. Yes, I’m aware using copyrighted ROMS is considered illegal by some, but this is all in the name of science, not to actually play the game for free. I used to own a legal copy of the game years ago anyway and don’t remember selling, donating or throwing away the tape, so I’m taking my chances. The emulator I used is Vice, which has proved excellent so far and runs natively on OS X.

Using Vice, I took screenshots of the first planet and stitched them together to get the above image, which is not only useful to pad out this post and break the wall of text, but also as a frame of reference for the relative sizes and distances of the planet itself, and all the stuff it contains. It seemed like a good idea to decide on a coordinate system for the game world pretty early on in the process, so I took the planet 0 overview image above and made a quick sketch containing the relevant distances. As I didn’t want to make an exact science out of it, I just picked the fuel pod as a reference point, for the simple fact that it is almost perfectly square, and because it’s dimensions seemed roughly equal to the smallest dimension observed for any of the other planet entities. It seemed only natural to make the fuel pod 1 by 1, leaving it to the imagination whether that would be 1 by 1 meters, yards, inches, or double-decker buses. Using our newfound dimensional anchor I sketched a back-of-the-envelope (literally) ‘blueprint’ containing the distances along the planet surface:

Data model changes

As I mentioned earlier, the moment I created an XCode project and started writing the first few data model classes, I ran into bad design decisions I made to get to the preliminary data model. Turns out my impression that drawing-board design without actual code rarely works well, has proven true yet again.

First of all, I decided to rename the K14World class to K14Planet. Not only does this look and sound a lot more interesting (planets are cool), but it also makes it easier to separate ‘planet’ as in ‘level of the game’ from ‘world’ as in ‘what Box2D uses to refer to the physics simulation environment’ when talking about these things.

The next thing I didn’t really think through very well was the construction and life-cycle management of game entities. Eventually, the main game loop will update entities through the K14Planet class, which means it should have some kind of repository of active entities, and provide functionality to add, remove, retrieve and uniquely identify them. This screams for a factory pattern, where entities are always created through a factory method on K14Planet. So I removed the addEntity method from the K14Planet class, and replaced it by a createEntity method that takes a string-type class name. Based on this class name, K14Planet will determine the actual class type of the entity to create, generate a unique identifier for it, instantiate the entity class, and register the resulting instance by adding it to an internal dictionary of active entities. For now, the entity class name is simply chosen to be the same as the name of the actual class representing the entity type, but I implemented the factory method using a table to allow more flexible class names later, which may prove useful if something along the lines of a K14ScriptableEntity is ever implemented. Imagine creating an entity using a classname of K14ScriptableEntity.Turret, for example. The K14Planet class will be fully responsible for life-cycle management of entities, so it will still need to a removeEntity method or something similar that safely removes the entity from the Box2D world and destroys the entity instance, but I haven’t implemented this yet.

Another oversight was entity setup itself. As one of the design goals for the game is full scriptability of entities, any kind of entity setup should be exposed through our own (scriptable) interfaces, not hard-coded inside (for example) the K14Entity class or requiring direct calls into Box2D. In particular, this applies to setting up Box2D bodies, and adding fixtures of various shapes to it. Remember that fixtures define the shape, mass, joint attachment points, etc of the (possibly multiple) parts of entity bodies. The entity body itself is basically ethereal without fixtures, so to say. Not only should a K14ScriptableActor some day be able to setup a body with multiple fixtures of various shapes and densities, it should also be able to manipulate fixture properties after the entity has been created, using a scriptable interface. Think changing the density of a particular fixture of an entity for example, or removing a fixture based on some kind of condition. To realize this, I introduced simple wrapper classes for the Box2D concepts of ‘fixture’ and ‘shape’ (shape is basically a property of a fixture), called (unsurprisingly) K14Fixture and K14FixtureShape (the latter isn’t actually a class by the way, but a protocol implemented by classes such as K14BoxShape, which is more Objective-C-ish than using an abstract base class with concrete subclasses). Analogous to how an entity is created through a factory method on K14Planet, fixtures are added to entities through a factory method createFixture on K14Entity, which takes a K14FixtureShape, a name for the fixture, and the fixture density as parameters. Note that the size of the shape combined with the density value determines the mass of the fixture, and the mass of all entity fixtures combined determines the total mass of the entity. Later on, it should be possible to retrieve, and remove entity fixtures through methods on K14Entity.

One other minor change I made is related to the way the planet surface is passed to the K14Planet constructor. Instead of allowing a list of edge-lists, I simplified the interface to only accept a single, contiguous edge list. I also imposed some restrictions this edge list has to adhere to: the vertices of the first and last point should have the minimum and maximum x-coordinate of any vertex in the edge list, respectively, and the y-coordinate of the first and last vertex should be the same. These two restrictions ensure the surface runs left-to-right and can be ‘stitched’ at its endpoints to make the planet ‘wrap around’ like it does in the original game. Both restrictions are checked in the K14Planet constructor and violating them will throw an assertion. Some time in the future it may be necessary to define a flexible interface to setup planet geometry, allowing more complex planet shapes, but as far as I can tell it should be possible to define any level of the original game using the current definition, so let’s keep it simple for now.

Here’s a quick detail-view of the current state of the planet-, and entity-related classes, including only those bits that are actually already implemented. Eventually I will integrate these in the larger data model, when development progressed a little further and the design has stabilized a bit.

Current project state

At this point in time ‘2k14: The Game’ consists of an XCode project containing a few skeleton classes representing the game world (K14Planet) and the entities I mentioned earlier. The skeleton classes expose factory methods to create entities and fixtures, and implement a few basic entity properties such as position, angle, etc. Most of these properties map to the Box2D body and fixture objects backing the entity classes, which are already created and added to the Box2D world. The Box2D world itself is created from the K14Planet constructor, and initialized with edge shapes representing the planet surface. There is no game loop, and no step methods on K14Planet or K14Entity yet, so even though it’s already possible to setup a planet, create entities and add fixtures to them, everything already backed by Box2D objects, there is no way to actually run the Box2D simulation yet.

In the following days I will add whatever is needed to be able to create and populate planet 0. The plan is to present some code snippets to illustrate how the planet setup works, taken from actual, working code.

Development time scoreboard

Now that I’ve started to write some actual code, I’m going to try to keep track of the amount of time spent in XCode, or at least a rough estimate of it. Setting up the initial XCode project and writing the skeleton classes took me about 4 hours total up to now, one hour of which was spent dicking around the build settings to get Box2D compiled into my project, and renaming/moving stuff in the directory structure XCode creates by default when you set up a new project (no, I don’t want directory names that have spaces and colons in my project directory). After the project was set up and I started to add classes according to my initial data model, I ran into all these bad design decisions I elaborated on in this post, which meant I had to start refactoring before I even had any working code. Hopefully things will be smoother from now on ;-)