Time to add another project to my github repository. This time I’m answering the frequently asked question (in some form or another) how to zoom in on a particular node. For example zooming in on the player when he dies.
That’s not as trivial as it sounds, but you can make it easy if you follow some guidelines.
First, you want to put all nodes that should be affected by the zoom in the same layer. Then you should avoid changing the position or anchorpoint of the layer - if you still want to change the position of the layer I suggest to add this layer into another, toplevel layer and then only change the position of the toplevel layer. Use the cocos2d node hierarchy to your advantage. And don’t use the CCCamera.
The behavior of this example project is best observed with your own eyes. You can get the ZoomInOnMe project on github.
I’m now hosting an unofficial Cocos2D (for iOS & Mac OS) API Reference, accessible via the Knowledge Base tab.
What’s so “unofficial” about it?
My version of the API reference includes previously undocumented classes, some are documented but just not in the official documentation, others are completely undocumented but at least now you know they’re there. Currently, there is no additional documentation added other than what’s in the official cocos2d source code files, and as far as I can tell nothing is missing. If there is, please let me know.
Since at least the release of v0.99.5 about a month ago important classes like CCLayer, CCArray and CCDirectorIOS have been missing from the official API reference. Did anyone even take notice, or was it just me? I hope it will be fixed soon and the missing classes added back to the official API reference.
I’d like to call it “unofficial” just to make sure everyone gets the idea that I’m not involved in the development of Cocos2D in any way, and my version of the API reference may contain crucial omissions or mistakes as well.
Angry Birds Tutorial causes slowdown
Current and well-deserved cause of the cocos2d-iphone.org slowdown is the SpaceManager Game Tutorial with source code by the mobile bros. LLC. The tutorial shows you how to make an Angry Birds style of game.
Todays link is one that I came across recently and I believe you’ll find that very helpful. Simon Skinner (@vultuk) wrote a blog post and published the source code for his implementation of a UIScrollView-like page scrolling layer implemented with Cocos2D. It behaves similar to browsing photos in the Photo application, with snapping and bouncing and all that. See this video:
Read Simon’s article on the Debug, Design, Assemble, Play (DK101) blog and grab the source code here: Implementing Page Scrolling in Cocos2D
Add your link to the Cocos2D Linkvent Calendar
Do you have something to share with the Cocos2D community? I haven’t received enough submissions to fill all the days until Xmas, although I do have enough links to post one each day, I’d rather post a link to your website or blog post.
While helping others solve their cocos2d project issues over the past year it became obvious that many projects have at least one major problem in one of these areas:
- memory management
- resource management
- code structure
Examples
Memory management issues normally range from allocating too much memory, either by loading too many textures up front which are only going to be needed later, or by memory leaks such as scenes not deallocating when switching scenes. Resource management problems range from not adding the right resources to the right target, often resulting in increased App size because resources are added to the bundle but never used by the App. It could also mean loading identical resource files except that they have different filenames (copies?), using up additional memory. Or not tightly packing sprites into Texture Atlases but instead using one Texture Atlas per game object - while this is understandable from a standpoint of logical seperation it does waste opportunities for optimization.
Finally, code structure or lack thereof regularly leads to “everything in one class” code design which is most likely an evolutionary process rather than intentional. It’s not uncommon to see classes with thousands of lines of code, sometimes even going past 10,000 lines of code in one class. Other things are using too many CCLayers without them adding a clear benefit, for example just to group all nodes at a specific z order together or to group them by functionality, eg one layer for enemies, one for players, one for background, one for UI, one for score, one for particle effects, and so on - without any of these layers being used for what they’re really good at: modifying multiple nodes at once, like moving, scaling, rotating or z-reordering them. And of course there’s the copy & paste hell, large blocks of code reproduced in various places only to modify some parameters instead of creating a method which takes the modifiable parameters as arguments. Even professionals I worked with got so used to doing that it became hard just to overcome the resistance of letting go of old habits. But they learned.
Summary
Nothing of this code design and structuring strikes me as odd or surprising. I’ve written code like this myself. I also believe if it’s good enough and works, then why the hell not? It’s a matter of experience and it’s only with experience that you clearly see how to improve things. This boils down to the regular learning curve where only training and tutoring and just simply making mistakes and learning from them helps in the long run. That’s how we learn things.
On the other hand, the things like Memory and Resource Management can also be learned but they have a different nature. They can be statistically assessed, they could be calculated and verified automatically. This makes me wonder if there isn’t some kind of automation and information tools that would help developers achieve better results in terms of memory usage and resource management? In the meantime it’s all about raising awareness …
Raising Memory Awareness
Most importantly I think we need to raise more awareness to these issues to cocos2d developers. One step towards that would be for cocos2d to display a “available memory counter” alongside the FPS counter. I used to patch CCDirector to simply display memory instead of FPS since that was always more important to me. Fellow cocos2d developer Joseph sent me his version to display both - I simply didn’t think of the obvious. So if you’d like to see FPS and available memory next to each other I think you can handle the changes to CCDirector outlined here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
// CCDirector.h, add below @interface: +(double) getAvailableBytes; +(double) getAvailableKiloBytes; +(double) getAvailableMegaBytes; // CCDirector.m, add as appropriate: #include <sys/sysctl.h> #import <mach/mach.h> #import <mach/mach_host.h> [...] +(double) getAvailableBytes { vm_statistics_data_t vmStats; mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT; kern_return_t kernReturn = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmStats, &infoCount); if (kernReturn != KERN_SUCCESS) { return NSNotFound; } return (vm_page_size * vmStats.free_count); } +(double) getAvailableKiloBytes { return [CCDirector getAvailableBytes] / 1024.0; } +(double) getAvailableMegaBytes { return [CCDirector getAvailableKiloBytes] / 1024.0; } [...] -(void) showFPS { frames++; accumDt += dt; if ( accumDt > CC_DIRECTOR_FPS_INTERVAL) { frameRate = frames/accumDt; frames = 0; accumDt = 0; // the only change in showFPS is this line: NSString *str = [[NSString alloc] initWithFormat:@"%.1f %.1f", frameRate, [CCDirector getAvailableMegaBytes]]; [FPSLabel setString:str]; [str release]; } } |
Raising awareness to leaking Scenes
In addition I highly, strongly and with utmost reinforcement (without pulling out a gun) recommend to cocos2d developers to frequently check your scene’s dealloc methods. Preferably add a breakpoint there, or at the very least add the logging line: CCLOG(@”dealloc: %@”, self). If you want a more visible but less intrusive method you could do something like flashing the screen or playing a sound whenever the last scene is deallocated, so that you get so used to it that when you’re not seeing or hearing it anymore it immediately raises your attention.
If at any time during the development of your project the dealloc method of a scene isn’t called when you change scenes, you’re leaking memory. Leaking the whole scene is a memory leak of the worst kind. You want to catch that early while you can still retrace your steps that might have caused the problem. Once you get to using hundreds of assets and thousands of lines of code and then realize the scene isn’t deallocated, you’ll be in for a fun ride trying to figure out where that’s coming from. In that case, removing nodes by uncommenting them until you can close in on the culprit is probably the best strategy, next to using Instruments (which I haven’t found too helpful in those cases).
I ran into such a problem once because I was passing the CCScene object to subclasses so that they have access to the scene’s methods. The subclass retained the scene and was itself derived from CCNode and added to the CCScene as child. The problem with that: during cleanup of the scene it correctly removed all child nodes but some of the child nodes still retained the scene. Because of that their dealloc method was never called, and in turn the scene was never deallocated.