I'm assuming that someone will either tell me I wasted my time and there is an easier way of doing this, or someone will poke a hole in what I wrote. Either way, here is what I came up with in case anyone else would like to use it.
The normal and disabled sprites you animate as normal, however In my case I needed the selected animation to finish playing before I triggered my call back. To do this I had to wrap up the selected animation in a sequence that bypassed the normal selected/activation code.
@interface AnimatedMenuItem : CCMenuItemSprite {
CCFiniteTimeAction *selectedAction_;
CCSequence *selectedSequence_;
}
@property(nonatomic,readwrite,retain) CCFiniteTimeAction *selectedAction;
- (void)selectedSequenceCompleted
@end
@implementation FIAnimatedMenuItem
@synthesize selectedAction = selectedAction_;
-(void) onEnter {
// call base implementation
[super onEnter];
// call the implementation of the images
if ([self isEnabled]) {
if ([self isSelected]) {
[selectedImage_ onEnter];
}
else {
[normalImage_ onEnter];
}
}
else {
[disabledImage_ onEnter];
}
}
-(void) onEnterTransitionDidFinish {
// call base implementation
[super onEnterTransitionDidFinish];
// call the implementation of the images
if ([self isEnabled]) {
if ([self isSelected]) {
[selectedImage_ onEnterTransitionDidFinish];
}
else {
[normalImage_ onEnterTransitionDidFinish];
}
}
else {
[disabledImage_ onEnterTransitionDidFinish];
}
}
-(void) onExit {
// call base implementation
[super onEnter];
// call the implementation of the images
if ([self isEnabled]) {
if ([self isSelected]) {
[selectedImage_ onExit];
}
else {
[normalImage_ onExit];
}
}
else {
[disabledImage_ onExit];
}
}
-(void) activate {
// Should we delay the activation?
if (selectedSequence_ == nil) {
[super activate];
}
}
-(void) selected {
[super selected];
if (isEnabled_) {
if (selectedImage_) {
if (selectedAction_) {
// Create a sequence to run the selected action then trigger activate
[selectedSequence_ release];
id actionCallFunc = [CCCallFunc actionWithTarget:self selector:@selector(selectedSequenceCompleted)];
selectedSequence_ = [[CCSequence actions:selectedAction_, actionCallFunc, nil] retain];
[selectedImage_ runAction:selectedSequence_];
}
[selectedImage_ onEnter];
[normalImage_ onExit];
}
}
}
-(void) unselected {
if (selectedSequence_ && [selectedSequence_ isDone] == NO) {
return;
}
[super unselected];
if (isEnabled_) {
if (selectedImage_) {
[selectedImage_ onExit];
[normalImage_ onEnter];
}
}
}
-(void) setIsEnabled:(BOOL)enabled {
[super setIsEnabled:enabled];
if (enabled) {
[disabledImage_ onExit];
if ([self isSelected]) {
[selectedImage_ onEnter];
[normalImage_ onExit];
}
else {
[selectedImage_ onExit];
[normalImage_ onEnter];
}
}
else {
[disabledImage_ onEnter];
[selectedImage_ onExit];
[normalImage_ onExit];
}
}
- (void)selectedSequenceCompleted {
[super activate];
[self unselected];
}
- (void)dealloc {
[self.selectedAction release];
[selectedSequence_ release];
[super dealloc];
}
@end
To use it, here is a modified test
CGSize s = [[CCDirector sharedDirector] winSize];
// IMPORTANT:
// The sprite frames will be cached AND RETAINED, and they won't be released unless you call
// [[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"grossini.plist"];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"grossini_blue.plist"];
//
// Animation using Sprite Sheet
//
CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:@"grossini_dance_01.png"];
sprite.position = ccp( s.width/2-80, s.height/2);
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < 15; i++) {
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"grossini_dance_%02d.png",i]];
[animFrames addObject:frame];
}
CCAnimation *normalAnimation = [CCAnimation animationWithName:@"dance" delay:0.2f frames:animFrames];
[sprite runAction: [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:normalAnimation restoreOriginalFrame:NO ]]];
CCSprite *touchedSprite = [CCSprite spriteWithSpriteFrameName:@"grossini_blue_01.png"];
touchedSprite.position = ccp( s.width/2-80, s.height/2);
NSMutableArray *blueAnimFrames = [NSMutableArray array];
for(int i = 1; i < 5; i++) {
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"grossini_blue_%02d.png",i]];
[blueAnimFrames addObject:frame];
}
CCAnimation *touchedAnimation = [CCAnimation animationWithName:@"blueDance" delay:0.2f frames:blueAnimFrames];
id actionAnimate = [CCAnimate actionWithAnimation:touchedAnimation restoreOriginalFrame:NO];
//[self addChild: sprite];
AnimatedMenuItem * testMenuItem = [AnimatedMenuItem itemFromNormalSprite:sprite selectedSprite:touchedSprite target:self selector:@selector(animationClicked:) ];
testMenuItem.selectedAction = actionAnimate;
CCMenu *menu = [CCMenu menuWithItems: testMenuItem, nil];
// Add the menu
[self addChild: menu];