I am wondering if someone can explain me how to re-use animations in cocos2d? I was used to so-called usual way: I create a 'game object', load animations and after that simply call my animations like gameObj->idle();
or gameObj->walkToPoint();
...
I understand that these helper methods should be defined by myself, and I also studied a lot of guides about CC2d and using animations in different ways, but these guides are too simple and don't shot real cases.
So at the moment I wrote method which loads animation from plist and png texture, adds this texture to parent layer and assigns first sprite to the 'Game Object' sprite. But I have some questions - I still can't find the way to play animations.
Situation is more difficult for me (but I know that this is usual case :) - animations should be assigned to 'actions' and there should be different types of actions. For example - idle action plays forever, death plays once and stays at the last frame and shoot action plays once and restores previous frame - idle's one.
To make things simple I'll show some basic code w\o complex checks and for..in loops (I wondering who decided store all frames in cc2d animation format as Array and load them with frame_%d
, not as Dictionary with structure Animations->Idle->Frames
Animations->Shoot->Frames
, but this not main point :))
//These things are global
CCAnimation *idleAnim;
CCAction * idleAction; // idle animation should be played forever
CCAnimation *deathAnim;
CCAction * deathAction; // death animation should be played once and stop at last frame
CCAnimation *shootAnim;
CCAction * shootAction; // shoot animation should be played once and idle frame restored
// loading animations with simple for loops
- (id)init {
self = [super initWithColor:ccc4(255,255,255,255)];
if (self) {
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
@"player.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:@"player.png"];
[self addChild:spriteSheet];
NSMutableArray *idleAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 20; ++i) {
[idleAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"hero_idle01_%04i_Layer-%i.png", i-1, i]]];
}
idleAnim = [CCAnimation animationWithFrames:idleAnimFrames delay:0.1f];
idleAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:idleAnim restoreOriginalFrame:NO]];
NSMutableArray *deathAnimFrames = [NSMutableArray array];
for(int i = 0; i <= 30; ++i) {
[deathAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"hero_death01_%04i_Layer-%i.png", i, i+1]]];
}
deathAnim = [CCAnimation animationWithFrames:deathAnimFrames delay:0.1f];
deathAction = [CCAnimate actionWithAnimation:deathAnim restoreOriginalFrame:NO];
NSMutableArray *shootAnimFrames = [NSMutableArray array];
for(int i = 0; i <= 19; ++i) {
[shootAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"hero_idleshoot02_%04i_Layer-%i.png", i, i+1]]];
}
shootAnim = [CCAnimation animationWithFrames:shootAnimFrames delay:0.1f];
shootAction = [CCAnimate actionWithAnimation:shootAnim restoreOriginalFrame:YES];
self.player = [CCSprite spriteWithSpriteFrameName:@"hero_idle01_0000_Layer-1.png"];
self.player.position = ccp(20, self.size.height/2);
[self.player runAction:shootAction];
[spriteSheet addChild:self.player];
[self.player runAction:[CCRotateTo actionWithDuration:0.0f angle:45]];
[self schedule:@selector(gameLogic:) interval:1.0];
}
return self;
}
This code runs correctly (loads idle animation and plays it forever) but I can't find the way to switch between actions and animatinos nicely. I've seen approaches when for example when someone wan't shoot animation, he deletes original sprite takes first sprite from shoot, plays shoot, deleted shoot sprite, restores original sprite. But what if sprite was rotated? One should pass all the params from original sprite such as flip, rotation, scale, etc. back and forward between sprites? Usually Game Objects are inherited from CCSprite, so this method generally means that one should delete and restore main game object all the time? This is not clear for me.
I tried next things, but they didn't work for me, program just halts and nothing is written to debug (I guest it is because error happens in other thread, the one which is responsible for touch handling).
// somewhere after touch happened in [shootToPoint:(CGPoing)point] method
[idleAction stop];
[shootAction startWithTarget:self.player];
[self.player runAction:[CCSequence actions:
shootAction,
[CCCallFuncN actionWithTarget:self selector:@selector(shooted)],
nil]];
And in shooted
method I call again something like this:
[shootActino stop]; // or [self.player stopAllActions] - doesn't matter I guess
[idleAction startWithTarget:self.player];
CCSprite *sprite = (Bullet *)sender; // remove bullet sprite from memory
[self removeChild:sprite cleanup:YES]; // remove bullet sprite from memory
// other routines...
So can someone explain me how to create game objects with helper methods to switch animations? Please don't send me to cc2d docs because for it is unclear how to solve this simple problem from cc2d docs or other tutorial on the web.