iPhone Game Programming – Tutorial 5 – Animation Class
Tutorial 5 is now uploaded and ready to view and runs for around 37mins. This tutorial covers the Animation class which allows you to specify a series of sprites which are displayed on screen in order. This class allows you to add any number of frames to an animation and also specify how long each frame should appear, so, rather than having every frame only appear on screen for the same period of time, each frame can have its own display time.
The class also supports the ability to repeat animations and ping pong backwards and forwards.
You can view the tutorial and download the project using the links below.
I hope you enjoy this tutorial and please post any comments or questions. I’m now working on the Tilemap tutorial which I’ll get done as soon as possible.
Mike
84 Comments
mike on April 19th, 2009
Well spotted Allan, that’s what comes of doing this stuff at 1am ;)
I’ll make the change and upload a new version once its encoded.
Mike
EDIT: The mistake has now been corrected :)
bob on April 19th, 2009
@Mike…
Great job, as always I must say you are one heck of a programmer/teacher. ( “so say the knights who say Nee!” ). And you’ve given me some new ideas.
mike on April 19th, 2009
Thanks bob, that’s made my day :D
I’m really enjoying this stuff at the moment. Its so different from the day job and making me think in new ways. I’m glad the tutorial has switched on some light bulbs for you and I’m keen to see your end product when your done :D
Mike
Ricardo on April 19th, 2009
Hello Mike, I just wanted to say thank you so much for making all these great video tutorials with such a great quality, I’ve been searching like crazy all over the internet for a good starting point on game programming for the iphone using OpenGL and your tutorials are by far the best thing out there, please keep’em coming! :D
Greetings from Mexico and thanks again!!
Jamie Hill on April 20th, 2009
Great tutorial yet again. Also thanks for enlarging on the bits I was unsure of in tutorial 4, I cleared it all up in my head nicely :)
I took it upon myself to rip apart the Texture2D class as a bit of an exercise more than anything. I have rewritten it into a simpler version with only the bits I need (it only supports RGBA images at present) and it comes in around 130 lines including comments for both the .h and .m files: http://pastie.org/452354.
I am implementing your tutorials as I go with my own take on it so I understand what is happening as I said before. One thing I have changed which may be worth mentioning is that I have added another renderAt method to the image class. The method accepts the currently bound texture from the AppDelegate (in this case) , meaning that this can be used in place of the “if([texture name] != appDelegate.currentTexture)” code, the reason being that then the image code is not coupled to one specific project and can therefore be used as a common library.
There is one thing I’m still struggling with and that’s the typedef, I don’t really understand what’s going on here:
typedef struct _Quad2 {
float tl_x, tl_y;
float tr_x, tr_y;
float bl_x, bl_y;
float br_x, br_y;
} Quad2;
Anyway, thanks again and I look forward to the next instalment.
p.s. the particle stuff is looking impressive.
Jamie Hill on April 20th, 2009
Sorry for the double post but forgot to mention, a lot of the code in the new texture class came from Apples GLSprite example.
mike on April 20th, 2009
No worries Jamie. I like the look of your class and totally get taking things apart to see how they work. That’s how I’ve learnt most of what I’m blogging about :D
At some point I must re-factor Texture2D so that it just does what I need and tidy things up. Your code would be a great place to start if you didn’t mind me including it at a future date?
The Quad2 structure was just created so that I could easy manage the x and y coordinates needed to define a quad. tl_x is the x coordinate for the top left hand corner, hence the tl. It makes it simple for me as I need simple things ;) to understand what part of the quad I’m working with. So to define a quad and pop it into an array, I use that structure. As I need to define similar texture map coordinates I use the same structure for hold my texture coordinated as well.
Let me know if that makes sense.
Cheers
Mike
Jamie Hill on April 20th, 2009
By all means use the code in that snippet, it’s the least I can do with all the time you’ve put into the tutorials.
As for the typedef stuff, it was more about understanding what that actually did. I can kind of see how it’s being used but I’ve not come across any like it being new to Objective-C and not having touched C for years. I think I might go read a few articles on C fundamentals as I’ve forgotten most of it since doing Ruby and before that PHP and Perl.
mike on April 21st, 2009
Hi Jamie, a structure is basically a collection of variables of different types. Using typedef allows you to create a new type which contains the variables defined in your structure. So, defining something like Quad2 means I can then access variables in Quad2 using the dot syntax
Quad2.tl_x = 10;
This also means that when you create a variable or array with this structure, the correct memory is allocated based on the size of the types used in your variables in the structure. So its really to allow you to make access variables which are related simple to use in your code, at a basic level that is :D
Hope that made some kind of sense, its been a long time since I’ve tried to explain something like that.
Mike
Jamie Hill on April 21st, 2009
Ahh, I see… it was the _Quad that was throwing me but that’s because the struct has to have a name, I’ll go back to sleep now ;)
I’ve made an interesting discovery on the OpenGL front. As I mentioned before, I was trying to lose the call to appDelegate in the Image class so I was passing in a texture name to render which wasn’t the best solution. I decided that that it must be possible to get the last bound texture from OpenGL and after a lot of searching I found a solution buried deep in the docs for: http://www.khronos.org/opengle...../glGet.xml.
So now in my check I am doing this which is working great for me so far in my testing:
int currentlyBoundTexture = 0;
int textureToBind = [texture name];
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤tlyBoundTexture);
if(textureToBind != currentlyBoundTexture) {
NSLog(@"Binding texture: %d", textureToBind);
glBindTexture(GL_TEXTURE_2D, textureToBind);
}
Thought you might find this useful.
mike on April 21st, 2009
@Jamie, well found. I looked for ages for that exact command. I also assumed that it must be possible to get the currently bound texture but gave up. That is a nice find and would certainly remove the need to speak with the appDelegate :)
I’ll put that on the list of things I want to change in the code.
Thanks for the heads up on that one.
Mike
Mark Lorenz on April 26th, 2009
Mike, thank your for these fantastic tutorials!
I’m trying to extend your classes a little bit, and I ran into some trouble that I can’t figure my way out of.
I’ve loaded several Animations into an NSMutableArray (instantiated as spriteAnimation), and added a renderPoint property to the Animation class (to keep it a self contained unit in the array). Then, in the (void)renderScene method of EAGLView.m I’ve added the lines:
for (int i = 0; i<[spriteAnimation count]; i++){
[[spriteAnimation objectAtIndex:i] renderAtPoint:[[spriteAnimation objectAtIndex:i] renderPoint]];
}
Everything works great, each object of the NSMutableArray is placed on the screen, and each object will respond to a touch, if the touchBegan in it’s bounds (implemented in other code I added).
However, I would like the animation sequence to begin when the object is touched, using [Animation setRunning:YES]. And it does, but only for the last object added to the array of Animations, no matter the number of objects in the array.
I’ve checked to make sure that each object of the Animations array has all the appropriate frames, and each object does.
Also, rendering order in the renderScene method doesn’t seem to matter.
I’m at my wits end. Do you have any suggestions? I would be happy to post more code, and/or send my entire project.
Thanks again for all that you’ve given already!
mike on April 26th, 2009
Hi Mark. I’m glad your finding the tutorials useful.
I think I understand what you are trying to do, but if you could send me your project that would be a great help. Sometimes the problems can be in something which does not seem related to the problem :o)
I delete all projects people send to me once I’m done with them and no information about any project is ever passed on i.e. nothing is ever disclosed :o)
If you send it to mike@blog_domain_name.co.uk I’m happy to check it out.
Mike
Dougontour on April 27th, 2009
Hi Mike,
This has been a great learning experience for me, absolutely sensational in fact.
I am trying to better understand things and wanted to know if I wanted the game to run in landscape mode, after setting the orientation in the plist, is it simply a matter of setting in the initOpenGL method
glOrthof(-160.0f, screenBounds.size.width, -240, screenBounds.size.height, -1, 1); glRotatef(270.0f, 0.0f, 0.0f, 1.0f);
to rotate … the part i am struggling to get my head around is that the x coordinates appear to still (once this rotation is taken in) be top to bottom as apposed to the landscape length.
Am I missing something obvious and stupid here?
Thanks again for the great tutorial.
mike on April 28th, 2009
Hi Dougontour
I’m afraid that from the checking I’ve been doing that when you rotate the device, the coordinate system used by OpenGL does not change, so X still represents the portrait width of the screen and Y the height of the screen.
I’ve not done much work on this yet, although I plan to make this the subject of a tutorial, but it looks like your code will need to recognize the orientation of the phone and do its calculations for positioning on the screen based on that.
If I find another better way of approaching this problem I’ll let everyone know and I will get a tutorial up on this as soon as I can.
Glad your enjoying the tutorials :)
Mike
mike on April 28th, 2009
Hi Mark
I’ve had a look at the code you sent over and I’ve spotted the issue you are having with the animation. You have created an NSMutableArray in which you have a number of animation instances. Within the renderScene method you have a for loop which is running through each one and performing the renderArPoint method on it, which is fine.
Within the updateScene method you are only updating the very last entry you placed into the array by using the following command
[anim update:delta];
What you need to do is the same as in the renderScene method and update each animation instance in your array as follows
for (int i = 0; i < [starSpriteAnimation count]; i++){
Animation *a = [starSpriteAnimation objectAtIndex:i];
[a update:delta];
}
Give that a try and I hope it helps. You could also loop through using the following as well to reduce some of the code
for(Animation *a in starSpriteAnimation) {
[a update:delta];
}
I’m going to check out also why your dragging of the objects seems to drop them if you move quickly.
Mike
mike on April 28th, 2009
@Mark, I’ve just had a quick look at the movement problem you have been having. By commenting out the line to dispatchTouchEvent in the touchesMoved method and placing the following line in that method at the end
[touchedSprite setRenderPoint:lastTouch];
The sprite which is touched is picked up and moved around no matter what speed you move the mouse. I’ve tried this on the iPhone as well and the sprite tracks your finger without any problems.
You may have had a need for the dispatch method to be called, but by not called it the problem is removed. Not looked into why :) but hopefully that points in a general direction of where to look.
Cheers
Mike
akucsai on April 28th, 2009
Mike,
First of all, thank you for these great tutorials. The best tutorials I’ve ever seen.
I’d like to suggest a tiny modification of the update method in the Animate class. This way you save some clock cycles, and that is always nice in case you work on a platform which has limited resources.
if(!pingPong) {
if(repeat)
// If we should repeat without ping pong then just reset the current frame to 0 and carry on
currentFrame = 0;
else {
// If we are not repeating and no pingPing then set the current frame to 0 and stop the animation
running = NO;
currentFrame = 0;
}
} else {
// If we are ping ponging then change the direction and move the current frame to the
// next frame based on the direction
direction = -direction;
currentFrame += direction;
}
Keep up the great job.
Regards, Antal
mike on April 30th, 2009
Hi akucsai and thanks for the feedback. Your change does make it neater and I’ll add that to the overall project and cover the change in the next tutorial.
Input like this is much appreciated as not only does it tidy up my code :o) but also provide others reading the blog with hints and tips. As you say, writing for something like the iPhone can be a challenge given the limited resources you have and getting into the habit of optimizing anything you can is a good thing.
Thanks again
Mike
mike on May 3rd, 2009
@Jamie, just to let you know I’ve added your check for the currently bound texture to the Image class and its working nicely :o)
I’m glad I’ve got rid of the call to the app delegate as its also something that was brought up in another comment as being bad practice.
I’ve checked around and found out how to implement Singletons so that you can have a static class which can share game state and other such items. I’m going to try and cover this in another tutorial :o)
Cheers
Mike
Will on May 4th, 2009
Hi Mike,
Thanks for your earlier responses. I’m using your Animation class to animate some insects and have them flying all around the screen. It’s really quite cool! However, they’re always facing the same direction. The obvious solution is to simply use the Image class and flip the image horizontally. However, I’m using the same Animation object and just rendering it at different places so that I can have, say, 5 insects on the screen but only use the memory for one Animation object.
The solution that I’ve come up with is to have two separate animation objects – one with the insects flying in the left direction and the other with them flying in the right direction. I swap them when they’ve hit the edge of the screen and need to fly back. Do you think this is the best practice? Or maybe I should just have an Animation object for every single insect on the screen. I’m not sure what is most efficient.
Thanks again and I have to say it’s so much fun working on these game ideas now that I have some good foundation from your tutorials.
Will
mike on May 5th, 2009
Hi Will
Having a single version of the Animation is ok and you could just flip the underlying image of the animation class before you draw each animation so that the bug is facing in the right direction.
If you created multiple animation instances all pointing to the same spritesheet, then the amount of memory being used is very small and it would let you have different settings for each bug i.e. that could all be at different stages of the animation making things look more natural, rather than say having them all beating their wings in time.
Mike
uvo on May 30th, 2009
Hi Mike,
first I want to thank you for your great work. I really enjoy watching your tutorials. Very well structured and straigthforward code!
I just want to report you a bug I just found, watching your Animation Class video:
In your method “- (Frame*)getFrame:(GLuint)frameNumber”
the check for frameNumber exceeding your frames array:
if(frameNumber > [frames count]) ..
should propably be:
if(frameNumber >= [frames count]) …
because giving back the object at index [frame count] will lead to an error (frames array is zero indexed).
Maybe you already found that bug by yourself, I just saw it and couldn´t say nothing…
I am really looking forward watching your next videos.
Uli.
Dan on June 9th, 2009
Hi Mike, me again. Only just got round to watching tutorial 5 (been pretty busy).
Just a quick note, the Frame initWithImage method takes an Image* as a parameter. It then assigns it to its attribute frameImage however it does not retain it.
This would not show up as a bug due to how you originally wrote the Image class getSubImageAtPoint method as it returned an alloc’d object without autoreleasing it. As the Frame class does not take ownership either the memory would be leaked on destruction of the Frame object.
However if you made the changes I suggested in the last tutorial you would probably get random crashes in the Frame class due to the fact it dosn’t take ownership of the image object returned (which will be autoreleased). So this constructor needs updating to call [frameImage retain], and the dealloc method needs to call [frameImage release].
You have probably already picked this up when you made the changes based on my last comments but I thought I would mention it just in case.
Keep up the good work :0)
Cheers,
Dan
mike on June 9th, 2009
Hi Dan and thanks again for the info. Its good to have someone keeping an eye on these things as they are easy to miss with everything else going on :o)
I’m sure I did make that change as I was getting some crashes, but I’ll check the source later just to make sure.
Keep these updates coming as it makes for much more stable code which is always good :)
Mike
Ian (Naraxis) on July 14th, 2009
Hi Mike,
Firstly, thanks for taking the time to create all this tutorials, it’s really great.
I just want to ask if anyone ever occur this problem that there isn’t any image rendering onto the screen when using the Animation and Frame class?
My spritesheet class works and it is rendering image onto the screen, but when I follow the tutorial on creating the animation and frame class, nothing is being drawn onto the screen even though the image from ‘ss’ object is still on the screen.
It’ll be great if anyone has encounter such problem and have a solution to it.
I’m using SDK and simulator 3.0, I’ve check against my Frame and Animation class, exactly the same code, but my isn’t rendering out any images but the Project from Mike is working.
Sorry if my question might sounds quite beginner. =)
mike on July 14th, 2009
Hi Ian
Off the top of my head I am not sure what the problem could be. Its hard to pinpoint these things without being able to see the code. Is there anything you can email to me and I’ll check it out.
Mike
Ian (Naraxis) on July 14th, 2009
I understand, sorry, compiling a zip file of my project and sending to your inbox. mike@71squared.co.uk? or mike@blog_domain_name.co.uk(which doesn’t recognise in my hotmail) ^^
amazium on July 21st, 2009
Hi,
Thanks again for the great tutorials.
Is there a way to define the background blend color of the sprite sheet? I’ve seen spritesheets (via charas-project.net) which use a green or yellow background depending on the colors used in the sprite. I was wondering how you could specify this so that you can load them and get rid of the green background.
Thanks for your advice!
Jeroen
amazium on July 21st, 2009
This is an example spritesheet regarding my earlier post:
http://charas-project.net/reso.....912646.png
Tnx
Jeroen
Mike on July 21st, 2009
@amazium, I am nit sure that there is a way to set the color which should be transparent. The only way I can think of doing it is to set the background to transparent is a graphics tool before using it in OpenGL.
I’ve not seen another way of doing this yet.
Mike
amazium on July 22nd, 2009
I ended up doing that last night and it did the trick. It’s no biggy to do that in Photoshop, so I guess I’ll stick with that.
Tnx!
Jeroen
nick on September 11th, 2009
@amazim
Check out Paint.net…free. I create png files and set the transparency there. But, when you port to other games systems not so well. to control the transparent color see this http://nehe.gamedev.net/data/l.....?lesson=08
glColor4f(1.0f,1.0f,1.0f,0.5f); // Full Brightness, 50% Alpha ( NEW )
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Blending Function For Translucency Based On Source Alpha Value ( NEW )
What this allows you to do is set the alpha values for specific colors. If your into old style mario collision detection you can assign a color with 0.0 alpha and test for that color. I don’t recommend this. Ray collisions should be used
@mike :
I used to use the Texture2D class but it’s really not needed. I am currently creating a map editor that allows you to assign different sprite sheets to multiple levels via xml. It’s only available in windows for the time being.
http://sourceforge.net/projects/netmapeditor/
I plan on allowing multiple dimensions of sprites on spritesheets.
I’m using it for my maze game as an example. I plan allow the user to drag the dimensions and port it to the web for all to use.
If anyone has likes it, send requests and I’ll do my best to add them in..it’s about 90% done. Has unlimited map sizes and sprite sheets. You can assign a different spritesheet for each level in your game.
nFieldFlyGuy on September 30th, 2009
Another great tutorial, Mike. Thanks! Have a Cup of Java on me….
Mark
mike on September 30th, 2009
Hi nick
Sorry for the late response, I missed our post :(
Your map editor sounds really interesting. I’m about to head to Australia for a couple of weeks and I’ll try to check it out while I’m on holiday :o). Thanks for sharing.
@nFieldFlyGuy, thanks for the kind comment and the coffee….with the hours I’m burning on the book the coffee is a real saviour :o)
Mike
Sergiu on October 8th, 2009
Hi mike,
Another great video. Just wanted to say, that as a good practice it seems better to have definitions in 1 header and import that, or use @class Image, Animation; instead of importing in the .h file all headers. And do the imports in the .m files of the project just to keep the headers as clean as possible.
Thx again for the great vid.
ben on October 23rd, 2009
I have a small recommendation for the “update” method in the Animation class. In your code you are resetting the frameTimer to zero each time it exceeds the frame delay. Wouldn’t it be better to subtract the frame delay value from frameTimer instead? That way the “extra” time will be counted towards the next frame which I *think* would yield more consistent timing for the animation. Otherwise, in most cases each frame will last just a little longer than it should. This would probably never be an issue, but if you were trying to synchronize an animation with a music or a real time clock, it would get out of sync quite easily (especially for looped animations).
Please note that I haven’t done any tests, it’s just something that ocured to me while watching the video tutorial.
Great tutorials by the way!
mike on October 26th, 2009
Hi ben, thanks for the feedback. That is actually a good idea and will produce a consistent animation speed. I’ve change my current code to reflect your suggestion and its working well :o)
If you think of anything just let me know.
Thanks
Mike
mike on October 26th, 2009
Hi Sergiu, you are absolutely right about not importing the headers all the time. For the code I’m putting into the book I am actually using forward declarations i.e. @class rather than importing everything in the .h file. I should have done this in the tutorials but it was one of those jobs I never got around to.
I appreciate the feedback.
Thanks
Mike
Jonathan on November 24th, 2009
I haven’t caught up to all the videos so excuse me if this has been addressed. This video and the code have inspired a question.
I was wondering what the concensus, feedback would be towards all elements (image, fonts, actors, etc…) drawn on screen being a subclass of a common type for example something called viewelement and then implementing an animationmanager that acceps an animation enum that describes common types of animations (color filter changes, movement changes) and an array of viewelements. It would add some overhead but could provide a command pattern approach to animating objects.
Rob Jones on January 19th, 2010
I just want to drop a note on here about an animation problem I was seeing in my own code. On the newest 32G iPod Touch I was getting a lot of flickering. It turned out that the kEAGLDrawablePropertyRetainedBacking key in the CAEAGLLayer’s drawableProperties ivar needed to be set to YES. Essentially this prevents the contents of your layer from being changed. More details can be found elsewhere.
I just want to share on this forum because the tutorials and reader comments have been immensely helpful to me.
mike on January 19th, 2010
Hey Rob, thanks for the heads up. Its interesting as in the Apple docs they have said that you should not set it to YES but keep it NO for performance reasons. I shall have to do some reading :o)
Mike
Rob Jones on January 19th, 2010
Hey Mike, it was a bit of a surprise to me too. I don’t feel like I fully understand the implications of this. If you come across more details I’d like to see them. I’m looking into it as well.
I can tell you that the performance hit for my game is marginal on the iPhone 3G, and completely irrelevant on the 32G iPod Touch.
mike on January 19th, 2010
OK. Looking in the docs I get this
The key specifying whether the drawable surface retains its contents after displaying them. The value for this key is an NSNumber object containing a BOOL data type. If NO, you may not rely on the contents being the same after the contents are displayed. If YES, then the contents will not change after being displayed. Setting the value to YES is recommended only when you need the content to remain unchanged, as using it can result in both reduced performance and additional memory usage. The default value is NO.
I’ve always gone with the default which is NO. I’m not sure why retaining the contents of the surface would stop you getting flickering. It sounds like your symptom is fixed, but that may not have been the cause.
Is there any way you can share the kind of issue you were seeing in more detail?
Mike
Rob Jones on January 19th, 2010
Mike, I’m working on a minimal case that exhibits this behavior. As you can imagine, I need to remove a lot of code to get to there. I would be happy to shoot off a minimal project to you when I get it put together.
I think your point is valid, which is why I say I don’t feel like I truly understand the implications of this change. Heck, I may not understand some of my own code. That’s happened before.:)
You’re probably right. Perhaps I have just treated the symptom.
mike on January 19th, 2010
LOL, you are not alone. If I had a pound for every time I read my own code and was not sure it was doing, I’d be a wealthy man :o)
Mike
Rob Jones on January 19th, 2010
Mike. You are the man! You pushed me to keep digging on this, and I really feel like I understand my issue now. Long story short:
I have a method that renders all objects. However, it only does this if there is at least one object that needs to be rendered. If not, it does nothing. This method did not return whether or not anything was rendered, so the calling method did not know how to behave.
The calling method is the responsible for binding the frameBuffer and renderBuffer and calling presentRenderBuffer. So, there were times when the screen did not need to be updated, and I was still calling glBindRenderBufferOES and presentRenderbuffer. Whoops! Enter annoying screen flicker. As you suggested, setting kEAGLDrawablePropertyRetainedBacking was only a band-aid.
My FPS is now clamped nicely to 30, which is what I expect. Instruments confirms this. I feel better.
mike on January 19th, 2010
That is great. Nothing worse than not being able to get to the bottom of something. Nice job :o)
Mike
minh on January 20th, 2010
Great tutorials Mike.
I just want to say thank you. I’m learning so much.
Christophe on February 6th, 2010
Hi Mike,
Your tutorials are of great help, keep up the good work!
I noticed a small detail, then in the comments saw that Akucsai already commented on it. His comment is basically what I wanted to comment, but I’d like to add mine as well as the structure is a lot clearer (imo).
if (pingpong) {
// when pingpong is true
direction = -direction;
currentFrame += direction;
} else if (repeat) {
// when pingpong is false and repeat is true
currentFrame = 0;
} else {
// when both pingpong as repeat are false
running = NO;
currentFrame = 0;
}
As I mentioned before, this is about the same change as mentioned before, but using the “else if” statement, it reads a lot easier.
Christophe
Christophe on February 6th, 2010
I forgot to ask something. Regarding the frameTimer:
It would seem to me that zeroing the frameTimer after updating the animation with the next frame seems wrong. On top of that, just doing a check if the frameTimer is bigger than delta, also rubs me the wrong way.
(Ok, did a quick search as I was writing this to see if this wasn’t already mentioned, and it seems ben already commented on zeroing the frameTimer. So I will just talk about my second comment.)
If you merely check that frameTimer is bigger than your current frame’s frameDelay, you’re not taking into account that for some reason your system may have slowed down for enough time to have gone by to skip one or more frames. For example, if every frame in your animation has a frameDelay of 1, then if for some reason your frameTimer is bigger than 2, you actually have to advance your currentFrame twice, instead of just once. Not taking this into account will also cause your animation to become out of sync.
Of course, if frames in your animation have different frameDelays, this makes the code required to fix this a little trickier. However, changing your if statement to a while statement should fix this elegantly.
This should do it:
while (frameTimer > [[frames objectAtIndex:currentFrame] frameDelay]) {
// rest of your code, making sure to reduce your frameTimer
// and increment (or decrement) your currentFrame, or you’re
// stuck in an infinite loop
}
Cheers!
Christophe on February 6th, 2010
Sorry to post 3 consecutive comments :) I tend to hit Submit too fast.
I just realized, upon rereading my previous comment, that the error I pointed out would not cause an out of sync animation, since substracting frameDelay from frameTimer would fix that in the long run. However, my code fix will take care of these skipping frames immediately, instead of doing it in the next pass(-es) through the update function. Which means a render has taken place unnecessarily in the mean time (a render of a frame that should have been skipped).
Christophe
PS: I promise, no more comments after this one ;)
Christophe on February 7th, 2010
Breaking my promise, but I noticed an error which is causing an infinite loop.
In EAGLView.m, mainGameLoop, you are setting delta to be (time – lastTime) * 1000
However, you did not initialize lastTime with the current time, so it defaults to 0. This gives you an initial delta of gargantuan size, which would cause my while loop from the previous comment to run for a very long time. Set lastTime to the current time in initGame, and it’s solved. With the while loop in place and substracting the frameDelay from the frameTimer inside there, I have a perfectly sync’d animation running as I’m writing this.
Christophe
mike on February 7th, 2010
Hi Christophe, you carry on posting :O) it is readers of this blog providing feedback that make the site so useful and allows me to fix stuff I’d not spotted ;o)
The problems you have pointed out are ones which have been seen before, but its good to get a new view on them. In later tutorials the bug of not initializing lastTime is fixed to stop those HUGE numbers. The animation loop also has some changed as well.
I must admit that in practice in game the syncing or skipping is not at all noticeable and hence I never went back and worked on it any more. That doesn’t make your suggestions invalid though and I will look at putting them in my new code.
Thanks again for the feedback and keep it coming :o)
Mike
Simoin on February 7th, 2010
Hi Mike,
As you’ve gone on developing your game – beyond the current set of tutorials. Have you noticed a memory leak in the Image clase. As it looks like i get a leak here
// Init texture and vertex arrays
int totalQuads = 1;
textureCoordinates = calloc( totalQuads, sizeof( Quad2f ) );
vertices = calloc( totalQuads, sizeof( Quad2f ) );
indices = calloc( totalQuads * 6, sizeof( GLushort ) );
and ideas the code is from the Image classs initImplementation
Thanks
Boss on February 7th, 2010
maybe you are not deallocating it properly?
mike on February 7th, 2010
Hi Simoin
I had noticed a leak in the past in this class, but it always seemed to be a false positive. The items you have highlighted in your comment are all deallocated when the image is deallocated. I think instruments is picking up the allocation but then not seeing the deallocation and is marking the memory as leaked. I’ve not tested this theory extensively and I’m happy to be pointed at any leaks that may exist :o)
Mike
mike on February 7th, 2010
Hi Simoin
I just checked and I noticed a really stupid mistake in the Image.m file. There is no dealloc method. The following code needs to be added to make sure that what is allocated is deallocated when an Image instance is released.
- (void)dealloc {
if(texture)
[texture release];
if(texCoords)
free(texCoords);
if(vertices)
free(vertices);
if(indices)
free(indices);
[super dealloc];
}
I am going to run through the old tutorial code and make some changes to make sure this is included as it is really important.
Mike
mike on February 7th, 2010
OK, been through all the tutorial code and made sure the dealloc method is included plus a number of other little fixes. Poor show on my part that I didn’t have that in there, still, added now and the new code with the book is MUCH cleaner :o)
Mike
Simon on February 7th, 2010
Mike & Boss,
I have the dealloc. So it’s not that.
Thanks for looking, if you have any other suggestions let me know.
Thanks
mike on February 7th, 2010
Are there any other details you can provide on the leak itself, maybe a screen shot of instruments?
Mike
Simon on February 7th, 2010
Hi Mike,
I’d be only more than happy to where would you like me to send it : )
I second set of eyes would be helpful.
Simon on February 7th, 2010
Hi Mike,
I’m e-mailing it to you now.
Simon on February 21st, 2010
I want the animation, when set to running and not repeating to end on the last frame and not revert to the first.
Any pointers?
Thanks
Simon on February 21st, 2010
I think I’m going to have to re-write the animation method to get it to do what I want as I thinking i’m going to need more control than is provided in the current class.
Simon on February 21st, 2010
Hi Mike,
Sometimes the answer to a question is so obvious that you miss it. Must be the alzheimers kicking in.
Just needed to check if the animation was running lmao now + feeling a little slow.
Jason on March 9th, 2010
HI Mike,
Love the tutorials and am looking forward to buying your book!
I have taken the tutorial 5 code and made it so that glView is loaded by a glViewController that is loaded by a RootViewController that is loaded by the AppDelegate. The only thing I had to change in your code was the reference to the AppDelegate and the currentTexture variable which I put in my glViewController class. I call:
[glView performSelectorOnMainThread:@selector(mainGameLoop) withObject:nil waitUntilDone:NO];
from the glViewController.
When I run the app everything works great except that the animation is referencing the wrong sprite sheet. Instead of animating the explosion it is animating a small piece of the font texture the same size as the explosion.
What I have found is that if:
[font1 drawStringAt:CGPointMake(messageX, 200) text:message];
immediately precedes:
[anim renderAtPoint:CGPointMake(160, 200)];
Then I always have this problem. However if I put any other render call between the two, or if I call the font after the anim one then the problem goes away and the animation uses the correct sprite sheet.
I have built this app twice to make sure I wasn’t accidentally changing any of your code. I have no warnings and no errors.
Can you think of any reason for this strange behaviour?
mike on March 9th, 2010
Hi Jason, it sounds as though the font texture once bound is still being used for the animation, rather than the animation binding its own texture. Have you checked to make sure that the Animation code actually binds to the right texture?
Are you caching the texture number and checking to see if its changed maybe before changing it. It certainly sounds like a texture binding issue.
Let me know what you find. If you can’t see the problem and can send the project I’ll try to take a look.
Mike
DonnaLea on April 1st, 2010
Hi Mike,
I’m having the same issue as Jason. And from what I can see, it is a binding issue. I think the reason is because in the Image renderAt method it is checking to see if the texture is already bound using your if statement:
[appDelegate setCurrentTexture:[texture name]];
glBindTexture(GL_TEXTURE_2D, [texture name]);
}
And then we jump to the font rendering for rendering the font, which just binds without checking if the texture is already bound as so:
and then when it goes back to the animation it uses the image render code, and according to the appdelegate, that texture is already bound, so it skips the binding step, except that when we did the font rendering, it changed the binding without telling the app delegate.
What I can’t figure out, is how come the code downloaded from the tutorial works, cos it has that flaw in it :P Cos in my code which I’ve been changing as I follow the tutorial video it doesn’t work with that flaw in it…. so I’ve missed something somewhere.
Cheers,
Donna
Danegraphics on April 5th, 2010
I’m having problems defining a class. everything builds correctly but my init doesn’t appear to assign anything a value.
Here’s my *.h file:
———————-
#import
#include
@interface Progression : NSObject {
float currentValue;
BOOL doesLoop;
float loopBegin;
float loopEnd;
}
@property (nonatomic)float currentValue;
@property (nonatomic)BOOL doesLoop;
@property (nonatomic)float loopBegin;
@property (nonatomic)float loopEnd;
-(id)initWithValue:(float)value doesLoop:(BOOL)loop loopBegin:(float)loopB loopEnd:(float)loopE;
-(void)progressBy:(float)value;
@end
———————–
and my *.m file:
———————–
#import “Progression.h”
@implementation Progression
@synthesize currentValue;
@synthesize doesLoop;
@synthesize loopBegin;
@synthesize loopEnd;
-(id)init {
self = [super init];
if(self != nil) {
currentValue = 0;
doesLoop = NO;
loopBegin = 0;
loopEnd = 1;
}
return self;
}
-(id)initWithValue:(float)value doesLoop:(BOOL)loop loopBegin:(float)loopB loopEnd:(float)loopE {
self = [super init];
if(self != nil) {
currentValue = value;
doesLoop = loop;
loopBegin = loopB;
loopEnd = loopE;
}
return self;
}
-(void)progressBy:(float)value {
currentValue = currentValue + value;
if(currentValue > loopEnd) {
currentValue = loopBegin + fmod(currentValue,loopEnd);
}
}
@end
——————–
Please help.
Danegraphics on April 5th, 2010
sorry, the import and include are this:
#import Foundation/Foundation.h
#include math.h
Danegraphics on April 5th, 2010
Nevermind. I was incorrectly using delta.
rob on April 11th, 2010
Thanks Mike for the great tutorials! I am totally new to iPhone development and OpenGL ES and really appreciate being able to follow along and see how this works… I am doing something really simple (i think!) … I just want to animate a figure running… 1 cycle in a continuous loop – i’m thinking 60 frames – just looping through in one spot (character is not running across the screen). I got your animations to work fine (16x16px) BUT when i replace with my spritesheet character which is 320x320px the character doesn’t appear at that size but rather about 4 small figures appear – they DO animate but why are they tiny and more than 1? (my scale factor is set at 1)… any ideas would be appreciated – is it to do with a texture altas file needing to be created at “power of 2″? … don’t quite understand that concept.
many thanks again, rob
Tweets that mention iPhone Game Programming – Tutorial 5 – Animation Class | 71² - The ramblings of two 30-something developers -- Topsy.com on April 25th, 2010
[...] This post was mentioned on Twitter by onion_papa. onion_papa said: http://tinyurl.com/29mbqpy iPhone Game Programming – Tutorial 5 – Animation Class | 71² – The … (WWW.71SQUARED.COM) [...]
Lakshmikanth Reddy on September 2nd, 2010
Mike,
Your tutorials are really great and gives more knowledge with very simple examples and crystal clear explanation, thats great work, keep up my frnd Mike, your are doing great job, i have started looking at all your videos and continuing it.
Thank you,
Lakshmikanth
Jiaren on October 1st, 2010
Hi Mike,
Thank you for your great job! I’ve learned a lot from your tutorials!
iPhone Game Programming Tutorial 1 | Hardblog Cafe on October 6th, 2010
[...] iphone-game-programming-tutorial-4-bitmap-font-class iphone-game-programming-tutorial-5-animation-cl… iphone-game-programming-tutorial-6-tiled-map-class iphone-game-programming-tutorial-7-singleton-class iphone-game-programming-tutorial-8-particle-emitter iphone-game-programming-tutorial-9-sound-manager iphone-game-programming-tutorial-10-game-structure iphone-game-programming-tutorial-11-joypad iphone-game-programming-tutorial-12-saving-state tutorial-13-app-store-submission AKPC_IDS += "1124,";Popularity: unranked [?] [...]
jc on November 3rd, 2010
hey mike I’ve been following your tutorials and reading the comments as well here in the forums.
I noticed that Dan pointed out that there are memory leaks inside the image class. When I tested it out, there was really a memory leak. What I tried doing was having a button that changes animations. Each time a button is pressed an animation will be started and once it finishes, it is then released and a new one will be allocated. Each time this happens there is a memory leak and I traced it back to the image class.
I tried the remedy he suggested by retaining the Image in both the frame class and the spritesheet class. After which I release them in the dealloc method. Also, I placed an autorelease on the subImage that is being passed on the image class. However, once I put the autorelease on the Image class, I get an error EXC_BAD_ACCESS.
Any suggestions on what I should do?
Thanks in advance and more power! I love the way you explain things it really helps beginners like me a lot!
Carlo on February 28th, 2011
A really interesting work!
I found this tutorial really useful.
I wonder if I can use some of your code for my iPhone App…
I didn’t find any copyright notice …
IlyaK on May 20th, 2011
Hi Mike,
I’m having the same problem as the people you responded to about a year ago:
“mike on March 9th, 2010
Hi Jason, it sounds as though the font texture once bound is still being used for the animation, rather than the animation binding its own texture. Have you checked to make sure that the Animation code actually binds to the right texture?
Are you caching the texture number and checking to see if its changed maybe before changing it. It certainly sounds like a texture binding issue.
Let me know what you find. If you can’t see the problem and can send the project I’ll try to take a look.
Mike”
Did you guys ever figure out what the problem was? I’ve been scanning my code and I can’t seem to figure out why this is happening.
Thank you,
Ilya
IlyaK on May 20th, 2011
Hi Mike,
Once again, never mind, problem solved.
I just had to copy some of the code in RenderAt in Image to the render method in AngelCodeFont (and add the appDelegate to the class, etc).
You rule.
Thank you,
Ilya





Allan on April 19th, 2009
Hi,
you made a little mistake with your intro…
its 71squared.co.uk not 71squared.couk you missed one dot ;)
regards
Allan