How to leverage CCSpriteBatchNode when frames are distributed into multiple textures - ios

In my game, there're plenty of enemies(subclass of CCNode) which animation frames are distributed into multiple texture files(enemy01.png, enemy02.png...) and enemies from different textures may be generated in the same scene.
I'd like to have a unified way to dynamically add a randomly generated enemy to the correct CCSpriteBatchNode, but a lookup table seems not so elegant. Is there any better way to handle it?
Thanks

Since each enemy uses its own texture, you can use one sprite batch node per enemy. So when you create enemy "X" it shouldn't be hard to get the corresponding sprite batch node from wherever you store it (perhaps an NSDictionary).
Keep in mind that one sprite batch node per enemy kind of defies the purpose, especially if the texture atlas for each enemy is rather small and not even close to the maximum allowed size (1024x1024 for old devices, 2048x2048 or more for iPhone 3GS and newer). If possible, cram as many images into one texture atlas and use one sprite batch node for it.

Related

What are the benefits of using texture atlas in Sprite Kit?

I'm new to ios game development field.
I have been going through the following apple tutorial multiple times but not getting the points
https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Sprites/Sprites.html
thanks
Directly from the SKTextureAtlas class reference :
Texture atlases can improve memory usage and rendering performance. For example, if you have a scene with sprites drawn with different textures, Sprite Kit performs one drawing pass for each texture. However, if all of the textures were loaded from the same texture atlas, then Sprite Kit can render the sprites in a single drawing pass—and use less memory to do so. Whenever you have textures that are always used together, you should store them in an atlas.
SKTextureAtlas Class Reference
animation can be hundred of files. atlas puts them in one large file.
reading one file (large with lots of images) is much more efficient then reading hundreds of files (with one image each)
rendering of one large image and then showing only part of it is much more efficient then rendering each file separately.

What is the correct way to cache SKScene?

I use SKScenes for different screens of my main menu. Each of these screens is rather complicated, sporting dozens of elements.
So each time user moves between those screens there is like 1-2 second lag before going next scene or previous scene as I recreate them each time.
Should I just store my scenes in some singleton after they are created so that next calls are faster?
Is it a good thing to do? Won't it be too memory-heavy?
Some optimization tips:
1) Your biggest memory hog is going to be the graphics. To keep this under control, use SKTexture object with a texture atlas. Always use a texture atlas because:
Texture atlases can improve memory usage and rendering performance. For example, if you have a scene with sprites drawn with different textures, Sprite Kit performs one drawing pass for each texture. However, if all of the textures were loaded from the same texture atlas, then Sprite Kit can render the sprites in a single drawing pass—and use less memory to do so. Whenever you have textures that are always used together, you should store them in an atlas.
2) Create your texture atlases based on levels so you do not use up memory for nothing. In other words, create an atlas for level 1, another one for level 2 and so on. According to the docs:
For a larger game, you may need to split the textures into levels or themes. Each level or theme’s textures are designed to fit in a specific amount of memory. When the player starts a new level, you preload all of that level’s texture objects. When the player finishes playing the level, the textures not needed for the next level are discarded.
3) You can use a (SKSpriteNode) singleton if you have a lot of the same animations used in different scenes. For example, an enemy present in all levels who has animations for idle, walking, running, jumping, attacking, etc... The same singleton can load all of your texture alases for your animations. You can also use a singleton to store all of your game sounds and thus further reduce load times but keep an eye on memory usage if you have a lot of sounds/music.
4) Setting the skView.ignoresSiblingOrder = YES; also gives an optimization boost. According to the documentation:
The default value is NO, which means that when multiple nodes share the same z position, those nodes are sorted and rendered in a deterministic order. Parents are rendered before their children, and siblings are rendered from eldest to youngest. When this property is set to YES, the position of the nodes in the tree is ignored when determining the rendering order. The rendering order of nodes at the same z position is arbitrary and may change every time a new frame is rendered. When sibling and parent order is ignored, Sprite Kit applies additional optimizations to improve rendering performance. If you need nodes to be rendered in a specific and deterministic order, you must set the z position of those nodes.
5) If your images do not absolutely require alpha, do not include it in your images.
6) Remove nodes from the parent if you no longer need them. Also make sure you remove any reference to them such as inclusion in any arrays. The rest is taken care of by SpriteKit as stated in the docs:
An SKTexture object is created and attached to the sprite. This texture object automatically loads the texture data whenever the sprite node is in the scene, is visible, and is necessary for rendering the scene. Later, if the sprite is removed from the scene or is no longer visible, Sprite Kit can delete the texture data if it needs that memory for other purposes. This automatic memory management simplifies but does not eliminate the work you need to do to manage art assets in your game.
In other words, delete a SKTexture object by removing any strong references to it, including:
All texture references from SKSpriteNode and SKEffectNode objects in your game
Any strong references to the texture in your own code
An SKTextureAtlas object that was used to create the texture object

cocos2d flicker

I have a pool of CCSprites numbering 1200 in each of two arrays, displayGrid1 and displayGrid2. I turn them visible or invisible when showing walls or floors. Floors have a number of different textures and are not z-order dependent. Walls also have several textures and are z-order dependent.
I am getting about 6-7 frames when moving which is okay because its a turn based isometric rogue-like. However, I am also getting a small amount of flicker, which I think is performance related, because there is no flicker on the simulator.
I would like to improve performance. I am considering using an array CCSpriteBatchNodes for the floor which is not z-order dependent but am concerned with the cost of adding and removing sprites frequently between the elements of this array, which would be necessary I think.
Can anyone please advise as to how I can improve performance?
As mentioned in the comments, you're using multiple small sprite files loaded individually which can cause performance issues as there is wasted memory being used to store excess pixel data around each of the individual sprites. Each row of pixel data in an OpenGL texture must have a number of bytes totaling a power of 2 for performance reasons. Although I believe OpenGL ES under iOS does this automatically, it can come with a big performance hit. Grouping sprites together into a single texture that is correctly sized can be a tremendous boon to rendering performance.
You can use an App like Zwoptex to group all these smaller sprite files into a larger, more manageable sprite sheets/texture atlas and utilize one CCSpriteBatchNode for each sprite sheet/texture atlas.
Cocos2D has pretty good support for utilizing sprite sheets with texture atlases and converting your code to using these instead of individual files can be done with little effort. Creating individual sprites from a texture atlas is easy, you just call the sprite by name instead of from the file.
CCSpriteBatchNodes group OpenGL calls for their sprites together, a process known as batching, which causes the operating system and OpenGL to have to make less round trips to the GPU which greatly improves performance. Unfortunately, CCSpriteBatchNodes are limited to only being able to draw sprites for the texture that backs them (enter sprite sheets/texture atlases).

Cocos2d: GPU having to process the non visible CCSprite quads

Given one texture sheet is it better to have one or multiple CCSpriteBatchNodes? Or does this not affect at all the GPU computational cost in processing the non visible CCSprite quads?
I am thinking about performance and referring to this question and answer I got. Basically it suggests that I should use more than one CCSpriteBatchNode even if I have only one file. I don't understand if the sentence "Too many batched sprites still affects performance negatively even if they are not visible or outside the screen" is applicable also having two CCSpriteBatchNode instead of one. In other words, does the sentence refer to this "The GPU is responsible for cancelling draws of quads that are not visible due to being entirely outside the screen. It still needs to process those quads."? And if so it should meant that it doesn't really matter how may CCSpriteBatchNode instances I have using the same texture sheet, right?
How can I optimize this? I mean, how can I avoid the GPU having to process the non visible quads?
Would you be able to answer to at least the questions in bold?
First case: Too many nodes (or sprites) in the scene and many of them are out of screen/visible area. In this case for each sprite, GPU has to check if its outside the visible area or not. Too many sprite-nodes means too much load on GPU.
Adding more CCSpriteBatchNode should not effect the performance. Because the sprite-sheet bitmap is loaded to the GPU memory, and an array of coordinates is kept by the application for drawing individual sprites. So if you put 2 images in 2 different CCSpriteBatchNodes or 2 images in 1, it will be same for both CPU and GPU.
How to optimize?
The best way would be to remove the invisible nodes/sprites from the parent. But it depends on your application.
FPS drops certainly because of two reasons:
fillrate - when a lot of sprites overlap each others (and additionally if we render high-res texture into small sprite)
redundant state changes - in this case the heaviest are shader and texture switches
You can render sprites outside of screen in single batch and this doesn't drop performance singnificantly. Pay attention that rendering sprite with zero opacity (or transparent texture) takes the same time as non-transparent sprite.
First of all, this really sounds like a case of premature optimization. Do a test with the number of sprites you expect to be on screen, and some added, others removed. Do you get 60 fps on the oldest supported device? If yes, good, no need to optimize. If no, tweak the code design to see what actually makes a difference.
I mean, how can I avoid the GPU having to process the non visible quads?
You can't, unless you're going to rewrite how cocos2d handles drawing of sprites/batched sprites.
it doesn't really matter how may CCSpriteBatchNode instances I have using the same texture sheet, right?
Each additional sprite batch node adds a draw call. Given how many sprites they can batch into a single draw call, the benefit far outweighs the drawbacks. Whether you have one, two or three sprite batch nodes makes absolutely no difference.

Texture and animation in iOS

I am developing a game for iPhone retina enabled.
This game has alot of sprite sheets to be used.
MyQuestion which is better to use
pvr
pvr.gz
pvr.ccz
or normal png format
which is the best practice for using sprite sheets.
Counter-Question: Is it better to use a sports car or a pickup truck?
It depends on your particular use case. You'll use PNG if you can't afford any loss in quality. You'll use PVR if memory and rendering speed are of higher concern.
GZ and CCZ are simply compression algorithms that determine how well the data is packed and how fast it can be loaded. I hear that PVR.CZZ is the fastest to load.
Now, what made me curious is that you say you have "a lot of sprite sheets". Ideally you'll want to be using as few as possible (best: 1) sprite sheets in a scene. If you create a sprite sheet per game object you're approaching it the wrong way, sprite sheets (texture atlases) are not a tool to structure and categorize your image assets! Your goal should be to cram as many images as possible into a single sprite sheet (texture atlas) to improve rendering performance.
In some cases you'll even want to duplicate some of your images so that you can create a single texture atlas for the current scene (level) even if that means to duplicate some images in the other scenes.

Resources