Performance Gain Using Multiple CALayers in One UIVew - iphone

I'm in the process of writing a simple 2D game which at present does a fair bit of custom drawing for multiple sprites upon each update - i.e. I have game view that delegates to all sprites to perform quartz rendering (point/line based) upon each update.
My performance is ok upto around 50 active objects being rendered but now things are starting to slow down so I'm looking to optimize. To do so I've decided to pre-render my sprites to a CALayer then add that to the game view.
My first thought was to give each Sprite instance a CALayer which is added to the GameView's view.layer as sublayer. This would mean that I use a single UIView which has multiple CALayers - one per game sprite.
Would there be a negligible performance loss if I decided to use a UIView for each game sprite?

UIViews are part of the responder chain and will add extra overhead. I started with UIViews for sprites and found gestures became sluggish.
I would recommend sticking with CALayers

As far as I know, UIViews are pretty lightweight wrappers around CALayer, so the performance loss shouldn't be too big. But I think a sprite would simply be better represented by an instance of CALayer rather than UIView.

Related

SpriteKit where to load texture atlases for thousands of sprites

In my game I have thousands of "tile" nodes which make up a game map (think simcity), I am wondering what the most frame-rate/memory efficient route for texturing and animating each node would be? There a a handful of unique tile "types" which each have their own texture atlas / animations, so making sure textures are being reused when possible is key.
All my tile nodes are children of a single map node, should the map node handle recognising a tile type and loading the necessary atlas & animations (e.g. by loading texture & atlas names from a plist?)
Alternatively, each tile type is a certain subclass. Would it be better for each SKSpriteNode tile to handle their own sprite atlas loading e.g. [tileInstance texturise]; (how does sprite kit handle this? would this method result in the same texture atlas being loaded into memory for each instance of a certain tile type?)
I have been scrounging the docs for a deeper explanation of atlases and texture reusage but I don't know what the typical procedure is for a scenario like this. Any help would be appreciated, thanks.
Memory first: there won't be any noticeable difference. You have to load the tile's textures, textures will account for at least 99% of the memory of the Map+Tiles and that's that.
Texture reuse: textures are being reused/cached automatically. Two sprites using the same texture will reference the same texture rather than each having its own copy of the texture.
Framerate/Batching: this is all about batching properly. Sprite Kit approaches batching children of a node by rendering them in the order they are added to the children array. As long as the next child node uses the same texture as the previous one, they will all be batched into one draw call. Possibly the worst thing you could do is to add a sprite, a label, a sprite, a label and so on. You'll want to add as many sprites using the same texture in consecutive order as is possible.
Atlas Usage: here's where you can win the most. Commonly developers try to categorize their atlases, which is the wrong way to go about it. Instead of creating one atlas per tile (and its animations), you'll want to create as few texture atlases as possible, each containing as many tiles as possible. On all iOS 7 devices a texture atlas can be 2048x2048 and with the exception of iPhone 4 and iPad 1 all other devices can use textures with up to 4096x4096 pixels.
There are exceptions to this rule, say if you have such a large amount of textures that you can't possibly load them all at once into memory on all devices. In that case use your best judgement to find a good compromise on memory usage vs batching efficiency. For example one solution might be to create one or two texture atlases per each unique scene or rather "scenery" even if that means duplicating some tiles in other texture atlases for another scene. If you have tiles that almost always appear in any scenery it would make sense to put those in a "shared" atlas.
As for subclassing tiles, I'm a strong proponent to avoid subclassing node classes. Especially if the main reason to subclass them is to merely change which texture they are using/animating. A sprite already is a container of a texture, so you can as well change the sprite texture and animate it from the outside.
To add data or additional code to a node you can peruse its userData property by creating your own NSMutableDictionary and adding any object you need to it. A typical component-based approach would go like this:
SKSpriteNode* sprite = [SKSpriteNode spriteWithWhatever..];
[self addChild:sprite];
// create the controller object
sprite.userData = [NSMutableDictionary dictionary];
MyTileController* controller = [MyTileController controllerWithSprite:sprite];
[sprite.userData setObject: forKey:#"controller"];
This controller object then performs any custom code needed for your tiles. It could be animating the tile and whatever else. The only important bit is to make the reference to the owning node (here: sprite) a weak reference:
#interface MySpriteController
#property (weak) sprite; // weak is important to avoid retain cycle!
#end
Because the sprite retains the dictionary. The dictionary retains the controller. If the controller would retain the sprite, the sprite couldn't deallocate because there would still be a retaining reference to it - hence it will continue to retain the dictionary which retains the controller which retains the sprite.
The advantages of using a component-based approach (also favored by and implemented in Kobold Kit):
If properly engineered, works with any or multiple nodes. If what if some day you want a label, effect, shape node tile?
You don't need a subclass for every tile. Some tiles may be simple static sprites. So use simple static SKSpriteNode for those.
It lets you start/stop or add/remove individual aspects as needed. Even on tiles you didn't initially expect to have or need a certain aspect.
Components allow you to build a repertoire of functionality you're going to need often and possibly even in other projects.
Components make for better architecture. A classical OOP design mistake is to have Player and Enemy classes, then realize both need to be able to shoot arrows and equip armor. So you move the code to the root GameObject class, making the code available to all subclasses. With components you simply have an equipment and a shooting component add to those objects that need it.
The great benefit of component-based design is that you start developing individual aspects separately from other things, so they can be reused and added as needed. You'll almost naturally write better code because you approach things with a different mindset.
And from my own experience, once you modularize a game into components you get far fewer bugs and they're easier to solve because you don't have to look at or consider other component's code - unless used by a component but even then when one component triggers another you have a clear boundary, ie is the passed value still correct when the other component takes over? If not, the bug must be in the first component.
This is a good introduction on component-based design. The hybrid approach is certainly the way to go. Here are more resources on component based design but I strongly advice against straying from the path and looking into FRP as the "accepted answer's author" suggests - FRP is an interesting concept but has no real world application (yet) in game development.

May I use UIViews to manage a large number of animated sprites? Or is it better to stick with CALayers?

that' my first question here on Stack Overflow. I'm making a columns inspired game for iPhone, that's my first serious project on iphone. I chose to use CALayers to implement it, it looked like a good choice, layers are simple and don't have the unnecessay (for this purpose) gagdets of UIviews.
Sadly I just recently discovered CALayers do not yet support filters and blending options, at least not officially. I've read many questions regarding performance differences between UIViews and CALayers, but seems I can't find a clear answer.
In my game it may happen to have up to 140 non-opaque sprites (70 static sprites, each one with an animated overlay) moving on screen in certain conditions, with collisions and some physics. With CALayers performance is very good, a large number of moving sprites seems to have low impact on performance and I managed to have 30 fps in the worst case, with the bottleneck being physics.
The only thing I feel the lack of are blending effects.
At this point OpenGL is hardly an option to me. For what I've understood I'd have blending effects with UIViews, my concern is about performance, I've read UIViews should not be used with a large number of sprites, especially if updating is frequent as is in my case.
Could it be worth a try? Any suggestion to add effects on layers?

Combining UIView animation blocks and OpenGL ES rendering

I am developing an iP* game and I make use of both UIKit and OpenGL ES 2.0. The UIKit elements are rendered over the OpenGL view and occupy a significant (arbitrary) amount of screen space. I must admit that Apple has done an excellent work and the frame rate of the game is always 60 FPS.
In order to come to this conclusion I made many tests regarding the performance:
I added lots of static (not moving) UIViews over the OpenGL view -- OK!
I animated using custom code the same UIViews (modified the center property in the drawFrame method of my game) -- OK!.
I added many OpenGL ES elements under the UIViews -- OK!
I added many moving OpenGL ES elements under the UIViews -- OK!
So, now I want to make use of the Core Animation Framework in order to animate the UIKit elements. I make use of
[UIView animateWithDuration:delay:options:animations:completion:]
in oder to perform the animations (I target iOS 4 or newer).
The problem now is that the frame rate has this weird behavior: Sometimes I get 60 fps with many many UIKit animating elements (30 elements is OK for me) and some other times the frame rate is obviously under 60 fps even with a single animating UIKit element but I cannot measure it with Instruments! Let me explain more: When I open Instruments and monitor the core animation and/or OpenGL driver I get always 60 fps. But it is obvious that this is not the case, I can see with my eyes the OpenGL animations to move much slower than the corresponding UIKit animations on the top. If I remove the UIKit elements from the view the frame rate comes back to normal. A similar situation with the one I describe here happens in any OpenGL ES game when the user changes the volume of the device while playing the game. When the transparent view that shows the current volume starts fading out and until it completely fades away the frame rate drops drastically, but in the instruments (I ve made this test too) it is stuck on 60 fps!
So, to sum up: sometimes I get real 60 fps with block animations with no ups and downs for a run and some other times I get fake 60 fps with no ups and downs.
Do you have any solution to this?
All tests were performed on an iPad 2 and iPhone 3GS with iOS 5.1
I managed to solve the problem and now I can combine UIView block/core based animations in my OpenGL game without any performance drop.
The solution is quite simple:
For each UIView that you want in your OpenGL app, keep its bounds, center and transform properties in your OpenGL screen coordinate system (e.g. create the following properties: GLBounds, GLCenter, GLTranform) and update them accordingly whenever you change one of the corresponding UIView properties.
When you start the game, load the UIViews but set them to hidden. So, UIKit does not draw on top of the OpenGL view (this way the frame drop issue is completely elliminated).Instead draw the UIViews yourself using the GL* properties you created in step 1, and using the corresponding textures (the images/colors you used for every UIView).
Animate the hidden UIViews properties (bounds, center and transform) using block/core animation depending on the animation you want to achieve (which in turn updates your GL* properties) and in your OpenGL draw method use the GL* properties to draw the UIViews! To get the actual values for bounds, center and transform when a UIView is animating (and update the GL* properties) use its presentationLayer property.
Best,

Equivalent of -viewDidAppear for CCLayer?

Question:
In the realm of cocos2d for iPhone, what's the equivalent of UIKit's -viewDidAppear callback for CCLayer?
*And if no equivalent exists (as seems to be the case in the docs), what's your recommended way knowing when a CCLayer has been rendered?
There are these two methods which are quite similar to
- (void)onEnter;
- (void)onEnterTransitionDidFinish;
Well, a CCLayer is rendered, usually, when it is created and you add sprites to it. You should do all this up front before the game play begins. Then you can move the layer around and animate its objects without worrying about "when" it will be finished rendering (usually).
Scenes are a different matter. A scene is what sets up the layers and creates them, loads images, sprites, etc, and tha can take a bit. For that you have a few options. One effective option is the the onEnter and onExit family of methods. However, another really good way is to simply have an intermediate scene, such as a mostly empty, lean Loading CCScene that you load, and then that scene loads the big scene you are trying to load. When you do this, you are freeing up old memory before adding new memory.
It really depends on what you are trying to accomplish with your equivalent of viewDidAppear.

Animating large sprites with cocos2d (ccspritesheet)

I'm working on an iPhone game using Cocos2d where the main character is approximately 194x114.
the animation consists of 100+ frames making my spritesheets larger than the 1024x1024 limit. The obvious solution would be to separate the animation to several files and swapping spritesheets when necessary. while doable (i guess) i'm not quite sure how to go about implementing this solution, is there a better solution? what is your experience with large animation with Cocos2d?
Yes, your best bet (and only option, really) is to break up separate animations into separate files. One strategy is to create a helper class that knows which animations live in which source files and swap between them, so your main code can worry about picking the animation and not messing with specific source file names.
I suspect you may be getting confused by CCSprites being added as a child of a CCSpriteSheet. When swapping between sheets to change animations, just remove the sprite from one CCSpriteSheet and add it to the CCSpriteSheet containing the new animation.