This is the code for creating single sprite, then animating it:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"crowfl.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"crowfl.png"];
[self addChild:spriteSheet];
NSMutableArray *crowAnimFrames = [NSMutableArray array];
for (int i=1; i<=8; i++) {
[crowAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"crow%d.png", i]]];
}
CCAnimation *crowAnim = [CCAnimation animationWithSpriteFrames:crowAnimFrames delay:0.1f];
_crow = [CCSprite spriteWithSpriteFrameName:#"crow1.png"];
_crow.position = ccp(windowSize.width + _crow.contentSize.width/2, _crowFlightHeight);
id crowAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:crowAnim]];
[_crow runAction:crowAction];
[spriteSheet addChild:_crow];
...
id crowMoveAction = [CCSequence actions:
[CCMoveTo actionWithDuration:5.0 position:ccp(_flipCrow ? (windowSize.width + _crow.contentSize.width/2) : (-_crow.contentSize.width/2), _crowFlightHeight)],
crowMoveComplete,
nil];
[_crow runAction:crowMoveAction];
What I need is to create multiple sprites(_crow) and animate them asynchronously. I need to know what part of code can be reusable/shared among multiple sprites and what part should be unique for each animating sprite.
Cache animation in CCAnimationCache and that reduces delay in loading again and again:
CCAnimation* crowAnim = nil;
crowAnim = [[CCAnimationCache sharedAnimationCache] animationByName:#"crowAnim"];
if(!crowAnim)
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"crowfl.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"crowfl.png"];
[self addChild:spriteSheet];
NSMutableArray *crowAnimFrames = [NSMutableArray array];
for (int i=1; i<=8; i++) {
[crowAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"crow%d.png", i]]];
}
crowAnim = [CCAnimation animationWithSpriteFrames:crowAnimFrames delay:0.1f];
[[CCAnimationCache sharedAnimationCache] addAnimation:crowAnim name:#"crowAnim"];
}
_crow = [CCSprite spriteWithSpriteFrameName:#"crow1.png"];
_crow.position = ccp(windowSize.width + _crow.contentSize.width/2, _crowFlightHeight);
id crowAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:crowAnim]];
[_crow runAction:crowAction];
[spriteSheet addChild:_crow];
...
id crowMoveAction = [CCSequence actions:
[CCMoveTo actionWithDuration:5.0 position:ccp(_flipCrow ? (windowSize.width + _crow.contentSize.width/2) : (-_crow.contentSize.width/2), _crowFlightHeight)],
crowMoveComplete,
nil];
[_crow runAction:crowMoveAction];
Related
I have a Helper Class that sets up animation but the code keeps failing when i call CCCallBlock.
Here is the Helper Class:
+(CCSpriteBatchNode*)setupAnimation:(NSString*)spriteNameWithoutPNG :(int)numberOfFrames :(CCSprite*)spriteObj :(int)startRandomX :(int)endRandomX :(int)endDuration{
CGSize winSize = [[CCDirector sharedDirector] winSize];
NSString *plist = [NSString stringWithFormat:#"%#.plist",spriteNameWithoutPNG];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:plist];
NSString *spriteFileName = [NSString stringWithFormat:#"%#.png",spriteNameWithoutPNG];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:spriteFileName];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i=1; i <= numberOfFrames; i++){
NSString *frameName = [NSString stringWithFormat:#"%#%d.png",spriteNameWithoutPNG, i];
[animFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:frameName]];
}
CCAnimation *moveAnim = [CCAnimation animationWithFrames:animFrames delay:0.1f];
NSString *spriteFrameName = [NSString stringWithFormat:#"%#1.png",spriteNameWithoutPNG];
spriteObj = [CCSprite spriteWithSpriteFrameName:spriteFrameName];
int x = arc4random() % startRandomX;
spriteObj.position = ccp(x, 480);
CCAction *actionFrames = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:moveAnim restoreOriginalFrame:NO]];
int q = arc4random() % endRandomX;
int r = arc4random() % endDuration;
CCAction *moveAction = [CCMoveTo actionWithDuration:r position:ccp(q, -50)];
id spriteObjRemove = [CCCallBlock actionWithBlock:^
{
[spriteObjRemove removeFromParentAndCleanup:YES];
//[asteroidArray removeObject:asteroid];
}];
id spriteSeq = [CCSequence actions:moveAction, spriteObjRemove, nil];
[spriteObj runAction:spriteSeq];
[spriteObj runAction:actionFrames];
[spriteSheet addChild:spriteObj];
return spriteSheet;
}
And this is how the code gets called in the parent:
-(void)asteroidCreate{
Asteroid *asteroid = [[Asteroid alloc] init:#"asteroid1.png"];
CCSpriteBatchNode *spritesheet = [Helper setupAnimation:#"asteroid" :8 :asteroid :320 :320 :10];
[self addChild:spriteSheet];
[self countDownToCreateNextAsteroid];
}
ERROR
Printing description of block:
<__NSStackBlock__: 0xbfffab90>
i doubt this is correct :
id spriteObjRemove = [CCCallBlock actionWithBlock:^
{
[spriteObjRemove removeFromParentAndCleanup:YES]; <=== using action instead of sprite
//[asteroidArray removeObject:asteroid];
}];
try
[spriteObj removeFromParentAndCleanup:YES];
I have tried to run multiple animation 1.Player will stand on screen loading 2.Then he starts running when his frames finish 3.Player will stop and Go action performed
problem is go action is executed before run action finishes
can any one help me to perform this task like player run 0.6 secs then he stops running action and Go action execute and after 4 sec it stops
- (void)didLoadFromCCB
{
CGSize winSize = [[CCDirector sharedDirector] viewSize];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"cc_player.plist"];
NSMutableArray *runAnimFrames = [NSMutableArray array];
for(int i = 0; i <= 12; i++)
{
[runAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"cc_player/cc_player_run_pistol_%d.png", i]]];
}
NSMutableArray *goAnimFrames = [NSMutableArray array];
for(int i = 0; i <= 11; i++)
{
[goAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"cc_player/cc_player_go_%d.png", i]]];
}
CCSprite *playerSprite = [CCSprite spriteWithImageNamed:#"cc_player/cc_player_idle_0.png"];
playerSprite.scale = 1.3;
playerSprite.position = CGPointMake(100, ( winSize.height / 2) - 60);
[self addChild:playerSprite z:3];
CCActionMoveTo *moveTo = [CCActionMoveTo actionWithDuration:8 position:CGPointMake(winSize.width+100 / 2, playerSprite.position.y)];
CCAnimation *runAnim = [CCAnimation animationWithSpriteFrames:runAnimFrames delay:0.06];
CCAnimation *goAnim = [CCAnimation animationWithSpriteFrames:goAnimFrames delay:0.06];
CCActionAnimate *runAnimationAction = [CCActionAnimate actionWithAnimation:runAnim];
CCActionAnimate *goAnimationAction = [CCActionAnimate actionWithAnimation:goAnim];
CCActionCallBlock *next=[CCActionCallBlock actionWithBlock:^
{
playerSprite.position = CGPointMake(playerSprite.position.x - 8, playerSprite.position.y + 6);
id goAction = [CCActionRepeat actionWithAction:goAnimationAction times:1];
CCActionCallBlock *nextStep=[CCActionCallBlock actionWithBlock:^
{
NSLog(#"***********not done");
// [playerSprite stopAllActions];
}];
CCActionSpawn *groupAction1 = [CCActionSpawn actionWithArray:#[goAction,nextStep]];
CCActionSequence *sequence2 = [CCActionSequence actionWithArray:#[groupAction1]];
// [playerSprite stopAllActions];
//CCActionSequence *goSequence = [CCActionSequence actions:moveTo,repeatingAnimation, nil];
[playerSprite runAction:sequence2];
}];
CCActionSpawn *groupAction = [CCActionSpawn actionWithArray:#[moveTo, next]];
CCActionSequence *sequence = [CCActionSequence actionWithArray:#[groupAction]];
[playerSprite runAction:sequence];
[playerSprite runAction:[CCActionRepeatForever actionWithAction:runAnimationAction]];
}
i have removed opticity line from code animation started showing now i have change sequance of my animation and its now working nice
(void)didLoadFromCCB
{
CGSize winSize = [[CCDirector sharedDirector] viewSize];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"cc_player.plist"];
NSMutableArray *runAnimFrames = [NSMutableArray array];
for(int i = 0; i <= 12; i++)
{
[runAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"cc_player/cc_player_run_pistol_%d.png", i]]];
}
NSMutableArray *goAnimFrames = [NSMutableArray array];
for(int i = 0; i <= 11; i++)
{
[goAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"cc_player/cc_player_go_%d.png", i]]];
}
CCSprite *playerSprite = [CCSprite spriteWithImageNamed:#"cc_player/cc_player_idle_0.png"];
playerSprite.scale = 1.3;
playerSprite.position = CGPointMake(100, ( winSize.height / 2) - 60);
[self addChild:playerSprite z:3];
CCActionMoveTo *moveTo = [CCActionMoveTo actionWithDuration:3 position:CGPointMake(300, playerSprite.position.y)];
CCAnimation *runAnim = [CCAnimation animationWithSpriteFrames:runAnimFrames delay:0.06];
CCAnimation *goAnim = [CCAnimation animationWithSpriteFrames:goAnimFrames delay:0.06];
CCActionAnimate *runAnimationAction = [CCActionAnimate actionWithAnimation:runAnim];
CCActionAnimate *goAnimationAction = [CCActionAnimate actionWithAnimation:goAnim];
CCActionCallBlock *next=[CCActionCallBlock actionWithBlock:^
{
playerSprite.position = CGPointMake(playerSprite.position.x - 8, playerSprite.position.y + 6);
id goAction = [CCActionRepeat actionWithAction:goAnimationAction times:1];
CCActionCallBlock *nextStep=[CCActionCallBlock actionWithBlock:^
{
// [playerSprite stopAllActions];
}];
CCActionSpawn *groupAction1 = [CCActionSpawn actionWithArray:#[goAction,nextStep]];
CCActionSequence *sequence2 = [CCActionSequence actionWithArray:#[groupAction1]];
// [playerSprite stopAllActions];
//CCActionSequence *goSequence = [CCActionSequence actions:moveTo,repeatingAnimation, nil];
[playerSprite runAction:sequence2];
}];
[playerSprite runAction:[CCActionRepeatForever actionWithAction:runAnimationAction]];
CCActionSpawn *groupAction = [CCActionSpawn actionWithArray:#[moveTo,runAnimationAction]];
CCActionSequence *sequence = [CCActionSequence actionWithArray:#[groupAction,next]];
[playerSprite runAction:sequence];
}
I want to rotate the third animation frame in my code below when it is run. I am doing this using an NSNotification when the frame is displayed to send a message. The animation plays without the third frame rotating. How can I solve this? I guess there could be 'simpler' ways to achieve this but I want to do it using NSNotifications.
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) ) {
CCSpriteBatchNode* batchNode;
CCSpriteFrameCache* frameCache;
frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"cat-hd.plist"];
batchNode = [CCSpriteBatchNode batchNodeWithFile:#"cat-hd.pvr.ccz"];
[self addChild:batchNode];
CCSprite* wallbg = [CCSprite spriteWithSpriteFrameName:#"firstBg.png"];
wallbg.position= ccp(240.0, 160.0);
//wallbg.anchorPoint = ccp(0.5, 0.5);
[batchNode addChild:wallbg];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(rotateAnimationFrame:) name:CCAnimationFrameDisplayedNotification object:nil];
NSMutableArray* catAnimationArray = [[NSMutableArray alloc]init];
for(int i = 1; i < 7; i++) // i< number of frames in the plist File Name
{
CCLOG(#"item %d added", i);
[catAnimationArray addObject:
[frameCache spriteFrameByName:
[NSString stringWithFormat:#"blackCat%d.png", i]]]; }
CCSprite* catSprite = [CCSprite spriteWithSpriteFrameName: #"blackCat1.png"];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
catSprite.position = ccp(screenSize.width/2, screenSize.height/2);
CCAnimation *animation = [CCAnimation animationWithSpriteFrames:catAnimationArray delay:0.6];
repeatMovement = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation :animation]];
[catSprite runAction:repeatMovement];
//CCAnimationFrame* thirdAnim = [CCSprite spriteWithSpriteFrame:#"catAnim3.png"];
CCRotateTo *rotateRight = [CCRotateBy actionWithDuration:0.3 angle:40.0];
rotateSprite = [catSprite runAction:rotateRight];
[batchNode addChild:catSprite];
NSDictionary* theInfo = [NSDictionary dictionaryWithObjectsAndKeys:rotateSprite,#"rotateSprite", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:CCAnimationFrameDisplayedNotification object:self userInfo:theInfo];
CCAnimationFrame* thirdFrame = [animation.frames objectAtIndex:2];
thirdFrame.userInfo = theInfo;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(rotateAnimationFrame:) name:CCAnimationFrameDisplayedNotification object:nil];
}
return self;
}
-(void)rotateAnimationFrame:(NSNotification*)notification {
CCAction *rotateAction = [[notification userInfo] objectForKey:#"rotateSprite"];
}
I add one sprite per body and run animation, but when I try to remove this sprite after reloading scene(calling afterLoadProcessing once again) - removes the only first with animation. I'm new to iOS & Cococs2D programming, please help me with advice.
Here is my code:
-(void)afterLoadProcessing:(b2dJson*)json
{
[super afterLoadProcessing:json];
[self removeChild:enemysprite cleanup:YES];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"player_enemy.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"player_enemy.png"];
[self addChild:spriteSheet];
NSMutableArray *enemyGusenitsaAnimFrames = [NSMutableArray array];
for (int i = 31; i <=36; ++i) {
[enemyGusenitsaAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%d.png",i]]];
}
CCAnimation *gusenitsaMovAnim = [CCAnimation animationWithSpriteFrames:enemyGusenitsaAnimFrames delay:0.1f];
_enemyGusenitsaMovement = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:gusenitsaMovAnim]];
_enemyGusenitsaMovement.tag = 109;
std::vector<b2Body*> enemySprites;
json->getBodiesByName("enemy", enemySprites);
for (int i = 0; i < enemySprites.size(); i++) {
b2Body *bod = enemySprites[i];
enemysprite = [[CCSprite alloc] init];
[enemysprite stopAllActions];
enemysprite.scale = 0.04;
[self addChild:enemysprite z:50];
bod->SetUserData(enemysprite);
[[enemysprite runAction:[_enemyGusenitsaMovement copy]] autorelease];
}
}
Instead of use [self removeChild:enemysprite cleanup:YES];, you can remove all children
[self removeAllChildrenWithCleanup:YES];
Or loop all bodies and remove it :
for (int i = 0; i < enemySprites.size(); i++) {
b2Body *bod = enemySprites[i];
CCSprite *sprite = (CCSprite *)bod->GetUserData();
[self removeChild:sprite];
}
I'm making a game in cocos2d, I have a chicken as character that use a CCSprite. This chicken have multiple images doing different movements.
There are so many images for the movements that I have to use multiple plist files for the sprite.
My problem is that I can switch between the differents sprites
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"chicken-1to3.plist"];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"chicken-4to5.plist"];
spriteSheet1to3 = [CCSpriteBatchNode
batchNodeWithFile:#"chicken-1to3.png"];
spriteSheet4to5 = [CCSpriteBatchNode
batchNodeWithFile:#"chicken-4to5.png"];
[self addChild:spriteSheet1to3 z:1];
[self addChild:spriteSheet4to5 z:2];
NSMutableArray *chickenManAni1Imgs = [NSMutableArray array];
NSMutableArray *chickenManAni2Imgs = [NSMutableArray array];
NSMutableArray *chickenManAni3Imgs = [NSMutableArray array];
NSMutableArray *chickenManAni4Imgs = [NSMutableArray array];
NSMutableArray *chickenManAni5Imgs = [NSMutableArray array];
for(int i = 1; i <= 9; ++i) {
[chickenManAni1Imgs addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"chicken-1-%d.png", i]]];
}
for(int i = 1; i <= 19; ++i) {
[chickenManAni2Imgs addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"chicken-2-%d.png", i]]];
}
for(int i = 1; i <= 21; ++i) {
[chickenManAni3Imgs addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"chicken-3-%d.png", i]]];
}
for(int i = 1; i <= 16; ++i) {
[chickenManAni4Imgs addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"chicken-4-%d.png", i]]];
}
for(int i = 1; i <= 36; ++i) {
[chickenManAni5Imgs addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"chicken-5-%d.png", i]]];
}
chickenManAni1 = [CCAnimation
animationWithSpriteFrames:chickenManAni1Imgs delay:0.04f];
chickenManAni2 = [CCAnimation
animationWithSpriteFrames:chickenManAni2Imgs delay:0.04f];
chickenManAni3 = [CCAnimation
animationWithSpriteFrames:chickenManAni3Imgs delay:0.04f];
chickenManAni4 = [CCAnimation
animationWithSpriteFrames:chickenManAni4Imgs delay:0.04f];
chickenManAni5 = [CCAnimation
animationWithSpriteFrames:chickenManAni5Imgs delay:0.04f];
chickenMan = [CCSprite spriteWithSpriteFrameName:#"chicken-5-1.png"];
chickenMan.position = ccp(winSize.width/2, winSize.height/2);
[spriteSheet4to5 addChild:chickenMan];
[chickenMan runAction:[CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:chickenManAni5 restoreOriginalFrame:NO]]];
chickenManAniRunning = 1;
Here is the code when I try to change the sprite
[chickenMan stopAllActions];
[spriteSheet4to5 removeChild:chickenMan cleanup:YES];
[spriteSheet1to3 addChild:chickenMan];
[chickenMan runAction:[CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:chickenManAni2 restoreOriginalFrame:NO]]];
After that I get this error:
'CCSprite is not using the same texture id'
UPDATE: I'm using two differents sprites:
chickenMan1to3 = [CCSprite spriteWithSpriteFrameName:#"chicken-1-1.png"];
chickenMan1to3.position = ccp(winSize.width/2, winSize.height/2);
[chickenMan1to3 setVisible:YES];
chickenMan4to5 = [CCSprite spriteWithSpriteFrameName:#"chicken-5-1.png"];
chickenMan4to5.position = ccp(winSize.width/2, winSize.height/2);
[chickenMan4to5 setVisible:NO];
And I switch them this way:
[chickenMan1to3 stopAllActions];
[chickenMan1to3 setVisible:NO];
[chickenMan4to5 setVisible:YES];
[chickenMan4to5 runAction:[CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:chickenManAni4 restoreOriginalFrame:NO]]];
use two sprites, one for each batch node. When switching to anim from the other batch node, set the animating sprite visible and hide the other. To make them animate in synch add both sprites to a ccnode which will then represent your chicken character as far as position, actions and other logic is concerned.
If the chicken is the only sprite child in the batch node you can simply remove the batch node since batching is only helping when you have muliple instances of the same sprite and texture.