So I’ve been working on my cocos2d game for a little while now just using a static one frame sprite because I hadn’t gotten the graphics for the full spritesheet yet. Now I have the spritesheet, and am having trouble implementing it.
The way I currently make my “Player” (the sprite) is by having a separate player class, shown below
Player.h
#interface Player : CCSprite{
CCAction *_WalkAction;
}
#property (nonatomic, assign) CCAction *WalkAction;
#property (nonatomic, assign) CGPoint velocity;
#property (nonatomic, assign) CGPoint desiredPosition;
#property (nonatomic, assign) BOOL onGround;
#property (nonatomic, assign) BOOL forwardMarch;
#property (nonatomic, assign) BOOL mightAsWellJump;
#property (nonatomic, assign) BOOL isGoingLeft;
-(void)update:(ccTime)dt;
-(CGRect)collisionBoundingBox;
#end
And Player.m (I won’t show the full thing, because it’s pretty long, it just defines everything about the character)
-(id)initWithFile:(NSString *)filename {
if (self = [super initWithFile:filename]) {
self.velocity = ccp(0.0, 0.0);
}
return self;
}
//THIS IS ONLY A FRACTION OF MY UPDATE METHOD, THE REST OF IT IS ALL SETTING VELOCITY AND WHATNOT FOR MY PHYSICS ENGINE, BUT THIS IS THE ONLY RELEVANT PART
-(void)update:(ccTime)dt {
if (self.forwardMarch) {
self.velocity = ccpAdd(self.velocity, forwardStep);
//[self runAction: _WalkAction];
}
}
Now in my GameLevelLayer.m I init the sprite like this (This is where we get filename from from the init in player.m):
//In my init
map = [[CCTMXTiledMap alloc] initWithTMXFile:#"level1.tmx"];
[self addChild:map];
player = [[Player alloc] initWithFile:#"banker1.png"];
player.position = ccp(100, 50);
[map addChild:player z:15];
So that all works perfectly fine. The problem comes when I try to turn that sprite into a sprite with a spritesheet. So I try to do this in player.m
-(id)initWithFile:(NSString *)filename {
if (self = [super initWithFile:filename]) {
self.velocity = ccp(0.0, 0.0);
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"BankerSpriteSheet_default.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"BankerSpriteSheet_default.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <=6; ++i) {
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"banker%d.png", i]]];
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
self = [CCSprite spriteWithSpriteFrameName:#"banker1.png"];
//HERE IS WHERE self.WalkAction IS DEFINED
self.WalkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[spriteSheet addChild:self];
}
}
return self;
}
//And then run it in my update method
if (self.forwardMarch) {
self.velocity = ccpAdd(self.velocity, forwardStep);
[self runAction: _WalkAction];
}
Just for reference, self.forwardMarch is a bool that is set every time the user pushes the button to move the player, so whenever its true I move the player like this.
But when I try this I get the error
'NSInvalidArgumentException', reason: '-[CCSprite setWalkAction:]: unrecognized selector sent to instance 0x88fab50'
Any Help is appreciated.
I also posted this on the cocos2d forums if you like their code display system more (color coded and whatnot)
http://www.cocos2d-iphone.org/forums/topic/making-spritesheets-work/
EDIT:
Okay so I have made a little progress, but I'm still a bit stuck. I've defined the batchnodes and all the actions in the init of GameLevelLayer.m
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"BankerSpriteSheet_default.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"BankerSpriteSheet_default.png"];
[self addChild:spriteSheet];
[player addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <=6; ++i) {
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"banker%d.png", i]]];
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
player = [[Player alloc] initWithSpriteFrameName:#"banker1.png"];
player.WalkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
//[spriteSheet addChild:player];
}
//player = [[Player alloc] initWithFile:#"koalio_stand.png"];
player.position = ccp(100, 50);
player.scale = 0.2;
[map addChild:player z:15];
And then in my Player.m I run
[self runAction: self.WalkAction];
//I've also tried [self runAction: _WalkAction]; The result is the same
I used NSLogs to find out that the above section ([self runAction: self.WalkAction]; is being called but not finishing. This is where my crash happens, but there is NO ouput to the console as to why there is a crash.. literally just says (lldb)
The problem is one line above the actual error. You assign self with the result from [CCSprite spriteWith...] which replaces the existing self and replaces it with a CCSprite. Instead change the init line to self = [super initWithSpriteFrameName:..]
Related
I have one character sprite and i have to run multiple ccAnimation on it like run animation and jump animation. For this i have created spritesheet and assign it the frames. here is my code:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ch_run_slow.plist"];
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"ch_run_slow.png"];
[self addChild:spriteSheet];
_character = [CCSprite spriteWithSpriteFrameName:#"Ch_run_slow_12.png"];
_character.tag=1;
[spriteSheet addChild:_character];
and my animation functions are:
-(void) characterSlowRun
{
NSMutableArray *runSlowAnimFrames = [NSMutableArray array];
for (int i=1; i<=12; i++)
{
[runSlowAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"Ch_run_slow_%d.png",i]]];
}
CCAnimation *runSlow = [CCAnimation
animationWithSpriteFrames:runSlowAnimFrames delay:0.1f];
runSlowAction=[CCAnimate actionWithAnimation:runSlow];
runSlowAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:runSlow]];
[_character runAction:runSlowAction];
}
and Jump Action method is:
-(void) characterJumpSmall
{
[[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromFile:#"ch_run_slow.plist"];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ch_jump_small.plist"];
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"ch_jump_small.png"];
NSMutableArray *jumpSmallAnimFrames = [NSMutableArray array];
for (int i=1; i<=13; i++)
{
[jumpSmallAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"Ch_jump_small_%d.png",i]]];
}
CCAnimation *jumpSmall = [CCAnimation
animationWithSpriteFrames:jumpSmallAnimFrames delay:0.1f];
jumpSmallAction=[CCAnimate actionWithAnimation:jumpSmall];
[_character runAction:jumpSmallAction];
}
on init i call [self characterSlowRun]; and on ccTouchesEnded i use [_character stopAction:runSlowAction];
[self characterJumpSmall];
initially runSlow action works fine bt when tap on screen it crashes. jump action not working. what i do? please help me
You have to stop your walkSlow Action with [_charactar stopAllActions] because walkSlow is running endlessly.
Assertion failure in -[CCSprite setTexture:]. And that's all? I am sure that your error message is a bit longer. Also you can check cocos2d sources, as it is open source and see what line caused this assertion failure.
Anyway, it seems that your touble is just a result of trying to use frames from different spritesheets on a single sprite. Place your animations to a single spritesheet and it should work fine.
SpriteSheets are one thing I just can't get my head around. I'm looking for a very clear and easy to follow way to learn about them. I have read and studied up on them but still have problems.
I don't know why my code isn't working.
-(void) addPlayer {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:#"walk1.png"];
sprite.position = ccp(winSize.width/2, winSize.height/2);
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"player-walk.png"];
[batchNode addChild:sprite];
[self addChild:batchNode z:350];
NSMutableArray *frames = [NSMutableArray array];
for(int i = 1; i <= 4; ++i) {
[frames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"walk%d.png", i]]];
}
CCAnimation *anim = [CCAnimation animation];
CCAnimate *animate = [CCAnimate actionWithAnimation:anim];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:animate];
[self runAction:repeat];
}
Why is my player not animating?
Spritesheet is just a convenient way to store textures.
Your CCAnimation object has no frames. You gather an array of frames, but you never use it. Change your
CCAnimation *anim = [CCAnimation animation];
line to
CCAnimation *anim = [CCAnimation animationWithFrames:frames delay:0.2f];
If you want to animate a sprite, you have to run animating action on this sprite. Use [sprite runAction:repeat] instead of [self runAction:repeat];.
i have a cocos2d world, and a sprite/body that is moving fast .
when contact occur i am calling animation function.
The problem is , that when the animation is running in the current sprite position, the sprite was already gone to another place so animation is not in right place:
how would i run this animation function to follow my sprite ?
code:
-(void)animation:(NSString *)animation
{
NSLog(#"check:%#",animation);
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:#"%#.plist",animation]];
sprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#_00000.png",animation]]; //take the corrdinates of this picture from the plist
sprite.position=boy.position;
//sprite.position=ccp(160,175);
CCSpriteBatchNode *spriteSheet = [ CCSpriteBatchNode batchNodeWithFile:[NSString stringWithFormat:#"%#.png",animation]];
[spriteSheet addChild:sprite]; //add this coordinates from the spritesheet to the screen
[self addChild:spriteSheet];
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *animPath = [Path stringByAppendingPathComponent: [NSString stringWithFormat:#"%#.plist", animation]];
NSDictionary *animSpriteCoords = [[NSDictionary alloc] initWithContentsOfFile: animPath];
NSDictionary *animFramesData = [animSpriteCoords objectForKey:#"frames"];
int b=0;
int a=0;
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < [animFramesData count]; i++)
{
a=a+1;
if(a==10)
{
b=b+1;
a=0;
}
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%#_000%0i%1i.png",animation,b,a]]; //[NSString stringWithFormat:#"eye_blinking_0000%1d.png",i]
[animFrames addObject:frame];
}
//CCAnimation *dollAnimation = [CCAnimation animation];
CCAnimation* dollAnimation = [CCAnimation animationWithFrames:animFrames delay:0.1f];
//CCAnimation *dollAnimation = [CCAnimation animationWithName:#"dance" animationWithFrames:animFrames];
//[dollAnimation setDelay:0.1f];
CCAnimate * Action = [CCAnimate actionWithAnimation:dollAnimation];
id call=[CCCallFunc actionWithTarget:self selector:#selector(finishAnimation)];
id sequence=[CCSequence actions:Action,[CCHide action],call,nil];
[sprite runAction:sequence];
}
thnaks a lot.
CCFollow will have the animation sprite follow the boy sprite:
id follow = [CCFollow actionWithTarget:boy];
[sprite runAction:follow];
Alternative is to continuously update the animation sprite's position to that of the boy position (sprite.position = boy.position) in a scheduled update method.
i know how to animate a sprite using cocos2d , with a spritesheet and plist .
i have a world, and the sprite can move in this world when forces applied .
i need to animate that sprite, while is moving , lets say he falls down, so his eyes should be blinking while he falls ,or move etc..
my code to animate now is this, when i insert a new sprite, but i need to apply it on a specific sprite ,not on a specific place ...
-(void)animation:(NSString *)animation
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:#"%#.plist",animation]];
sprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#_00000.png",animation]]; //take the corrdinates of this picture from the plist
//sprite.position=ccp(240,160);
//sprite.position=ccp(160,175);
CCSpriteBatchNode *spriteSheet = [ CCSpriteBatchNode batchNodeWithFile:[NSString stringWithFormat:#"%#.png",animation]];
[spriteSheet addChild:sprite]; //add this coordinates from the spritesheet to the screen
[self addChild:spriteSheet];
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *animPath = [Path stringByAppendingPathComponent: [NSString stringWithFormat:#"%#.plist", animation]];
NSDictionary *animSpriteCoords = [[NSDictionary alloc] initWithContentsOfFile: animPath];
NSDictionary *animFramesData = [animSpriteCoords objectForKey:#"frames"];
int b=0;
int a=0;
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < [animFramesData count]; i++)
{
a=a+1;
if(a==10)
{
b=b+1;
a=0;
}
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%#_000%0i%1i.png",animation,b,a]]; //[NSString stringWithFormat:#"eye_blinking_0000%1d.png",i]
[animFrames addObject:frame];
}
CCAnimate *Action ;
CCAnimation* dollAnimation = [CCAnimation animationWithFrames:animFrames delay:0.1f];
Action = [CCAnimate actionWithAnimation:dollAnimation];
id call=[CCCallFunc actionWithTarget:self selector:#selector(finishAnimation)];
id sequence=[CCSequence actions:Action,[CCHide action],call,nil];
[sprite runAction:sequence];
}
You have to change the animation to walk when it start to move and change when stop in [sprite runAction:sequence];
I have created an animating sprite using CCSpriteBatchNode and CCSprite. I use plist to get frames. Here is the code I put it in init().
//================== making animating sprite
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"framelist.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"frames.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 2; ++i) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"frame%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation
animationWithFrames:walkAnimFrames delay:0.1f];
//_frameSprite is CC Sprite
_frameSprite = [CCSprite spriteWithBatchNode:spriteSheet
rect:CGRectMake(0,0,48,48)];
_frameSprite.position = ccp(winSize.width + 60, winSize.height/2);
_flyAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[_frameSprite runAction:_flyAction];
[spriteSheet addChild:_frameSprite];
Once the sprite is ready and running on screen I created b2BodyDef and assign b2Body (i.e. frameBodyDef, frameBody) my sprite as shown below.
b2BodyDef frameBodyDef;
frameBodyDef.type = b2_staticBody;
frameBodyDef.position.Set(160/PTM_RATIO, 200/PTM_RATIO);
frameBodyDef.userData = _frameSprite;
frameBody = _world->CreateBody(&frameBodyDef);
After creating the body, when build and ran, the program crashes at line
frameBody = _world->CreateBody(&frameBodyDef);
Saying BAD ACCESS.
Please kindly help me out in this, why the animating sprite cannot be added to the body???
Thank you.
Here is the solution I figure it out.
If you make sprite sheet from plist and want your animation sheet to add to the body make sure first add your sprite object to the body then add the sprite to the sheet.
here is the right code
//================== making animating sprite
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"framelist.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"frames.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 2; ++i) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"frame%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation
animationWithFrames:walkAnimFrames delay:0.1f];
//_frameSprite is CC Sprite
_frameSprite = [CCSprite spriteWithBatchNode:spriteSheet
rect:CGRectMake(0,0,48,48)];
_frameSprite.position = ccp(winSize.width + 60, winSize.height/2);
_flyAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[_frameSprite runAction:_flyAction];
b2BodyDef frameBodyDef;
frameBodyDef.type = b2_staticBody;
frameBodyDef.position.Set(160/PTM_RATIO, 200/PTM_RATIO);
frameBodyDef.userData = _frameSprite; //================first add the sprite to body
frameBody = _world->CreateBody(&frameBodyDef);
[spriteSheet addChild:_frameSprite]; //======second add sprite to the sheet