Can somebody please explain to me how CCSpriteBatchNodes and spritesheets work ? - iphone

I have built a little ipad game and spritesheets and batchnodes are all over the place. However I have no idea how they really work, when to add a sprite sheet, when to add sprites to the spritebatchnode etc. etc. .
This is what I do in the initial screen (main menu):
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"sprites.png"];
screenSize = [CCDirector sharedDirector].winSize;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"sprites.plist"];
[self addChild:spriteSheet];
In other classes - I always need to use the same batch node -> "sprites.png" - I call
CCSprite *someSprite = [CCSprite spriteWithSpriteFrameName:someSpriteFrameName.png];
and add it to self.
[self addChild:someSprite]; // I do not understand why I would add my sprite to the batch node instead of self
So the situation is the following:
I have 1 file called "sprites.png" where all my sprites are on.
Do I make a new batch node whenever I change the scene ? The spriteframecache should stay the same right ?
What would I have to do with the spriteframecache if i had two sprite sheet files ?
When do I add children to the batch node, and why ?
I really don't seem to grasp the concept entirely. I know approximately why I use it. But I would really appreciate it if somebody could explain everything to me again in layman terms, so I am 100% sure about what I do. Please try to explain it as basic as it gets.
Thank you very much -
Martin

CCSpriteBatchNode is CCNode successor so you have to create separate instance for every scene. You can use several batch nodes on the scene if you have more than one texture file.
CCSpriteFrameCache is a singleton so it stays the same during application lifetime.
Add both to CCSpriteFrameCache. CCSpriteFrameCache singleton has loadedFilenames_ field (instance of NSMutableSet) which caches all sprite frames for all scenes.
You have to use batch node when you expect large amount of sprites with similar textures. For example you want to generate 100 coins every 2 seconds. If you use usual CCNode and create sprites on it, your application will allocate these 100 CCSprite objects every 2 seconds. CCSpriteBatchNode is targeted for performance and better memory usage. It works like UITableView with reusable cells.
When you scroll table view with reusable cells, it does not create new cells. When new cell has to be presented on screen table view simply finds cell with same reuse identifier offscreen and replaces it's content with new content. CCSpriteBatchNode works in the same way. When you try to add new sprite to it, the node tries to find unused sprite offscreen and replaces it's content.
Remember that sprites which you add to CCSpriteBatchNode have to use the textures from texture file which was used to create this batch node.
Following example is based on code from your question:
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"sprites.png"];
screenSize = [CCDirector sharedDirector].winSize;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"sprites.plist"];
[self addChild:batchNode];
CCSprite *someSprite = [CCSprite spriteWithSpriteFrameName:#"someSpriteFrom_sprites.png_.png];
[batchNode addChild:someSprite]; // add sprite to batch node to get all advantages of it
Here is a good article about CCSpriteBatchNode performance: http://www.learn-cocos2d.com/2011/09/cocos2d-spritebatch-performance-test/

Modern renderer
We rewrote the renderer from scratch. The Render graph was decoupled from the Scene graph.
That means that auto-batching is supported, finally :-) And the new renderer is so fast, that we no longer encourage the use of SpriteBatchNode.
Sprites have auto-culling too.
And the good thing is that we didn't sacrifice any of the old features: custom OpenGL commands are still supported!
Refer this link
Hopes it helps

Related

how to embeed multiple sprite sheet CCSpriteFrameCache animation in cocos2d

all
I want to embeed multiple spriteFrame cache using the following code.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"abc.plist"];
// Create a sprite sheet with the Happy Bear images
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"abc.png"];
[self addChild:spriteSheet];
the problem is that after 1st animation is cover I want to do another animation through another ccsprite fram cache, and add another sprite sheet, but when I add another sprite sheet it will give me sigerbat error.
how can I do multiple animation after one animation cover then the second animation will start, remember that there are 4 CCSpriteFrameCache file (ie,. 4 plist file)
All CCSprite added to a CCSpriteBatchNode must use the same texture. So what you're trying to accomplish is not possible because you're trying to add images from 4 different textures. If you check the Console (in Debug builds) you'll find a message stating something to that effect.
The solution: use one CCSpriteBatchNode for each texture (loaded via CCSpriteFrameCache plist). You'll have to write more code but that's the only way you can do it, apart from not using CCSpriteBatchNode at all.
You might want to do a performance test to check if you really, really need the CCSpriteBatchNode. For example, if you only display ONE sprite from the same texture on screen at any one time, you don't need a CCSpriteBatchNode. It's only improving performance if you have multiple (and many) sprites on screen and all are using the same texture.

Cocos2D should I use one image per sprite

If I have several identical sprites on the screen at once, do I need to load one image for each of the sprite, or can I simply re-use the images somehow?
i.e,
Do I need to do this?
CCSprite *mySprite1 = [CCSprite spriteWithFile:#"mySprite.png"];
CCSprite *mySprite2 = [CCSprite spriteWithFile:#"mySprite.png"];
Or is there a better way to deal with identical sprites?
Your solution is fine. The first call to spriteWithFile: will load the texture and add it to the shared CCTextureCache. The second one will check to see if the texture already exists, and this time will reuse it from the first one.
You should propably use
- (id)initWithCGImage:(CGImageRef)image
key:(NSString *)key
Reference
This method uses either image or a cached texture named by key. If no cached texture with this key is available, it'll create a texture and cache it for you.

How do I add background in cocos2d?

I'm a total noob. Starting my first app. I'm using cocos2d and there's isn't a .xib file so how do I add a background image behind the sprites I have in my scene?
In Cocos2d you don't use xibs you have to place all the objects by code. Check the samples that come with Cocos2d to get a sense of how it works.
If you already know how to add sprites, adding a background is done the same way, it would be just another sprite just add it with a lower z-order.
[self addChild:myBackground z:0];
"self" would be the actual CCLayer
"myBackground" the sprite you created with the bakcground iamge.
and "z" would have to be lower than the z used for the other elements.

The best way to remove a sprite from a batch in Cocos2D

I'm using Cocos2D in my project and I'm quite new to this library. And I don't understand one thing.
I have many sprites on the scene which are added and removed constantly. So at certain moment a sprite becomes useless and I have to remove it form a batch node.
In the comments of the removeChild method of CCSpriteBatchNode class is said:
#warning Removing a child from a CCSpriteBatchNode is very slow
Does anybody know what the best method of removing a sprite?
Thanks!
Instead of adding and removing sprites why not re use them, then you won't have any slow down caused by adding or removing sprites.
Setting a sprite not to be visible saves the render cost and when you need to add it again just move it to position and the texture frame if you need to and then turn the visibility back on.
I subclass a ccSprite and then add them to an array to keep track of active and inactive sprites.
Dave.

IPhone and Cocos2d Sprites/Layers

I am using cocos2d-iphone to place Sprites onto a Layer to setup a game playfield. At certain points in the game, certain Sprites need to be removed based upon game conditions. What I would like to do is setup an array of Sprite pointers, but I have two questions:
What's the best way to place Sprite pointers in an array?
How does one remove the Sprite in cocos2d with only a pointer to the Sprite? I know how to do it from its parent layer, but that is too runtime intensive for the main game loop.
Thanks in advance!
The Sprite class inherits from CocosNode, so you should be able to call spritePointer.parent.remove(spritePointer)
I figured it out. If anyone else is interested, the way to do it is to declare an array of Sprite pointers, such as:
Sprite * mySprites[10][10]; // assuming a 10x10 playfield where obstacles get placed
Then, when setting up your Sprites:
mySprites[0][0] = [Sprite spriteWithFile: #"obstacle.png"];
[myLayer add:mySprites[0][0]];
To remove the Sprite:
[myLayer remove:mySprites[0][0]];
There's also [mySprite removeFromParentAndCleanup:YES].