DISCLAIMER: This is a big post, and it's written in my very average English. So I'd like to apologize for any error that you will find.
I'd like to share some classes that I am using in my games (Caribbean Treasures and the upcoming Fix The Leaks). They are quite useful to me, and I hope for you as well.
1. Script parser
I am using my own scripts to describe levels, sprite animation (critters in Fix The Leaks have an emotion engine, and emotions animation is described using my own script language), and even game properties (for big projects it's much faster to make changes in the script rather than in the code that might require a complete re-compilation).
ScriptParser is a class that helps you to add your own scripting language in your games. It load script from the file, breaks it into commands and parameters and put commands into the queue. All you have to do is to run through the queue with a simple if/then condition and execute commands that you defined.
ScriptParser is a very simple class, so it has a limitation: 1 line = 1 command with parameters.
Here's how it work:
// Load custom script from a file and break it into components
// Each command might be treated as a parameter. If you have a line "width 800" in your
// script, then you can call [getValue:@"width"] to retrieve the value 800
// Call [getValue] if the parameter has only one value and [getValues] to get an array
// of parameters that are separated by comma in the script
// IMPORTANT! If you used getValues to get an array with multiple parameters,
// you must release the array!
// Each line of the script is supposed to have the same format: [command] [parameters]
// getCurrentAction returns a string with the current command
// getCurrentParameter and getCurrentParameters act like getValue and getValues.
// They return the parameters for the current command
// nextStep move internal pointer to the next command in the queue.
// It return NO when there's no more commands left.
Let's create a script with our custom language that do the math calculations and make a code that will execute it.
Here's the script:
putinrange 0, 10
And here's the code that execute this script:
ScriptParser *sp = [[ScriptParser alloc] init];
// Values are always NSString, so we must convert it into other data types
float value = [[sp getValue:@"setvalue"] floatValue];
if([[sp getCurrentAction] isEqualToString:@"add"])
float += [[sp getCurrentParameter] floatValue];
if([[sp getCurrentAction] isEqualToString:@"mult"])
float *= [[sp getCurrentParameter] floatValue];
if([[sp getCurrentAction] isEqualToString:@"putinrange"])
NSArray *values = [sp getCurrentValues];
float min = [[values objectAtIndex:0] floatValue];
float max = [[values objectAtIndex:1] floatValue];
if(value < min) value = min;
if(value > max) value = max;
if([[sp getCurrentAction] isEqualToString:@"printvalue"])
} while([sp nextStep];
As you see, you can define any command and create your own custom language. For example, this is my own custom script that describe how to remove the UFO from the scene:
stopsound 35, 6
move 0, -200, 3
rotate 15, 3
And I have my own SPAnimSprite class that execute this script and play the animation.
2. Resource manager
I am using ResourceManager to preload textures and texture atlases for the current game scene and release them when the scene is done.
The advantages of this class are following:
If there's many objects that use the same texture or texture atlas, I don't need to care on passing the link to the graphics into each object. I just preload it into the resource manager from main class that handle the scene and then access it from another classes through the resource manager.
If I decide to add another texture for my classes that describe scene objects, I will not need to modify my code in every place where the objects are created to pass additional link. Again, I just preload it into the resource manager in main class and then simply access it through the resource manager from other classes.
If I add a new texture or atlas to use in child classes, I don't have to add an additional code into the destructor to release it. It will be released once I call resource manager's method "flush" in my main loop during the scene switch.
ResourceManager work with SPTexture and SPTextureAtlas. Unfortunately, SPTextureAtlas doesn't have any methods to get the information about texture regions. So to use ResourceManager, you have to add a new method to the SPTextureAtlas:
The usage of the class is pretty simple. It's a singleton class, so you don't need to allocate and release it. Just call [ResourceManager shared] to get the access to the object.
// Preloading texture from a file
[[ResourceManager shared] preloadTexture:(NSString *)fileName
// Preloading texture atlas from a file and add it's regions as separate resources
[[ResourceManager shared] preloadAtlas:(NSString *)fileName;
// Get texture by name (file name for a texture preloaded from file or
// the region name for a texture that is a part of SPTextureAtlas.
// If a resource is not preloaded yet, ResourceManager assumes that it's a file
// and attempts to preload it.
[[ResourceManager shared] get:(NSString *)resourceName;
// Add a custom SPTexture
[[ResourceManager shared] add:(SPTexture*)tex name:(NSString *)resourceName;
// Release all preloaded resources
So, how to use it?
Preload the required graphics during the scene initialization
When the scene is done, call [[ResourceManager shared] flush]; in scene class destructor or in the code that change a scene. All preloaded resources will be released.
3. Large image renderer
Well, problem is that a big texture takes more time to be rendered than a bunch of smaller textures. Here's the description of the problem:
And here's a solution:
SPLargeImage class that is simply load a big image and break it into a set of smaller triangles. And then render them all with 1 OpenGL call.
Not that it add a lot performance, modern video cards are quite fast. but with several big images you win a few several fps.