For Kobold Kit (the Sprite Kit game engine) we’re working on Super Stick Spy, a 2D platformer game. Like so many others, we started out using the (Box2D) physics engine that’s so neatly integrated in Sprite Kit to get everything up and running quickly.
But we knew full well that for the final product, we’ll have to scrap the physics engine altogether and follow best practices when it comes to platformer-programming.
Now with the demo version nearing completion (see video) I can tell you in full detail why you don’t want to use a physics engine for a 2D platformer!
Moving Platform Hell
A moving platform with physics needs to be a dynamic body. Don’t even try moving static bodies, at least in Box2D that will end up in jumpy movement of the body. Though kinematic bodies work better (if available).
The player or other game characters standing on a moving physics body will have the platform slide underneath their feet. The characters won’t magically move along with the platform! And there is no feature in the physics engine that lets you set this up. You have to program it to synchronize character movement with the platform they’re currently standing on, and end the synchronization as soon as a character lifts its feet up from the platform.
Which can be a problem for downward-moving platforms as the player loses contact with the platform every other frame, starts falling, and lands right back on the platform. To put it in Homer’s words: “Doh, doh, doh, doh, doh, doh, doh …”. So you need to make the character stick to the platform, yet allow him to fall off of the ledges and jump, and possibly also allow him to be forced off the ground by normal collision events (projectile impact, platform moving through a tiny crevice). Continue reading »
Due to technical issues (blank page) I had to split the previous article (now focuses only on memory optimization) in two. This is the second part which (mostly) focuses on reducing the app bundle size.
Loading Assets In Sequence
Here’s the code that I use to load textures or other assets asynchronously (in background, on another thread).
Imagine loadAssetsThenGotoMainMenu being a scheduled method that runs every frame or perhaps less often. The assetLoadCount and loadingAsset variables are declared in the @interface as int and BOOL respectively.
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 |
-(void) increaseAssetLoadCount { assetLoadCount++; loadingAsset = NO; } -(void) loadAssetsThenGotoMainMenu:(ccTime)delta { NSLog(@"load assets %i", assetLoadCount); switch (assetLoadCount) { case 0: if (loadingAsset == NO) { loadingAsset = YES; NSLog(@"============= Loading home.png ==============="); [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGB5A1]; [[CCTextureCache sharedTextureCache] addImageAsync:@"home.png" target:self selector:@selector(increaseAssetLoadCount)]; } break; case 1: if (loadingAsset == NO) { loadingAsset = YES; [self performSelectorInBackground:@selector(loadSpriteFrames:) withObject:nil]; } break; // extend with more sequentially numbered cases, as needed // the default case runs last, loads the next scene default: { [self unscheduleAllSelectors]; MainMenuScene* mainMenuScene = [MainMenuScene node]; [[CCDirector sharedDirector] replaceScene:mainMenuScene]; } break; } } |
When this method runs the first case statement is executed. To avoid accidentally loading the same image multiple times every time the selector runs, the loadingAsset flag is set to YES. When the texture cache has completed loading this texture, it will call the increaseAssetLoadCount. This then ensures that the next case statement is executed the next time loadAssetsThenGotoMainMenu runs.
The cool thing about this solution is that you can easily add more switch statements to add more textures to load. Because the default case is where the scene changes, and that only happens if there are no more switch cases to process.
Be sure not to skip a number in the switch cases because that will also run the default case.
Decreasing the size of your app
Besides the memory usage advantage, reducing the color bit depth of textures to 16 bit will also significantly reduce their size. But there are other options that will allow you to reduce your app’s size, perhaps significantly.
TexturePacker PNG Optimization
If for some reason you still want to use PNG files instead of the highly recommended .pvr.ccz file format, TexturePacker has a slider named “Png Opt Level” to help reduce the size of PNGs (doesn’t affect loading time though):
As far as I understand it, it tries a given number of optimizations and picks the one that creates the smallest file size. The downside is that the maximum level can take very long for large texture atlases, in some cases 10 to 20 minutes on a Late 2009 27″ iMac. The task is multi-threaded, so it should be a lot faster on quad core systems.
Fortunately there’s really no need to do this unless you’re ready to release the app. Question is, how much can it reduce the size of PNG files? Continue reading »
I’m currently completing one last contract project. One of the last things I had to deal with was to optimize the game’s memory usage.
In today’s iDevBlogADay article I’ll explain how I was able to cut down memory usage by about 25-30 MB (down to 90-95 MB, ie fixing memory warning related crashes) as well as reducing the size of the app bundle from around 25 MB to below 20 MB (which would have been more awesome if Apple hadn’t already increased the over-the-air download limit from 20 MB to 50 MB some time ago).
I’ll also explain how to animate the loading screen while you’re loading resource files, and I’ll add some best practices and common wisdom too.
What’s using 90% of the memory?
Take a guess.
In almost all cases, it’s textures that consume most of the app’s memory. So textures is where you look to optimize first and foremost if you’re having memory warning troubles.
Avoid loading PNG/JPG Textures one after another
The problem with texture loading in cocos2d is that it happens in two steps: first, a UIImage is created from the image file. Then a CCTexture2D object is created from that UIImage. This means while a texture is being loaded, it will consume twice as much memory for a short time period.
The problem used to be so bad that if you loaded 4 textures one after another in the same method, at the end of the method each texture would still consume twice as much memory as it ought to, probably because of the way autorelease works.
I’m not sure if this is still the case, or whether this only applies to manual reference counting but not ARC. I made it a habit to load textures in sequence, waiting at least one frame before trying to load another. This will allow any texture loading overhead to be released from memory. Besides, as you’ll see later, if you want to load textures and other assets in the background this asset-load-sequencing is something you’ll do anyway.
Since I started working on KoboldTouch a couple things fell into place. Mainly that it would:
Provide what Cocos2D leaves up to its users. Fixes what Cocos2D does badly. Adds what Cocos2D doesn’t do at all. Eases development with Cocos2D and accommodates actual developer needs.
While Cocos2D is moving towards cross-platform with their Javascript API, KoboldTouch will focus on adding & improving game design features.
I have a hunch most Cocos2D developers have better iOS/Mac integration and game-specific features higher up on their wish list than cross-platform. Most of you are indies, hobbyists, pragmatists and Apple enthusiasts without the need or resources to do cross-platform development.
UPDATE: KoboldTouch is now available!
KoboldTouch: Spiritual Successor
I first started working on KoboldTouch a few weeks back. I initially undersold it as a “MVC wrapper for Cocos2D”. With what I have in mind spiritual successor of Cocos2D is more like it.
It’s going to be a framework to program iOS & Mac games in, where best practices evolve naturally, where Cocoa programmers feel right at home, where beginners are not left in a void * EXC_BAD_ACCESS … and where Cocos2D is still at the heart of it.
KoboldTouch takes control over Cocos2D, to allows users to implement best practices naturally. Cocos2D provides the view, KoboldTouch provides the controllers, models and the framework to write your code in.
![]() |
KoboldTouch brings you the best 2D game development experience for Apple’s platforms!
KoboldTouch is the only Objective-C, ARC-enabled 2D game engine built on the Model-View-Controller (MVC) design pattern. Write ambitious games with greater ease!
KoboldTouch is also a continuously evolving, customer driven game development framework for iOS & Mac OS X, designed by game industry veterans to incorporate game development best practices and decades of experience.
Learn more about KoboldTouch features and what’s in it for you:
Open the “About KoboldTouch” Page for Details
Not quite ready for KoboldTouch yet?
Fill out the KoboldTouch Survey. Let us know what you think of KT and how to make it better.
Get KoboldTouch!
KoboldTouch is available as a subscription program that entitles you to updates and support.
Choose Your Support & Updates Plan
Recurring billing may be cancelled at any time. The yearly plan is non-recurring.
Monthly
$14.95
You will be charged $14.95 every month.Quarterly
$39.95
You will be charged $39.95 every 3 months.One Year
$119.95
You will be charged $119.95 once. No automatic rebills.
60-Day Money Back Guarantee
If you’re not satisfied you can request a refund within 60-days from the date of purchase, directly via Clickbank.
Scheduled for release on November 7th, 2011. Continue reading »