0
votes

I started playing around with Cocos2D and I figured out to do a sprite animation with sprite sheets.

Now I have a little robot walking around on my screen. But I am wondering how I can put one animation into another.

For example, my robot has a walking animation and I want to move his arms separately. But his shoulders will rise and fall during walking and the arms should move relative to his shoulder position.

My walk animation has five sprites and I have nine different arm positions. Now, I could add the arms to every single walking sprite for all nine arm positions. but then I would have 45 Images instead of 14.

1
you robot needs to be a spritesheet - Grady Player

1 Answers

0
votes

That's a good question (finally!).

What I would do is separate your character into different sprites (you already did this) that are animatable on their own.

Then, whenever a frame of that animation is presented, I would have a block of code executed that modified the position of the arms animation, so it matches the shoulders.

To execute that block of code, you'd need Cocos 1.1 or better, since they added the CCAnimationFrame there, however, those frames can only execute code via an NSNotification, so I made an improvement so we can set a block on a frame, and that block would be executed whenever that frame is displayed.

Just find CCAnimation.h and modify the CCAnimationFrame interface to look like this:

typedef void(^FrameBlock)(CCSprite *sprite);

/** CCAnimationFrame
 A frame of the animation. It contains information like:
 - sprite frame name
 - # of delay units.
 - offset

 @since v1.1
 */
@interface CCAnimationFrame : NSObject <NSCopying>
{
    CCSpriteFrame* spriteFrame_;
    float delayUnits_;
    NSDictionary *userInfo_;

    FrameBlock frameBlock;
}
/** CCSpriteFrameName to be used */
@property (nonatomic, readwrite, retain) CCSpriteFrame* spriteFrame;

/**  how many units of time the frame takes */
@property (nonatomic, readwrite) float delayUnits;

/**  A CCAnimationFrameDisplayedNotification notification will be broadcasted when the frame is displayed with this dictionary as UserInfo. If UserInfo is nil, then no notification will be broadcasted. */
@property (nonatomic, readwrite, retain) NSDictionary *userInfo;

/**  If the block is not NULL, it will be executed when the frame becomes visible **/
@property (nonatomic, readwrite, copy) FrameBlock frameBlock;

/** initializes the animation frame with a spriteframe, number of delay units and a notification user info */
-(id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame delayUnits:(float)delayUnits userInfo:(NSDictionary*)userInfo;
-(id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame delayUnits:(float)delayUnits block:(FrameBlock)block;
@end

And then open CCAnimation.m and make sure the CCAnimationFrame implementation looks like this:

@implementation CCAnimationFrame

@synthesize spriteFrame = spriteFrame_, delayUnits = delayUnits_, userInfo=userInfo_;

@synthesize frameBlock;

-(id) initWithSpriteFrame:(CCSpriteFrame *)spriteFrame delayUnits:(float)delayUnits userInfo:(NSDictionary*)userInfo
{
    if( (self=[super init]) ) {
        self.spriteFrame = spriteFrame;
        self.delayUnits = delayUnits;
        self.userInfo = userInfo;
    }

    return self;
}

-(id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame delayUnits:(float)delayUnits block:(FrameBlock)block{
    self = [self initWithSpriteFrame:spriteFrame delayUnits:delayUnits userInfo:nil];
    if(self){
        [self setFrameBlock:block];
    }
    return self;
}

-(void) dealloc
{    
    CCLOGINFO( @"cocos2d: deallocing %@", self);

    [spriteFrame_ release];
    [userInfo_ release];

    [super dealloc];
}

-(id) copyWithZone: (NSZone*) zone
{
    CCAnimationFrame *copy = [[[self class] allocWithZone: zone] initWithSpriteFrame:[[spriteFrame_ copy] autorelease] delayUnits:delayUnits_ userInfo:[[userInfo_ copy] autorelease] ];
    return copy;
}

-(NSString*) description
{
    return [NSString stringWithFormat:@"<%@ = %08X | SpriteFrame = %08X, delayUnits = %0.2f >", [self class], self, spriteFrame_, delayUnits_ ];
}
@end

Then, when creating the animation frames, add a block to them in which you set the position of the arms to match the shoulders.

I hope it helps.