The iOS Game Template extras

This is part five of a series on making iOS games.

Continuing on from last week, this post describes some of the non OpenGL parts of my iOS game template, and then finishes with some discoveries.

Centre of the universe

Since the player is the centre of the universe in my game, I can apply one translation to all my sprites.

Here is the simple translation I do:

GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(bounds.size.width * 0.5 - player->location.x, bounds.size.height * 0.5 - player->location.y, -6.0f);
spriteEffect.transform.modelviewMatrix = modelViewMatrix;

The z coordinate is arbitrary number – maybe I’ll use the z later at some stage.

ARC

Properties were great for memory management pre ARC – now of course ARC takes care of that, however in non games I still do tend to use only properties to access ivars. In a game I often do the opposite, I access the ivar directly, I try to avoid message passing. It can significantly deteriorate performance. With operations that are happening hundreds of times per second, messages (properties or methods), can hammer down the frame rate (I guess I could have my cake and eat it too, that is performance and classes by using C++. I don’t like C++, so I am not going to do that). Of course there is always a balance between performance and ease of use, so for my player sprite and monsters, I tend to use classes and instance methods, but for particles I use structs and functions.

Textures atlases and Zwoptex

Zwoptex http://zwoptexapp.com/, is a great app because you can drag all the images you want into an atlas (one image) and it will arrange them for you, you then can export the image and the plist describing the images held that one image. I assume if you are reading this, you probably know why this is done, but just in case.

From Apple’s: OpenGL ES Programming Guide for iOS: Best Practices for Working with Vertex Data.:

 ”Binding to a texture takes time for OpenGL ES to process. Applications that reduce the number of changes they make to OpenGL ES state perform better. For textures, one way to avoid binding to new textures is to combine multiple smaller textures into a single large texture, known as a texture atlas. A texture atlas allows your application to bind a single texture and then make multiple drawing calls that use that texture, The texture coordinates provided in your vertex data are modified to select the smaller portion of the texture from within the atlas”


Source:the Apple doc above
In Zwoptex make sure in the prefs you swap the origin.. here is the code I use to parse the plist exported from Zwoptex:

-(void)loadTextureRects
{
textureRects = [NSMutableDictionary dictionary];
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *plistPath = [path stringByAppendingPathComponent:@"atlas.plist"];
NSDictionary *spriteData = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSDictionary *spriteFrames = [spriteData objectForKey:@"frames"];
NSArray *spriteNames = [spriteFrames allKeys];
NSDictionary *mapSizeDictonary = [spriteData objectForKey:@"metadata"];
CGSize mapSize = CGSizeFromString([mapSizeDictonary objectForKey:@"size"]);
float xPixelBuffer = 2 /mapSize.width;
float yPixelBuffer = 2/ mapSize.height;

for (int i=0; i < [spriteNames count]; i++)
{
NSDictionary *sprite =[spriteFrames objectForKey:[spriteNames objectAtIndex:i]];
NSString *rectString =[sprite valueForKey:@"textureRect"];
CGRect initialRect = CGRectFromString(rectString);
CGRect newRect = CGRectMake(initialRect.origin.x / mapSize.width, 1 -   (initialRect.origin.y / mapSize.height + initialRect.size.height / mapSize.height), initialRect.size.width / mapSize.width, initialRect.size.height / mapSize.height);
CGRect final = CGRectInset(newRect, -xPixelBuffer, -yPixelBuffer);
NSValue *rectValue = [NSValue valueWithCGRect:final];
[textureRects setValue:rectValue forKey:[[spriteNames objectAtIndex:i] stringByDeletingPathExtension]];
}

}

And later on I use:

CGRect rectForName(NSString *name, NSDictionary *textureRects)
{
NSValue *rectValue = [textureRects valueForKey:name];
return [rectValue CGRectValue];
}

to get the rect for a named image.

Things to note with iOS and OpenGL

  • Test on the device – its much faster than the the simulator for OpenGL and much slower for non OpenGL, and different devices have very different performance profiles
  • When playing with vertex structs – the wrong sizeof, or the  number of vertices and indices can trip you up, with little feedback as to why.
  • Watch out for overruns in the indexes – GL_UNSIGNED_BYTE – as it can only hold 256 indices. A good check for these issues is to print out all the vertices and indices
  • Do sanity checks – put a bunch of tiles over the screen and test fps, test it when scrolling, test it when changing the vertices for all sprites
  • Make sure blend modes are ok.
  • For my drawing engine on the iPod touch 4G, multi-sampling (view.drawableMultisample) , going down to 16 bit context, and using different contentScaleFactors on the view made no difference to performance
  • Use GCD for the update logic – even on the iPod touch 4G had a signicant speedup to the update time.This includes collisions so it’s basically all non drawing part of the game loop. I use a dispatch group to wait for all asynchronous updating to finish. However no OpenGL code (including GLKBaseEffect manipulation) uses GCD in my engine.

Summary

I have found that creating a project which satisifies most of the OpenGL drawing needs of my upcoming projects, is time consuming but worth while exercise.

I did this same exercise in MacRuby and OpenGL (not ES of course) a few years ago, and it enabled me to go from idea to prototype creation for a top down 2D tile based action game in 2 weeks. No promises for this game though, a demo is not a shipping product, and in this game since I want to create a lot of effects (for which there will be another OpenGL focused blog post).

Coming up: Particles

Resources

iPhone 3D programming – Rideout – widely described as the best book on OpenGL for the iPhone. I think its good too, but wading through C++ is very dull, OpenGL ES 1 and 2.

Learning iOS game programming – Michael Daley – good reference – (OpenGL ES 1.0 only).

In the past he had some nice videos on the topic – currently he has some useful tools to sell. http://www.71squared.com/

iOS 5 by tutorials, Ray Wenderlich – chapter 8, is a nice place to start things for OpenGL ES 2.0. (nothing on multiple sprites/particles).

Apple WWDC talks on OpenGL 2010 and 2011

Apple’s: OpenGL ES Programming Guide for iOS: Best Practices for Working with Vertex Data.

Jeff LaMarche’s website has some good openGL stuff: http://iphonedevelopment.blogspot.com/

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>