Cocos2D CCSprite question? - iphone

I am new to Cocos2D and I have question about texuture loading.
When I use code like follows to create two sprites ,does it load the texture "alien.png" two times into memory? Or does it save only one copy and create only one OpenGL texture ?
sp1=[CCSprite spriteWithFile:#"alien.png"];
sp2[CCSprite spriteWithFile:#"alien.png"];

If you have a look at the way Cocos2D is implemented (don't forget that it's open source and you can drill down into every method), you will see that [CCSprite spriteWithFile:#"alien.png"] uses [[CCTextureCache sharedTextureCache] addImage: filename];
to load/cache the texture. The addImage method on the CCTextureCache singleton checks to see if the texture is already cached, and only if it's not will start to load it from the specified path. Now, with the texture cached, it doesn't matter how many times you draw it on the screen, you will not load the texture in memory more than once.

Related

Cocos2d - Can I load multiple sprite frames into frame cache

In Cocos2d v0.99 there's a class named CCSpriteFrameCache. I can load all the sprite frames
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"images.plist"];
and then I can use those loaded frames
CCSprite *sprite=[CCSprite spriteWithSpriteFrameName:#"img01.png"];
Now my question is: Do we create a big sprite sheet that will hold every single image that we're going to use for animations? I mean, I thought I'd have several sprite sheets for different animation objects. If this question is answered NO,so that I load each sprite differently, then my second question is how do I refer to a frame in a specific sprite sheet?
Now my question is: Do we create a big sprite sheet that will hold every single image that we're going to use for animations?
yes, or you can have multiple sprite sheets if you have many different frame images...
I mean, I thought I'd have several sprite sheets for different animation objects.
It depends on the size of the resulting sprite sheet. In principle it is convenient to organize the different frames of the same animation within the same sheet, but if your frames occupy, e.g., 600x600, your sprite sheet will occupy the same memory as a 1024x1024 sheet, so you are better off adding some more frames to that same sheet, even if it belogs to a different animation. In general, you can play with the sheet size, as long as both dimensions are a power of 2, you will not have inefficiencies as to memory occupation and you can organize your frames into different sheets if that makes sense to you.
If this question is answered NO,so that I load each sprite differently, then my second question is how do I refer to a frame in a specific sprite sheet?
by the original filename that was composed into the sprite sheet...
hope it helps...
If possible, cram as much images into as few texture atlases as possible. The determining factor is quite often z ordering. If you have two atlases and two sprite batch nodes, then each sprite batch node can only render their sprites on their z order, while the sprites in the other batch node are either always in front or behind.
You do not need to know which texture atlas (sprite sheet) a sprite frame came from. Just reference it by name. If you need to know which texture the frame refers to, check the sprite frame's texture property and compare it with the texture property of the sprite batch node.

COCOS2d - Reusing Sprite & Replacing scene

I have 2 scenes both the scene shares a same back ground Image so I have this below code in both scenes init method and added. Everything works prefect. My question is , since the same image file is read twice , allocated memory and deallocated so why cant we store it one common place (spriteManager) using singleton pattern and reuse that instance? If I do this way will the memory will be released when when the scene one get replaced with scene 2.
One this strike my mind is Retain but not sure how and where to handle this retain. If my approach is wrong for handling Common reusable sprite then please suggest me the proper way of doing the same. I am new to this cocos2d so I havent read the concept of sprite sheet , for now I want to keep everything simple.
CCSprite *bg = [CCSprite spriteWithFile:#"bg.png"];
2nd Question , I read while replacing two heavy scene there would be some chances of memory leak due to overlap in releasing first scene memory and allocating the next scene memory. So to avoid this I read we have to give a pause for seconds load a light weight scene (Loading scene). Is that a good solution or the replacing scene itself will not create any problems.
Would be great if there is a good article about this post title (Reusing Sprite & Replacing scene). .
To answer your first question, you don't need a spriteManager because cocos2D already have a default texture caching mechanism(refer to ccTextureCache class), and when you call spriteWithFile next time it will just load the texture from texture cache. Note: ccTextureCache usually clear its textures when there is a memory warning.
Secondly there shouldn't be any memory leaks when replacing scenes if you have deallocated the objects properly. Can you provide a link to where you read about this?

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

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

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.