0

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)

tyler53
  • 429
  • 1
  • 5
  • 16
  • You didn't post the line where you actually send the setWalkAction: message (likely property, like so: self.WalkAction = x). Either way, the error is pretty clear, you're sending the message to a class (CCSprite) that does not implement the setWalkAction: selector. – CodeSmile Jun 06 '13 at 20:29
  • Btw, you don't need a batch node if you're using this solely for the player sprite, as it will still be only one sprite causing one draw call either way. – CodeSmile Jun 06 '13 at 20:31
  • I needed the batchnode because I am now trying to create the walking animation as the character walks. And the line is there, its right underneath the definition for the CCAnimation walkAnim (I edited it in the code to show you where it is @LearnCocos2D – tyler53 Jun 06 '13 at 22:20
  • Also WalkAction is a property of the class @property (nonatomic, assign) CCAction *WalkAction; – tyler53 Jun 06 '13 at 22:22
  • So would I be better off defining the actions and batchnodes and spritesheets and all of this in the GameLevelLayer init? If so, how would I implement that back into the player class – tyler53 Jun 06 '13 at 22:23
  • I've updated the question a little bit. take a look – tyler53 Jun 06 '13 at 22:40
  • hmmmm i did a find and didn't show up, maybe a typo. I see the error now. – CodeSmile Jun 06 '13 at 22:59
  • ps: you don't need a batchnode for the animations, it's still the same spriteso no need to "batch draw" it. Batch nodes are not a prerequisite for animations. – CodeSmile Jun 06 '13 at 23:00
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/31372/discussion-between-tyler53-and-learncocos2d) – tyler53 Jun 07 '13 at 06:20

1 Answers1

0

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:..]

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
  • I updated the question with my new form of the issue, I moved it to the GameLevelLayer class, is this wrong? – tyler53 Jun 07 '13 at 00:31
  • okay so I tried putting self = [super initWithSpriteFrameName: @"banker1.png"] where the if(self = [super init]) usually goes (It looks like this now in player.m) `-(id)init{ if(self = [super initWithSpriteFrameName:@"banker1.png"]){}}` and now when I run I get the error in the GameLevelLayer.m where I do [map addchild:player]; saying that player is nil – tyler53 Jun 07 '13 at 00:37
  • you also need to load the sprite frames into cache *before* initWithSpriteFrameName – CodeSmile Jun 07 '13 at 06:14
  • can we carry this on into chat, this is really frustrating me that I can't understand this :( – tyler53 Jun 07 '13 at 06:20
  • or skype? or whatever you can, i'd really appreciate it if you had the time @LearnCocos2D – tyler53 Jun 07 '13 at 06:24