Sprites

09 Nov 2014

Time for another update. It’s starting to become a recurring theme, but progress has been slow again. Besides a full-time job and a social life, I’ve recently started taking Japanese classes, which means I don’t spend a whole lot of time behind a computer when at home these days. Nevertheless, I managed to put together a very simple framework for sprite-based rendering of entities together.

Sprite rendering

I made a conscious decision not to use an already-existing sprite-based framework such as SpriteKit or Cocos2D, and instead write everything related to rendering from scratch. The main reason for this decision is that DIY is more fun, but it also means I can keep things as concise and simple as possible.

To render game entities using sprites, I first created a simple sprite atlas class, K14SpriteAtlas. A sprite atlas represents a set of sprite frames as a single image, somewhat like a collage of sprite frame images. A texture is created from the atlas image, and when rendering an entity, it can change its sprite frame by just using different texture coordinates into the atlas image, instead of having to create a single texture for every sprite frame and binding it on every draw call.

The sprite atlas class is simple but effective: it’s created with a frame size and a number of rows and columns of frames, and on construction it will allocate a bitmap context large enough to accomodate the requested number of sprite frames. Sprite frames can then be added to the atlas using a string-type key, and a UIImage containing the frame image, which is pasted into the bitmap context using UIImage drawInRect.

I chose to use one sprite atlas for each entity type, which is initialized and uploaded to the GPU by the renderer before the game loop is started. A static singleton property spriteFrameImages was added to K14Entity and its descendants, which returns a dictionary from sprite frame names to UIImage instances, which are loaded from PNG files in the application bundle the first time the property is accessed. To limit creating texture atlases to only those entities that a are actually used by the active planet, a property usedEntityClasses was added to K14Planet, which returns the class names of all used entity types.

The code inside the renderer class that sets up the atlas images for all entity types used on the active planet looks like this:

_spriteTextures = [NSMutableDictionary new];
_spriteTextureAtlases = [NSMutableDictionary new];

// Create texture atlases for used entity types
for (NSString *entityClass in planet.usedEntityClasses)
{
  Class cls = NSClassFromString(entityClass);
  
  K14SpriteAtlas *sprite_atlas = [[K14SpriteAtlas alloc] initWithRows:4 columns:4 frameWidth:128 frameHeight:128];
  
  for (NSString *frame_name in [cls spriteFrameImages])
  {
    [sprite_atlas addSpriteFrameWithName:frame_name image:sprite_frames[frame_name]];
  }
  
  _spriteTextureAtlases[entityClass] = sprite_atlas;
  
  _spriteTextures[entityClass] = [GLKTextureLoader textureWithCGImage:sprite_atlas.image.CGImage
                                                              options:@{ GLKTextureLoaderApplyPremultiplication : @(YES) } 
                                                                error:nil];
}

Result

To test sprite rendering I cobbled together some vector drawings for the entities of the test planet. I used Sketch 3 by Bohemian Coding, which isn’t cheap but makes it so easy to create vector drawings like this, that it’s easily worth the investment. Here’s a video of the test planet using sprite rendering for entities:

Note that I made no effort whatsoever to make the sprites look good yet, they are all single-colored and their proportions are a little off compared to the original game. None of the sprites are animated yet either, but the supporting code to animate them is all there: animating a sprite is just a matter of creating the necessary sprite frames and swapping them by setting the entity sprite frame name when necessary.

Next steps

I’m not quite sure what feature I want to add next, most likely it will be one of the following: a simple main menu and scene transitions to allow getting in and out of different planets, or hooking up input handling to actual working controls (on-screen or accelerometer) so the game can be ‘played’ on a real device. The combination of these 2 things would allow recording more elaborate action replays, which will come in handy as test inputs when I start working on the actual game logic and win-lose conditions and such.

Development scoreboard

I spent about 4 hours on the sprite atlas classes, and another 2 creating the sprites. The total development time is now at about 97 hours. SLOC count is now 1353.