Cocos2d animations in main loop - cocos2d-iphone

Anyone that can give any hint of the smartest way to do a main loop animation? I don't want to use CCAnimation because I want to control the animations frame by frame.
Shall I store the sprite rect (relative to the sprite sheet) for each individual frame in an array, and then look up the suiting rect in each animation step? I tried to find out how this is done in CCAnimation, but I didn't succeed...
How to get the rect for each frame at initialization?
How to set the rect at each animation step?
Do I need to use CCSpriteBatchNode? I guess not, eh?

Cannot crealry understand, why you don't want to use CCAnimation, but anyway, to get answer for your questions you can check creation code of the CCSprite instance. Then, check creation of CCSpriteFrame instance. There you will find the answer for at least your first question.
Actually if you just want to manage animation frames differently from CCAnimate, you can just store array of CCSpriteFrames and show them as you want(in CCAnimate action these frames are just changed one by one in equal time intervals).
And if you do not want to show more than one frame of your animation, there is no difference will you use CCSpriteBatchNode or not. It saves a lot of processor time if you need to draw several parts of one texture, as it draws them in one draw call instead of send draw message to all of these sprites.

As you want animate sprite frame by frame I think using CCSpriteBatchNode would be a better option as it give you frame by frame access of animation.Making plist of sprites using any tool like "Zwoptex" will give an efficient way to animate using CCSpriteBatchNode.
Hope you know the animation using plist file with CCSpriteBatchNode.

I did the following with inspiration from Morions answer:
In the game tick function:
_animationFrames.legFrame = (_animationFrames.legFrame + 1) % _animationFrames.legFrames.count;
[_legs setDisplayFrame: [_animationFrames.legFrames objectAtIndex: _animationFrames.legFrame]];
And in the init function:
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"Player.png"];
[self addChild:spriteSheet];
_animationFrames.legFrames = [[NSMutableArray array] retain];
for(int i = 0; i <= 15; ++i)
{
[_animationFrames.legFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"Player_legs-%d.png", i]]];
}
_legs = [CCSprite spriteWithSpriteFrameName:#"Player_legs-0.png"];
[_sprite addChild: spriteSheet];
[spriteSheet addChild:_legs z:1];

Related

Which APIs should we use to add spritesheets and sprites to a cocos2d game?

While creating a cocos2d iOS game, there are several options to add spritesheets - CCTextureCache::addImageAsync, CCSpriteFrameCache::addSpriteFramesWithFile, etc. - what is the difference between using these different ways to add a spritesheet?
Similarly, to load a sprite, we can call CCSprite::spriteWithSpriteFrameName or CCSprite::spriteWithFile or CCSpriteBatchNode::batchNodeWithTexture, etc. What is the difference between using these techniques?
Thanks
Anand
Load sprite frames, this also loads the textures:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"file.plist"];
Use sprite frames:
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:#"frame.png"];
Add the sprite to a batch node:
CCSpriteBatchNode* batchNode = [CCSpriteBatchNode batchNodeWithTexture:sprite.texture];
[batchNode addChild:sprite];
The batchNodeWithFile works too if you use the same image file of the sprite. If the sprite was initialized with a spriteframe, it'll be the texture atlas image (ie "file.png").
addImageAsync is only needed if you want to load your texture on another thread, usually to animate the loading screen. You'll still have to add the sprite frames afterwards.
CCSprite spriteWithFile creates a sprite from a single image file. Those can be batched too but it's better to use a texture atlas with sprite frames.

Cocos2D - redeclaring the frame cache?

I have this declared on my main class:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"atlas.plist"];
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"atlas.png"];
now I am on another class and I want to create a new batchNode but get spriteFrames from atlas, that was declared on the main class. How do I do that? Do I need to put these same lines again on my other class? By doing so, will I have redundant images imported to the sharedSpriteFrameCache? My idea is to save memory, not wasted.
Any clues? thanks.
You don't need to call [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"atlas.plist"]; again assuming you haven't removed these sprite frames.
You will need to create another batch node to put sprites on.
If you were to try and add the sprite frames to the cache again, you wouldn't waste space, the sprite frames would only be added once, but you would waste time while cocos2D parses through the file and determines if each sprite frame has indeed already been added.

multiple CCSpritevFramevCache at one time

i am using the CCSpriteFrameCache a lot but cant understand somthing about it.
can i load many .plist to the cache at the start of my game ? or the CCSpriteFrameCache has ONLY one plist at a time ?
by now there is a sprite which is a child of a CCSpriteBatchNode ,that is been created many times during the game , with different images. so every time i create a new sprite i do this:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:#"cand%i.plist",stage]];
candySheet = [CCSpriteBatchNode batchNodeWithFile:[NSString stringWithFormat:#"cand%i.png",stage]];
[self addChild:candySheet];
sprite1 = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"cand%i.png",1]];
is it ok ?
now lets say i have 2 spriteSheets, and 2 .plist, and i want to load both of them on my init , and add 2 sprites, each to be a child of one CCSpriteBatchNode and render images for each sprite from his own spriteSheet and Plist. but i get error then that :
CCSprite is not using the same texture id
so, i understand that each time i have to load to the cache the plist that i need at that specific time ????
thanks.
Someone asked a similar thing earlier.
You cannot make sprites children of the same CCSpriteBatchNode if they are not from the same spritesheet.
You need to create a new CCSpriteBatchNode for each spritesheet you use (by spritesheet I mean the combined image file and .plist file)
The CCSpriteFrameCache is a single cache shared across all your scenes and classes. When you call this method:
[CCSpriteFrameCache sharedSpriteFrameCache]
You are not making a new CCSpriteFrameCache object everytime, there is just ONE instance. You store all your loaded spritesheets in this single cache. So you could load 2 spritesheets into the cache like so:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"sheet1.plist"]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"sheet2.plist"];
You then need to create a CCSpriteBatchNode for EACH spritesheet, you cannot have more than one sheet in a batch node:
CCSpriteBatchNode *spriteSheet1 = [CCSpriteBatchNode batchNodeWithFile:#"sheet1.pvr.ccz"];
CCSpriteBatchNode *spriteSheet2 = [CCSpriteBatchNode batchNodeWithFile:#"sheet2.pvr.ccz"];
You can then add both of these batch nodes to a layer if you wish. Sprites added to batch nodes must be from the spritesheet that batch node is using.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"some.plist"];
The above line takes quite a chunk of time even if the sprite frames are already loaded/cached. So make sure to avoid doing this unless you're absolutely certain that these sprite frames haven't been cached before, like at the beginning of the game or after purging the sprite frame cache.

Cocos2D - CCAnimation: which frame is being displayed right now?

I'm doing a sprite animation. The code is:
CCAnimation *anim = [CCAnimation animationWithFrames:frames delay: 0.1f];
CCAnimate *animate = [CCAnimate actionWithAnimation:anim];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:animate];
[sprite runAction: repeat];
I want to know which frame of the animation is being displayed when I click on the sprite. How can I do that? Thanks.
You can use the CCSprite method isFrameDisplayed to compare the current CCSpriteFrame with another. You'll have to keep the frames array around to do the later comparison. Unfortunately Cocos2D does not support testing if the n-th frame of a particular animation is displayed out of the box, nor does it tell you the filename of the currently displayed CCSpriteFrame.

create a texture from a spritesheet cocos2d

Hey all
Basically all i want is to create CCTexture2D objects from a spritesheet. I can make individual sprites from
charSpriteCur = [CCSprite spriteWithTexture:charSheet.texture rect:CGRectMake(136, 0, 136, 223)];
but i want to get individual textures from a spritesheet so that i can use
[mySprite setTexture:tex];
to change the sprite as required. I dont need it to be an animated sprite i just want to be able to change its texture when i want using a spritesheet.
any ideas with this or what is the best approach?
thanks
g
I don't think this is possible. When I need to do this I instead remove the CCSprite node (which I have setup as a property in my class) and then make a new one. Here is an example:
[self removeChild:[self mySprite] cleanup:YES];
[self setMySprite:[CCSprite spriteWithSpriteFrameName:#"image.png"]];
[mySprite setAnchorPoint:ccp(0,1)];
[mySprite setPosition:ccp(623,872)];
[self addChild:mySprite z:5];