Hello.
I've been working on a game for a bit, I'm now trying to get it working with OS4+. I'm struggling with saving data, my method worked perfectly for OS3. I have a singleton:
#import "GameState.h"
@implementation GameState
@synthesize gStarted; @synthesize gLevel;
static GameState* _sharedGameState = nil;
+(GameState*)sharedGameState { @synchronized([GameState class]) { if (!_sharedGameState) [[self alloc] init];
return _sharedGameState;
}
return nil;
}
+(id)alloc { @synchronized([GameState class]) { NSAssert(_sharedGameState == nil, @"Attempted to allocate a second instance of a singleton."); _sharedGameState = [super alloc]; return _sharedGameState; }
return nil;
}
-(id)init { self = [super init]; if (self != nil) { // initialize stuff here gStarted = 0; gLevel = 0; }
return self;
}
@end
In my appDelegate, I save data like so (apologies for posting it all, thought it may help):
#import "LanderOpsAppDelegate.h"
import "cocos2d.h"
import "SplashScene.h"
import "GameState.h"
@implementation LanderOpsAppDelegate
@synthesize window;
(void) applicationDidFinishLaunching:(UIApplication*)application { CC_DIRECTOR_INIT();
// Obtain the shared director in order to... CCDirector *director = [CCDirector sharedDirector];
// Sets landscape mode [director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];
// Turn on display FPS [director setDisplayFPS:YES];
// Turn on multiple touches EAGLView *view = [director openGLView]; [view setMultipleTouchEnabled:YES];
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565 // You can change anytime. [CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
[[CCDirector sharedDirector] runWithScene: [SplashScene scene]]; //start with a splash screen }
(void)applicationWillResignActive:(UIApplication *)application { // Set up the game state path to save the global properties to NSArray *statePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *stateDirectory = [statePath objectAtIndex:0]; NSString *gameStatePath = [stateDirectory stringByAppendingPathComponent:@"gameState.dat"];
//Set up the encoder and storage for the global properties NSMutableData *gameData; NSKeyedArchiver *encoder; gameData = [NSMutableData data]; encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:gameData];
//archive our game data [encoder encodeInteger:[[GameState sharedGameState] gStarted] forKey:@"started"]; [encoder encodeInteger:[[GameState sharedGameState] gLevel] forKey:@"level"];
//Finish encoding and write to memory [encoder finishEncoding]; [gameData writeToFile:gameStatePath atomically:YES]; [encoder release];
[[CCDirector sharedDirector] pause]; }
(void)applicationDidBecomeActive:(UIApplication *)application { [[CCDirector sharedDirector] resume]; }
(void)applicationDidReceiveMemoryWarning:(UIApplication *)application { [[CCDirector sharedDirector] purgeCachedData]; }
-(void) applicationDidEnterBackground:(UIApplication*)application { // Set up the game state path to save the global properties to NSArray *statePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *stateDirectory = [statePath objectAtIndex:0]; NSString *gameStatePath = [stateDirectory stringByAppendingPathComponent:@"gameState.dat"];
//Set up the encoder and storage for the global properties
NSMutableData *gameData;
NSKeyedArchiver *encoder;
gameData = [NSMutableData data];
encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:gameData];
//archive our game data
[encoder encodeInteger:[[GameState sharedGameState] gStarted] forKey:@"started"];
[encoder encodeInteger:[[GameState sharedGameState] gLevel] forKey:@"level"];
//Finish encoding and write to memory
[encoder finishEncoding];
[gameData writeToFile:gameStatePath atomically:YES];
[encoder release];
[[CCDirector sharedDirector] stopAnimation];
}
-(void) applicationWillEnterForeground:(UIApplication*)application { [[CCDirector sharedDirector] startAnimation]; }
(void)applicationWillTerminate:(UIApplication *)application { // Set up the game state path to save the global properties to NSArray *statePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *stateDirectory = [statePath objectAtIndex:0]; NSString *gameStatePath = [stateDirectory stringByAppendingPathComponent:@"gameState.dat"];
//Set up the encoder and storage for the global properties NSMutableData *gameData; NSKeyedArchiver *encoder; gameData = [NSMutableData data]; encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:gameData];
//archive our game data [encoder encodeInteger:[[GameState sharedGameState] gStarted] forKey:@"started"]; [encoder encodeInteger:[[GameState sharedGameState] gLevel] forKey:@"level"];
//Finish encoding and write to memory [encoder finishEncoding]; [gameData writeToFile:gameStatePath atomically:YES]; [encoder release];
//CC_DIRECTOR_END(); }
(void)applicationSignificantTimeChange:(UIApplication *)application { [[CCDirector sharedDirector] setNextDeltaTimeZero:YES]; }
(void)dealloc { [[CCDirector sharedDirector] release]; [window release]; [super dealloc]; }
@end
And I load my saved data in my main menu scene like so:
+(id)scene {
CCScene *scene = [CCScene node];
MainMenuScene *layer = [MainMenuScene node];
[scene addChild:layer];
return scene;
//Load game data and write to the singleton
NSArray *statePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *stateDirectory = [statePath objectAtIndex:0];
NSMutableData *gameData;
NSKeyedUnarchiver *decoder;
NSString *documentPath = [stateDirectory stringByAppendingPathComponent:@"gameState.dat"];
gameData = [NSData dataWithContentsOfFile:documentPath];
if(gameData) {
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:gameData];
//Set the global user data
[[GameState sharedGameState] setGLevel:[decoder decodeIntegerForKey:@"level"]];
[[GameState sharedGameState] setGStarted:[decoder decodeIntegerForKey:@"started"]];
[decoder release];
} else {
//Game has not been run yet, set default values here
[[GameState sharedGameState] setGLevel:0];
[[GameState sharedGameState] setGStarted:0];
}
}
However, this isn't working on OS4. What happens is the game loads fine the first time, I do something and quit out (I have it set currently to force a change on the level integer) and then re-load. It comes straight back to where it was, without any change in level data. If I quit the application totally from the multitask bar then reload, the screen goes black and I have to force quit the app from XCode, then sleep and wake the device. Not good :)
I think the things that are confusing me are the multitask management, sleeping and waking. I've hunted for hours and tried every method I've seen, but they seem very complex for saving out a couple of integers :)
Any help would be great. The winning person gets credit in my game (if you want it :) )
T.