Matt Tuttle


Saving Game State on the iPhone

Do you need to save your game's data on the iPhone but you don't know where to start? Look no further than this article because it should have everything you need. Just fire up Xcode and we'll begin to add our game state saving code.

First thing we want to do is create two new functions in the app delegate code. These two functions loadSettings and saveSettings will load/save our game data at the start and close of the app respectively. We'll add some boiler plate code and then move on to the fun stuff. This will save/load settings from the iPhone user defaults.

AppDelegate.mm

- (void) loadSettings {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [defaults objectForKey:@"GameData"];
    gGameData = [[NSKeyedUnarchiver unarchiveObjectWithData:data] retain];
    if(gGameData == NULL) {
        gGameData = [[GameData alloc] init];
    }
}

- (void) saveSettings {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:gGameData];
    [defaults setObject:data forKey:@"GameData"];
}

- (void) applicationDidFinishLaunching:(UIApplication*)application {
    ...
    [self loadSettings];
    // Run you game code after loading settings
    ...
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [self saveSettings];
    ...
}

Now let's create a GameData structure to hold all of our data we want to save and load. It's a good idea at this point to write down all of the data you want to save (score, positions, name, etc...). The implementation is pretty straight forward but can get complicated if you have a lot of data to save. In this example I'm going to save a level number.

GameData.h

#import <Foundation/Foundation.h>

@interface GameData : NSObject<NSCoding> {
    int level;
}

@property (readwrite,assign) int level;

@end

extern GameData *gGameData;

GameData.m

#import "GameData.h"
GameData *gGameData;

@implementation GameData

@synthesize level;

-(void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeInt:level forKey:@"Level"];
}

-(id)initWithCoder:(NSCoder *)coder {
    NSData *data;

    if((self = [super init])) {
        [self setLevel: [coder decodeIntForKey:@"Level"]];
    }

    return self;
}

-(id) init {
    if((self = [super init])) {
        level = 1;
    }
    return self;
}

-(void) dealloc {
    [super dealloc];
}

@end

You may have noticed that we've declared a global variable gGameData in the header file. This variable will be used in your app to access the game data while running. It also makes it so we don't have to pass the variable through the entire app. The global variable is allocated and released in the app delegate so the data will always be around. You can access the GameData properties as shown.

int level = gGameData.level;
gGameData.level = level;

You can decode anything from integers, NSNumbers, booleans, and even objects. To save an object you'll need to write a custom save routine and use addObject/decodeObject respectively. 

That's about all it takes to write code to save your game's state in an iPhone app. This is obviously a simple example and you'll find that your game may require more data to save. It's also possible to save separate chunks of data in different classes using NSCoder. The most important concept is saving the data to the iPhone's user defaults. Happy coding!

Posted in Game Development

Tags:

comments powered by Disqus