Iphone Game Programming – Tutorial 12 – Saving State

I’ve managed to squeeze in one last small tutorial for 2009. I had a request on the blog for a tutorial on saving game state. This is only a quicky and I’ve built it on the code from Tutorial 11. It covers how I’ve used NSCoding to store game state which is really easy to do.

Tutorial 12

Tutorial 12 Project

I hope you enjoy it and have a great Christmas :o)

Upate 23/12/09: Kurt commented on the tutorial and pointed out that I am over retaining myObject when it is loaded from the decoder. As I am using self.myObject and the property is defined as retain, doing a further retain when reading it in would in fact leak myObject. I have changed the source code and removed the unnecessary retain. I don’t use self in the SLQ code and hence need the retain. More haste less speed they say :o)

Mike

Share:
  • Digg
  • del.icio.us
  • Facebook
  • MySpace
  • Reddit
  • StumbleUpon
  • Technorati
  • TwitThis
  • Design Float
  • DZone
  • email
  • Google Bookmarks
  • LinkedIn
  • Scoopeo
  • Tumblr

47 Comments

Tweets that mention Iphone Game Programming – Tutorial 12 – Saving State | 71² - The ramblings of two 30-something developers -- Topsy.com  on December 23rd, 2009

[...] This post was mentioned on Twitter by 71Squared, Carlos Chavez. Carlos Chavez said: RT @71squared: Tutorial 12 – Saving Game State has been posted – http://tinyurl.com/ye9ma4e [...]

Kurt  on December 23rd, 2009

I think you are over-retaining myObject. In the header file, myObject is tagged with the “retain” attribute. When you load your object from the archived data, you use self.myObject assignment which will do the retain for you. You do not need the extra retain, and this can cause a leak.

In your Sir Lamorack’s Quest code, you do not use “self-dot” syntax, you just assign directly to variables, so you do need the explicit retain there. I’ll bet you just got in the habit of adding the retain here, and carried it over to your other example.

mike  on December 23rd, 2009

Hi Kurt and thanks for the heads up. Your absolutely right that I’m over retaining it. I did just carry it over without thinking from my SLQ code, DOH!!!

I’ll make a note in the post :o)

Mike

RoberRM  on December 24th, 2009

Thank you very much, Mike, for this early Xmas present. :)
Merry Christmas and a happy New Year to you too.

Kurt  on December 25th, 2009

Hi Mike,

In my haste to point out a leak I forgot to say:

Thank you so much for your tutorials. Examples like these are a wonderful resource for new programmers. I would never have been able to write an iPhone app without people like you who post these examples. I hope you have a Merry Christmas and best wishes for a great 2010!

mike  on December 25th, 2009

Cheers Kurt

People sharing their knowledge is how I have learnt SOO much over the years, so this is just a way for me to repay the community.

I hope you have a great Christmas too and a successful app filled new year.

Mike

PaulC  on December 28th, 2009

Was it my request that this was a response to? Because it was exactly what I was looking for. Thankyou so much!

I hope you had a great Christmas, have an even better New Year.

Paul.

mike  on December 28th, 2009

Hi Paul, yes, this was based on your request :o)

I’m glad it gave you what you needed. I did have a great Christmas and looking forward to an exciting new year. I hope you also had a great Christmas and wish you all the best with your projects in the new year :o)

Mike

Martin  on December 29th, 2009

Hi Mike,

This is very useful for beginners like me. I am developing an Opengl based iPhone app. I have a question, i want to keep the home view background image as under the sea(i.e. live water image as background image), how can i do that? Do i need to have a sea water image in .gif format and add it as background because it should be live water flowing here and there, same like under sea?

mike  on December 30th, 2009

Hi Martin

I’m not completely sure I understand your question, but it sounds like you want an animated background to your game?

If you are rendering in OpenGL there is no built in way to render an animated GIF. You would need to create your own animation using a sprite sheet.

If your background image is the full size of the screen then I would create one image that filled the entire screen, and then render smaller animated images on top where you want the water to be flowing etc.

There is a tutorial I’ve done on sprite sheets if you want to take a look through.

Hope that helps.

Mike

Martin  on December 30th, 2009

Hi Mike,

Thanks a lot. Yes, i want an animated background with full screen. There is no specific place where should the water flow etc. instead it can simply look like under water.

mike  on December 30th, 2009

Great, glad to gave you some ideas. To get started you could simply create a sprite sheet from the seperate images you have in your gif image and then just run that animation in the background.

When you start to get more advanced you can start to perform all sorts fancy effects using OpenGL e.g. render a simple underwater background and then use OpenGL to render a wobbly refractive effect over the top using that base image. This can all get very complex but some cool effects can be achieved.

Check out Pearl Diver in the Readers Game section to see the kind of underwater effects you can create. Not sure how they did them but they look good.

Mike

Martin  on December 30th, 2009

Thanks Mike. As i can’t use a single animated image directly, i should have images separated out that water flow gif image as i) First static image can have only water. ii) Next image can have moving water kind of static image etc., atlast i should animate these images one by one using animation API’s? Are there any samples source to go through?

Starra  on December 31st, 2009

Hi MIke,

Great tutorials. Me and a couple friends want to develope iphone games and your tutorials have been very helpful in getting the ground running.

One question, since I am still a beginner in Objective-C. When I run your code straight from the downloaded file, it runs fine. However, when I copied the files over to a new project, I get this warning.
“/Users/Starra/Documents/Project/2DShooter/MenuScene.m:31:0 /Users/Starra/Documents/Project/2DShooter/MenuScene.m:31: warning: incompatible Objective-C types ‘struct NSString *’, expected ‘struct UIImage *’ when passing argument 1 of ‘initWithImage:’ from distinct Objective-C type”

Shouldn’t the initwithImage function be expecting a NSString instead of UIImage like the warning suggest? I am confused.

Also, when I run the new project, somehow, I just get a white screen after the loading screen. The menu screen did not show up. I probably did something wrong when I moved the files or something, but just in case you have any idea what is going on.

Starra  on December 31st, 2009

I found the problem to the warning. All I needed is to cast the initwithImage with a (Image*) in front.

Now I am stuck with the white screen problem. As I play with it more, I notice that the menu scene might have rendered, but somehow it is not shown because when I click the iphone button, as the app quit, there is a fade out sequence of the menu scene with all the menu item. Any ideas??

Thank for the help and Happy New year!!

mike  on December 31st, 2009

Hi Starra

Do you have any code you can send me or an example project with the issue you are seeing and I can take a look.

Mike

Starra  on December 31st, 2009

I did some googling around and found out that if I comment this line out…

“window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];”

in applicationDidFinishLaunching(), the app runs fine with the menu scene and everything. Not sure why that is though, since I was about to run your project straight from the downloaded files. Thanks Mike!

dilbertian  on January 1st, 2010

Mike,
Trying to implement this into my program today and am making progress but don’t have it working quite yet. I have a question. If I were going to integrate this with something similar to your Tutorial 10 with which already has a call to [window addSubview:glView]; in the applicationDidFinishLaunching() routine, would I just add another line under that for MyObject to add another subview for that too? Here is an excerpt of that section of code:

[window addSubview:glView];
[window addSubview:viewController.view];
[window makeKeyAndVisible];

Having some compilation issues with the viewController’s .view member at the moment so I can’t tell if it will work or not yet.

I just wanted to make sure I’m on the right path.

Thanks for putting this and all of the other tutorials together as well, it’s all VERY helpful and enlightening

Thanks!

-Dil

Anonymous  on January 3rd, 2010

Any link to download the video directly instead of watching online?

Thank you.

benoitr007  on January 4th, 2010

Hi Mike,

Thanks again for the wonderful tutorials.

I would like to ask, will your book cover audio sessions in more depth, as I am having problems with the background music of my game, more specifically when I lock the phone. It just stops playing and doesn’t come back, and I also have lag issues.

Thank you

Benoit

mike  on January 4th, 2010

Hi benoitr007, yes, the book is going to have a chapter on the SoundManager class as well as information on how I have implemented it in SLQ. SLQ uses OpenAL for location based sound e.g. when doors open and close the sound can be heard based on where the player is standing in relation to the door :o)

Locking and unlocking the phone and keeping music playing was a problem I was having as well. I made changes to the sound engine to better handle this. I’ll post up a zip later of my latest sound engine with these changes. Just dropping the class in should cause it to work nicely when phone calls, alarms or phone lock stops the sound :o)

Mike

benoitr007  on January 4th, 2010

Hi Mike, that’s great news! Did you experience lag problems caused by the music? I’m having some when I run the tutorial 10 project on my iPhone and add music to it. There seems to be 2-3 skipped frames every second or so. I found a way to fix this by setting the audio session category to SoloAmbientSound, which apparently keeps the decoding on the audio hardware instead of the CPU. But whenever I play the sound again after locking and unlocking the phone, the lag is back.

dilbertian  on January 9th, 2010

Mike,
I am having some issues with the sound engine – (maybe the same problem you have fixed) – looks like when the background music pauses or stops, all sounds stop as well. If I resume or restart another music track, it sounds as if all previous sounds had been queued and try to play all at once.

In doing some debug with playSoundWithKey(), I don’t see any smoking guns but noticed that the sourcestate was always AL_STOPPED but wasn’t sure if this was causing the problem or not. I tried a few work-arounds but most of them were either inefective or crash and burn.

Thanks,

-Dil

mike  on January 9th, 2010

Hi Dil

That is an odd issue. The AVAudioPlayer is different from the OpenAL side of things so should not interfere with it. I’ll do some testing and see if I can get the same effect and get back to you.

Mike

mike  on January 9th, 2010

I’ve just one a quick test. I paused music playing but could still hear OpenAL sounds being played. When I then played the music again it continued from where I had paused it and the OpenAL still worked ok.

What I’ve done is zip up my latest SoundManager files. This has all the bug fixes in it for handling sound interruptions etc. It also makes use of the Apple C class for loading sound files of different types correctly.

Give it a try and let me know if you have the same issues. You should just be able to drop this straight into your project.

Let me know how it goes.

Mike

mike  on January 9th, 2010

A link would be useful :o)

http://www.71squared.com/iPhon.....lasses.zip

Mike

dilbertian  on January 10th, 2010

Mike,

Thanks bunches for the ultra quick reply and source dump!!!!

I expect that this will work but will check back to let you know either way.

-Dil

Juion  on January 15th, 2010

Hi,

first of all I want to thank you very much for the incredibly helpful tutorials you’ve put up here. It’s been a great support for me so far.

Unfortunately I’m having an issue running Tutorial 12 on my machine.

While executing line 41:

_soundManager = [SoundManager sharedSoundManager];

in the OGLGameController method init, XCode always throws an “EXC_BAD_ACCESS” error. I tried to incorporate the new sound manager version you’ve recently uploaded, but still no success.

I’ve come to a dead end. Can you please help me?

mike  on January 16th, 2010

Hi Juion

I’m not sure what your problem is. It certainly telling you that your trying to access something that has either not been allocated or has been released too early and its still trying to be used.

What happens if you comment out that line. Tutorial 12 did not use the sound manager class or the game controller class so I’m assuming you are adding these yourself. Check to make sure you are allocating your objects at the right time and not releasing them too soon.

Without seeing more code that is all I can suggest at the moment.

Mike

Peter  on January 19th, 2010

Wanted to thank you Mike for all the hard work you’ve done to get this together for everyone.

I started following your tutorials back when you first started and I wanted to share with you and anyone else that’s interested what we’ve been able to achieve so far using your blog as a starting point.

Here’s the game we are developing, thanks to your tutorials. Let us know what you think!

http://www.squaresmile.com

hugo  on February 1st, 2010

Hi Mike,

Could you tell me please how to deal with arrays of objects?
Let say i have an object A that contains an array of objects B (object B has encodeWithCoder and initWithCoder methods) and i want to encode object A…
encoding every single one separately with different key (using stringWithFormat for example) seems stupid.
Is there an easier way?
btw. Do you encode all particle emitters while saving game sate?

mike  on February 1st, 2010

Hi hugo

Based on your example, you would just need to encode object A which could be an NSMutableArray or dictionary. For example, I have an array in SLQ that contains all my baddies. Each baddie is an object which supports NSCoding. When I want to encode the array I simply do

[encoder encodeObject:entities forKey:@"entities"];

This will encode the entire contents of that array and store it with the key entities. I can then decode in the same way populating an NSMutableArray.

There is nothing stopping you from doing the same with particles, although more work would be required so that the particle details that are stored in a structure are converted to a wrapping object or class of their own.

I personally don’t bother with that. I simply create any particle emitters that are held within an object during the init, which is still done when you create objects that have been encoded. It saves a lot of effort :o)

Hope that helps

Mike

hugo  on February 2nd, 2010

hey, thanks for reply,
good to know that it’s so easy with nsarrays, unluckily form me i’ve used staright C arrays and i had to do it all by myself… everythig is workin fine except for particle emitters – but im working on it. i will share the code only if i manage to get it work

mike  on February 3rd, 2010

@Peter, I checked out your website and the its looking very cool. Trying to cover a project like this and being so far apart cannot be easy, but it looks like your making great progress.

I can’t wait to see the next video and how the game is coming along :o)

Mike

9livesoftware  on February 8th, 2010

Hello,
Im trying to make it so when my character jumps and when it lands on a block it doesnt go through it.

PS I dont know how to code for the jump or the collision.

glen  on February 12th, 2010

Hi Mike
Great tutorials!
Could you, or anyone else help with the following.
In the game i’m trying to develope i’ve been using a 2d array to store bullet information. The array holds a bullet start position x and y offset for x and y to control direction and a counter which reduces to 0, giving the bullets a lifespan. the other dimension to the array is for the number of bullets if you see what i mean. So when the screen is touched the array is checked for the first instance of a 0 lifespan then the x,y,and lifespan are set. The update scene then loops the array changing the position by using the offset for each bullet with a lifespan > 0 and decreases the lifespan. The render scene then loops and displays a bullet each time the lifespan is > 0. I have altered this code loads of times even to the point of makeing multiple 1d arrays which prevents me from looping as i would like but i come up with the same problem everytime? When you create a new bullet the previous one disappears???? Thanks to all in advance for any help.

Anonymous  on March 5th, 2010

Hey Mike,

I would like to thank you for this great tutorial, it is the best.

I am starting to build my game project based on the tutorial, and started to worry about the Max PNG size the Image/2DTexture could handle.

I would really apreciate any help on this.
Cheers.

mike  on March 5th, 2010

The largest texture that can be handled in OpenGL ES 1.1 on the iPhone is 1024×1024 pixels. On the iPhone 3GS using OpenGL ES 2.0 it is 2048×2048.

Unless you really need the features of OpenGL ES 2.0 I would stick with 1.1 which also gives you currently the largest user base, so 1024×1024 is the max.

Hope that helps.

Mike

jjack  on March 6th, 2010

is it possible to use NSUserDefaults to save the state or is that to memory constraining

Thanks

Ron  on March 11th, 2010

Hi Mike,
Excellent tutorials! I’m finding them extremely helpful and informative. Keep up the great work!

Cheers!

glen  on March 17th, 2010

Hi All
I’ve been working with tutorial9 to do my little project and its going good. But ive just started to try and implement some saving when the app quits using tutorial 12. I cant seem to get it working and i wondered if anyone could tell me anything to help or even post an example. All i want to be able to do is save a handfull of ints when the program quits???
Thanks in advance

mike  on March 17th, 2010

Hi glen, where are your ints being stored? Are they within objects you have created, or just held in your main game.

If they are inside objects then the NSCoder stuff should be implemented in those objects to encode the ints. If they are just in the core game code then you could use an NSDictionary and write its contents out. This is how I am saving my settings in SLQ e.g. volume

	NSNumber *mv = [NSNumber numberWithFloat:sharedSoundManager.musicVolume];
	NSNumber *fv = [NSNumber numberWithFloat:sharedSoundManager.fxVolume];
	NSNumber *lh = [NSNumber numberWithInt:joypadPosition];
	NSNumber *fd = [NSNumber numberWithInt:fireDirection];
	[settings setObject:mv forKey:@"musicVolume"];
	[settings setObject:fv forKey:@"fxVolume"];
	[settings setObject:lh forKey:@"joypadPosition"];
	[settings setObject:fd forKey:@"fireDirection"];
	[settings writeToFile:settingsFilePath atomically:YES];

Loading them back in would use

	if([[NSFileManager defaultManager] fileExistsAtPath:settingsFilePath]) {
		SLQLOG(@"INFO - GameController: Found settings file");
		settings = [[NSMutableDictionary alloc] initWithContentsOfFile:settingsFilePath];
	} else {
		SLQLOG(@"INFO - GameController: No settings file, creating defaults");
		settings = [[NSMutableDictionary alloc] init];
		[settings setObject:[NSString stringWithFormat:@"%f", 0.7f] forKey:@"musicVolume"];
		[settings setObject:[NSString stringWithFormat:@"%f", 0.5f] forKey:@"fxVolume"];
		[settings setObject:[NSNumber numberWithInt:0] forKey:@"joypadPosition"];
		[settings setObject:[NSNumber numberWithInt:0] forKey:@"fireDirection"];
	}

	// Get the prefs from the pref file and update the sound manager
	[sharedSoundManager setMusicVolume:[(NSString *)[settings valueForKey:@"musicVolume"] floatValue]];
	[sharedSoundManager setFxVolume:[(NSString *)[settings valueForKey:@"fxVolume"] floatValue]];
	self.joypadPosition = [[settings valueForKey:@"joypadPosition"] intValue];
	self.fireDirection = [[settings valueForKey:@"fireDirection"] intValue];

Hope that helps.

Mike

glen  on March 18th, 2010

Hi Mike
Thanks for the response i have decided that if somethings worth doing its worth doing right. So i have bought the book and im going to start all over again with a better understanding of how to do everything. Only read to chapter 3 so far but im already glad i bought it.
Cheers

mike  on March 18th, 2010

Let me know how you get on :o)

Mike

dave  on April 2nd, 2010

Hi Mike,

Thanks for all the great tutorials. I just wanted to ask a question about saving game state. Given an earlier tutorial on a singleton shared game state, why not just centralise all game state and encode/decode/save the singleton object? Is there a benefit to having each game object know how to encode/decode its own game state data?

David

Greg  on April 28th, 2010

Hi Mike, thanks for all the tutorials. Had a follow-up question similar to the one above me (dave). Is there a way to restore a singleton (with state) or is it better practice to just save the data individually from the singleton, initialize and rebuild the singleton manually from my “Load Game” methods?

Kaizoku  on July 26th, 2010

Thx mike, the project file seems to be only the joypad, not the actual tutorial 12 folder.

Leave a Comment