Animating Sprite Sheets in Cocos2d - ios

I'm having some issues with animating my sprite sheet. I got this code before and it worked. I had 2 frames and my variable in my loop was only allowed to reach a values of 0 and 1 since the frame names were stickman0-568.png and stickman1-568.png. My frames weren't so good so I made a new sprite sheet with 3 frames in it, stickman0-568.png, stickman1-568.png, and stickman2-568.png. My .list file is called sickman-568.plist and the .png sprite sheet is stickman-568.png. I changed the loop so i could only reach a value of 2(0,1,2). When I run it now, it crashes, despite it working before when I only had 2 frames. Can anyone please give me suggestions as to what might have went wrong? Here's my code so you can see what I did:
-(id) init
{
if( (self=[super init]) )
{
backGroundDesert = [CCSprite spriteWithFile:#"DesertMap.png"];
backGroundDesert.position = ccp(backGroundDesert.textureRect.size.width/2, backGroundDesert.textureRect.size.height/2);
[self addChild:backGroundDesert];
[backGroundDesert runAction:[CCMoveBy actionWithDuration:100 position:ccp(-1400,0)]];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"stickman-568.plist"];
CCSprite *mainGuy = [CCSprite spriteWithSpriteFrameName:#"stickman0-568.png"];
mainGuy.position = ccp(40,backGroundDesert.textureRect.size.height/2);
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"stickman-568.png"];
[batchNode addChild:mainGuy];
[self addChild:batchNode];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 0; i < 3; i++)
{
CCSpriteFrame *frames = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"stickman%02d-568.png", i]];
[animFrames addObject:frames];
}
CCAnimation *cape = [CCAnimation animationWithSpriteFrames:animFrames delay:0.2f];
[mainGuy runAction:[CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:cape restoreOriginalFrame:NO]]];
}
return self;
}
-(void)dealloc
{
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[super dealloc];
}

When You Run the code the for loop create the images as below name
stickman00-568.png
stickman01-568.png
stickman02-568.png
That is not images in your sources so only replace below line in your code of for loop. It work fine.
Change the code as below.
CCSpriteFrame *frames = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"stickman%d-568.png", i]];
See this

Related

stopping and continuing a SKAction

How we can stop an action on certain frame (texture)? I want to make an animation which stops after the touch is ended. I searched trough the docs, but with no luck. The only thing I have found is methods removeAllActions and removeActionForKey: but I don't want to completely remove an action, I just want to stop it at the right texture - the current texture when the animating signal is stopped.
//This is from the scene init method
NSMutableArray *frames = [NSMutableArray array];
SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:#"hero-movement"];
int numImages = atlas.textureNames.count;
for (int i=1; i <= numImages; i++) {
NSString *texture = [NSString stringWithFormat:#"animation_00%d", i];
SKTexture *t = [atlas textureNamed:texture];
[frames addObject:t];
}
self.animation = frames;
And this is the method which I use in touchesBegan to start animation:
-(void)move :(float)delay
{
//This is our general runAction method to make our bear walk.
//By using a withKey if this gets called while already running it will remove the first action before
//starting this again.
[self.hero runAction:[SKAction repeatActionForever:[SKAction animateWithTextures:self.animation
timePerFrame:delay
resize:NO
restore:YES]] withKey:#"move"];
return;
}
You can use the speed property to pause/resume an action:
SKAction *action = [_hero actionWithKey:#"move"];
action.speed = 0; // to pause
or
action.speed = 1; // to resume

Sprite Frame Animation Cocos2d 3.0

I've been trying to make an animated sprite, they're are a lot of tutorials but they're all for Cocos2d 2.x. My sprite sheet is named flappbird.png and the .plist is named flappbird.plist
I have this code but every time i start the scene it just crashes, this is in my init method
// -----------------------------------------------------------------------
_player = [CCSprite spriteWithImageNamed:#"monster1.png"]; // comes from your .plist file
_player.position = ccp(self.contentSize.width/28,self.contentSize.height/2);
_player.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, _player.contentSize} cornerRadius:0]; // 1
_player.physicsBody.collisionGroup = #"playerGroup";
_player.physicsBody.type = CCPhysicsBodyTypeStatic;
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"monster1.png"];
[batchNode addChild:_player];
[self addChild:batchNode];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < 5; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"flapbird%d.png",i]];
[animFrames addObject:frame];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.2f];
[_player runAction:[CCActionRepeatForever actionWithAction:[CCActionAnimate actionWithAnimation:animation]]];
[_physicsWorld addChild:_player];
// -----------------------------------------------------------------------
Animate sprite with spritesheet in Cocos2d 3.0
Make sure to add #import "CCAnimation.h" at the beginning of your code
Also add the sprite sheet after the self.userInteractionEnabled = YES; in the init
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"your.plist"];
No add all this where the sprite will be
//The sprite animation
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 7; ++i)
{
[walkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"monster%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation
animationWithSpriteFrames:walkAnimFrames delay:0.1f]; //Speed in which the frames will go at
//Adding png to sprite
monstertest = [CCSprite spriteWithImageNamed:#"monster1.png"];
//Positioning the sprite
monstertest.position = ccp(self.contentSize.width/2,self.contentSize.height/2);
//Repeating the sprite animation
CCActionAnimate *animationAction = [CCActionAnimate actionWithAnimation:walkAnim];
CCActionRepeatForever *repeatingAnimation = [CCActionRepeatForever actionWithAction:animationAction];
//Animation continuously repeating
[monstertest runAction:repeatingAnimation];
//Adding the Sprite to the Scene
[self addChild:monstertest];
Hope this helps somebody :D Cheers

CCAnimation crashes with unrecognized selector setDisplayFrame

I don't know why but my animation does not work.
I am trying to add an animated unit now via sprite sheet but through a set of sprites.
And something goes wrong
Here is the code of init method:
#implementation Enemy
-(id) initAt:(CGPoint)pos
{
if([super init])
{
self.position = pos;
CCSprite *start_sprite = [CCSprite spriteWithFile:#"unit1_00000.png"];
start_sprite.position = ccp(0,0);
[self addChild:start_sprite z:2];
const int FRAMES_COUNT = 10;
NSMutableArray* frames = [[NSMutableArray alloc]initWithCapacity:FRAMES_COUNT];
for (int i = 0; i < FRAMES_COUNT; i++)
{
NSString* file = [NSString stringWithFormat:#"unit1_0000%i.png", i];
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];
CGSize texSize = texture.contentSize;
CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect];
[frames addObject:frame];
}
_default_animation = [CCAnimation animationWithSpriteFrames:frames delay:0.1f];
_current_anim_action = [CCAnimate actionWithAnimation:_default_animation];
CCRepeatForever* repeat = [CCRepeatForever actionWithAction:_current_anim_action];
[self runAction:repeat];
}
return self;
}
The error is the following: -[Enemy setDisplayFrame:]: unrecognized selector sent to instance 0x8929bd0
setDisplayFrame is a method of CCSprite class, so in order to run a CCAnimation on Enemy class (which internally calls setDisplayFrame), Enemy must extend CCSprite, not CCNode.

Animation with large number of sprites in Cocos2d iOS?

I have to animate(dancing) a character(guy) for about 6-7 seconds i.e 500-600 frames. I have done animation before by creating spritesheets using zwoptex and then loading it with CCSpriteFrameCache && CCSpriteBatchNode with the help of The Great Ray Wenderlich. But in this case frames are heavy in number i am not sure if iOS device will be able to sustain it. What is the best process to animate all these frames with as little overhead as possible. Can i change the fps while animating? any idea anyone??
Here I put code That use for add Animated Image Without use TexturePacker:
CCSprite *dog = [CCSprite spriteWithFile:#"dog1.gif"];
dog.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:dog z:2];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=5;i++)
{
NSString* file = [NSString stringWithFormat:#"dog%d.gif", i];
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];
CGSize texSize = texture.contentSize;
CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect];
[animFrames addObject:frame];
}
CCAnimation * animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.07f;
animation.restoreOriginalFrame = YES;
CCAnimate *animAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation]];
[dog runAction:animAction];
Try with This code, I'm not sure might be helpful in your case:

game crashes 3-5 big sprites for background (1920*640 ~100kb each) ~ 400-500kb in each level

I've got a problem in my cocos2d game: In the Game's level layer I've 3-5 big sprites for background (1920*640 ~100kb each) ~ 400-500kb in each level. When I switch between menu and various game's level 4-5 times the game crashes to main IPhone menu
[[CCDirector sharedDirector] replaceScene:transition];
without this big sprites all work perfect!
-(id) init
{
....
if( (self=[super init])) {
_spriteBGLevel1 = [CCSprite spriteWithFile: [NSString stringWithFormat:#"level_fon_%i_1.png", _currentLevel]];
_spriteBGLevel1.anchorPoint = ccp(0, 0);
_spriteBGLevel1.position = CGPointMake(0.0, 0.0);
[self addChild:_spriteBGLevel1 z:-5];
_spriteBGLevel2 = [CCSprite spriteWithFile: [NSString stringWithFormat:#"level_fon_%i_2.png", _currentLevel]];
_spriteBGLevel2.anchorPoint = ccp(0, 0);
_spriteBGLevel2.position = CGPointMake(0.0, 0.0);
[self addChild:_spriteBGLevel2 z:-5];
_spriteBGLevel3 = [CCSprite spriteWithFile: [NSString stringWithFormat:#"level_fon_%i_3.png", _currentLevel]];
_spriteBGLevel3.anchorPoint = ccp(0, 0);
_spriteBGLevel3.position = CGPointMake(0.0, 0.0);
[self addChild:_spriteBGLevel3 z:-5];
....
- (void) dealloc
{
....
_spriteBGLevel1=nil;
_spriteBGLevel2=nil;
_spriteBGLevel3=nil;
[super dealloc];
}
Background.m
#import "Background.h"
#import "GameConfig.h"
#import "XMLReader.h"
#import "CCParallaxNode-Extras.h"
#import "SettingsManager.h"
#implementation Background
#synthesize backgrounds=_backgrounds;
#synthesize backgroundNode=_backgroundNode;
+(id) scene
{
CCScene *scene = [CCScene node];
Background *layer = [Background node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if ((self = [super init]))
{
CGSize screenSize = [[CCDirector sharedDirector] winSize];
int currentLevel = [[SettingsManager sharedSettingsManager] getCurrentLevel];
_backgroundNode = [CCParallaxNode node];
_backgroundNode.anchorPoint = CGPointMake(0, 0);
_backgroundNode.position = CGPointMake(0, 0);
[self addChild:_backgroundNode z:-1];
NSData *xmlData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:#"gameScene" ofType:#"xml"]];
NSError *error = nil;
NSDictionary *dictionary = [XMLReader dictionaryForXMLData:xmlData error:&error];
NSDictionary *levelsDict = [dictionary valueForKeyPath:#"levels.level"];
NSDictionary *levelDict;
_backgrounds = [[[NSMutableArray alloc] init] retain];
// [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: [NSString stringWithFormat:#"level_fon_%i.plist", currentLevel]];
for (levelDict in levelsDict)
{
int idLevel = [[levelDict valueForKeyPath:#"id"] intValue];
if(idLevel==currentLevel)
{
NSDictionary *fonsDict = [levelDict valueForKeyPath:#"background.fon"];
NSDictionary *fonDict;
for (fonDict in fonsDict){
NSString *name=[fonDict valueForKeyPath:#"name"];
int zIndex=[[fonDict valueForKeyPath:#"z"] intValue];
float ratio=[[fonDict valueForKeyPath:#"ratio"] floatValue];
float offsetx=[[fonDict valueForKeyPath:#"offsetx"] floatValue];
float offsety=[[fonDict valueForKeyPath:#"offsety"] floatValue];
if(zIndex<0)
{
//CCTexture2D* tex = [[CCTextureCache sharedTextureCache] addImage:[NSString stringWithFormat:#"%#", name]];
//CCSprite *fon_level_1 = [CCSprite spriteWithSpriteFrameName: [NSString stringWithFormat:#"%#", name]];
//CCSprite *fon_level_2 = [CCSprite spriteWithSpriteFrameName: [NSString stringWithFormat:#"%#", name]];
//CCSprite *fon_level_1 = [CCSprite spriteWithTexture:tex];
//CCSprite *fon_level_2 = [CCSprite spriteWithTexture:tex];
fon_level_1 = [CCSprite spriteWithFile:[NSString stringWithFormat:#"%#", name]];
fon_level_2 = [CCSprite spriteWithFile:[NSString stringWithFormat:#"%#", name]];
fon_level_1.anchorPoint = CGPointMake(0, 0);
fon_level_1.position = CGPointMake(0, 0);
fon_level_2.anchorPoint = CGPointMake(0, 0);
fon_level_2.position = CGPointMake(0, 0);
//[_backgroundNode addChild:fon_level_1 z:zIndex parallaxRatio:ccp(ratio, ratio) positionOffset:ccp(offsetx, offsety*screenSize.height)];
//[_backgroundNode addChild:fon_level_2 z:zIndex parallaxRatio:ccp(ratio, ratio) positionOffset:ccp(fon_level_1.contentSize.width, offsety*screenSize.height)];
[_backgrounds addObject:fon_level_1];
[_backgrounds addObject:fon_level_2];
fon_level_1=nil;
fon_level_2=nil;
}
}
break;
}
}
NSLog(#"count: %d",_backgrounds.count);
[self scheduleUpdate];
}
return self;
}
- (void)scheduleUpdate
{
[self schedule:#selector(updateBackgroud:)];
}
-(void) updateBackgroud:(ccTime)delta
{
CGPoint backgroundScrollVel = ccp(-1000, 0);
_backgroundNode.position = ccpAdd(_backgroundNode.position, ccpMult(backgroundScrollVel, delta));
for (CCSprite *background in _backgrounds) {
if (([_backgroundNode convertToWorldSpace:background.position].x+background.contentSize.width/10) < -(background.contentSize.width)) {
[_backgroundNode incrementOffset:ccp(background.contentSize.width*2,0) forChild:background];
}
}
}
- (void) dealloc
{
_backgroundNode = nil;
// _backgrounds = nil;
[_backgrounds removeAllChildren];
[_backgrounds release];
[super dealloc];
}
#end
Well, here's how I have gone about it:
Get as close as possible to a POT texture size. 1920x640 costs you as much memory as a 2048x2048. Maybe you could get your artists to combine the three-five sprites on a single 2048x2848 png, crop with an plist (like for animation).
Whenever possible, load textures 'just in time', ie before they are required to be visible. If load time became an issue (perceivable lag at an inappropriate game circumstance), convert the texture to .pvr format (faster load), later to .pvr.gz (still faster load time, smaller app download size). PVR will cause some artefacts, so check with graphic people on your project before comiting.
Coming out of any level transition (either to some kind of menu or to some cut-scene), cleanup memory used by textures. This means that if the game logic requires returning to the main scene, reload textures just-in-time, during the transition.
Last ditch, change the depth setting before loading these large textures (code snippet below). Setting to RGBA444 will save 75% of the memory requirement, BUT, you take a hit on some graphic quality, especially for high saturation images. Once again, if you need to go there, get your graphics people to optimize the images to this depth, so they are satisfied with the result on device.
cleanup:
NSLog(#"GESprite<removeUnusedSprites> : before purging all caches");
[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[[CCDirector sharedDirector] purgeCachedData];
NSLog(#"GESprite<removeUnusedSprites> : after purging all caches");
[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
depth (in a CCSprite derivative class, some utility methods), you can do this anywhere anytime:
+(void) mediumPixelFormat{
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444];
}
+(void) highPixelFormat{
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
}

Resources