You know those moments where you suddenly realize The Right Way (TM) to do something and you slap yourself on the forehead for wasting untold hours. I've had a number of those while working with cocos2d and I wish I could go back in time and reveal all those little discoveries to past me. Unfortunately, I lack access to a DeLorean or other means of time travel so I will do the best I can and write down my notes here in case any other noobs stumble across it. This will be a multi-part semi-regular series in which, in no particular order, I will reveal the wondrous errors and oversights I made on my journey to cocos2d near-competence.
Points - Do I have one?
It is hard to make a game without dealing with points, coordinates, Euclidean distance, etc. The project I am currently working on is no exception. In the beginning I created CGPoints. I saw that the CGPoints were good, and I did lots of math with them. Unfortunately, I made the mistake of breaking out x and y, typing up some basic math and littering my code with things like the distance formula. After a few instances of this, I decided that I should write up some helper functions as it was likely I would be doing these basic operations a number of times. Not long after starting my own CGPointHelper file, I was reading through some sample code and saw ccpAdd. I quickly scrambled to find the source for it and discovered this: CGPointExtension.h. Mindsplosion!
CGPointExtension is an absolute gold mine that will prevent you from writing a bunch of code that you probably can't live without. I'll go over a few of the star players, but I suggest you read through the entire header file.
ccpAdd, ccpSub - Need to add (or subtract) two points from each other? Then these are your homies.
ccpLength, ccpDistance - Determine the distance between two points. ccpLength is a double whammy giving you either the distance from the origin or the magnitude of the vector.
ccpFuzzyEqual - Are we really close enough? Checks if points are equal within a specified variance.
ccpMidPoint - Let's meet halfway. Gives you the midpoint between two points.
ccpAngle, ccpRotateByAngle, etc - There is a ton of great stuff if you need to work with angles or translate coordinates. Isn't it fantastic that someone has done all this work for you? If you aren't familiar with the underlying math, check out the source for some learnin'!
ccpLengthSq - Great for fast distance or magnitude checks. This is effectively ccpLength without the costly square root operation. Keep this one in your bag to save your FPS.
While prototyping I eventually needed to animate some sprites. I read the cocos2d docs and ended up using Zwoptex to create my spritesheets because they had an awesome free version. Free has a strong appeal. Zwoptex served me well, but I spent a lot of time maintaining both an sd and an hd version of every spritesheet. I stumbled across Ray Wenderlich's review of Texture Packer and discovered a tool that gave me everything I needed: command line interface, integration with xcode, auto-sd, saving in various pixel format modes. I bought Texture Packer and haven't looked back, the amount of time it has saved me has paid for itself a hundred times over. I'm not going to go over all the details because Ray has already done an excellent job. Read his review and then go buy it now!
Cleaning up after yourself is as important in Objective-C and cocos2d as it is in the rest of life. If you don't you will eventually be crushed under the weight of a wall for trash falling on top of you as you wander the trash filled maze you call a house. Or in our case, you end up leaking a ton of memory and your app crashes.
This isn't meant to be a introduction to memory management or an all inclusive guide. That would be an entire series of blog posts of its own. This is just a short list of things to keep in mind to help clean up after yourself.
- Use debug logging to verify that you are dealloc-ing what you need to dealloc.
- Release anything you retain. Children will be released on their own unless you retain them as well.
- In your scene's onExit call clean up touch handlers. This includes setting isTouchEnabled to NO.
- If you retain CCActions in a custom CCNode you must release them before the node's dealloc will be called.
- If you are using chipmunk, clean up your bodies and shapes if you retain them.
- Because it bears repeating: Release anything you retain.
- Don't over release or you will cause a crash.
- You can free up a lot of memory by freeing unused sprite frames and textures:
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
If you are using any scene transitions be careful cleaning up sprite frames and textures. You can run into timing issues where you remove sprite frames that were just loaded prior to using them in the new scene. This can cause a crash.
In the next installment I will go over other advice to myself that I wrote out in my dev notebook for the project. I may also go into more detail on clean up and memory management.
- This series will likely bathe in extreme overuse of the word "unfortunately". This is because I unfortunately made a number of unfortunate oversights during the initial learning period and likely continue to do so.
- There is at least one super secret hint as to what Taco Graveyard's Top Secret Project is in this post. Unfortunately, no one will ever pickup on it.