如果你使用 cocos2d 2.0,现在有一个基于每帧的通知。直接来自文档:
/*******************/
/** Notifications **/
/*******************/
/** @def CCAnimationFrameDisplayedNotification
Notification name when a CCSpriteFrame is displayed
*/
#define CCAnimationFrameDisplayedNotification @"CCAnimationFrameDisplayedNotification"
创建动画时,您可以向每一帧添加将与通知一起接收的 userInfo 字典。这是来自 CCActionInterval 的行:
NSDictionary *dict = [frame userInfo];
if( dict )
[[NSNotificationCenter defaultCenter]
postNotificationName:CCAnimationFrameDisplayedNotification
object:target_
userInfo:dict
];
所以我想你可以为第 3 帧和第 8 帧添加一个 dict 对象,并在通知回调中“做你的事”。
ob cit:没有尝试过,但应该适合你。
编辑:现在试过了。在我的游戏的一个战斗控制器类中,我花了一个小时将一个非常笨拙的基于时间的算法转换为一个可靠的事件驱动实现。我只收到 2 帧的通知:攻击动画的第 9 帧(我现在可以完美同步播放武器声音)和受伤动画的第 11 帧(如果受害者死了,我可以停下来动画并慢慢淡出小动物)。cocos2d 团队走的路。不是那么难,API 干净明了。
这是代码的一部分(我的第一次破解,并不自豪:)),代码使用了我的其他一些东西,但您应该能够从总体思路开始。
-(void) registerForFrames{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(gotFrame:)
name:CCAnimationFrameDisplayedNotification
object:nil];
}
-(void) deregisterForFrames {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:CCAnimationFrameDisplayedNotification
object:nil];
}
-(NSDictionary *) frameEventForFrameNumber:(NSUInteger) frameNumber
animation:(NSString *) animationType {
return [[FrameEvent frameEventForListener:frameListenerCombatController
animationName:animationType
frameNumber:frameNumber] asDictionary];
}
-(FrameEvent*) frameEventForFrame:(NSDictionary *) theDic{
return [FrameEvent frameEventListenerWithContentsOfDictionary:theDic];
}
-(void) gotFrame:(id) notification{
NSDictionary *userInfoDictionary = [notification userInfo];
FrameEvent *ev = [self frameEventForFrame:userInfoDictionary];
if (!ev) {
MPLOGERROR(@"*** userInfo returned nil frameEvent object, bailing out!");
return;
}
if (ev.frameListenerType==frameListenerUnknown){
MPLOGERROR(@"*** Got served an unknown dictionary, bailing out!");
return;
}
if (ev.frameListenerType==frameListenerCombatController) {
MPLOG(@"Got Frame %@",ev.description);
if([ev.animationName isEqualToString:@"attack"]) {
[self scheduleOnce:@selector(attackTurnAround) delay:0.];
}
if ([ev.animationName isEqualToString:@"hurt"]) {
// more here !
MPLOG(@"TODO : schedule dead critter method");
}
} else {
MPLOGERROR(@"*** Not processing frame listener of type [%@], bailing out!",
[GEEngineSpecs frameListenerAsString:ev.frameListenerType]);
}
}
最后是关键部分,将用户信息放在框架上:
- (CCAction *)attackActionFor:(GEClassAnimationSpec *)animSpec playerAsString:(NSString *)playerKey {
NSMutableArray *animFrames = [NSMutableArray array];
for (int i = 1; i <= animSpec.frames; i++) {
NSString *sfn = [NSString stringWithFormat:@"%@%@%i.png", animSpec.fileName, playerKey, i];
CCSpriteFrame *sf = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:sfn];
[animFrames addObject:sf];
}
float animFrameDelay = 1.0f / K_ATTACK_FRAME_RATE;
CCAnimation *anim = [CCAnimation animationWithSpriteFrames:animFrames delay:animFrameDelay];
anim.restoreOriginalFrame = NO;
CCAnimationFrame * ninth = [anim.frames objectAtIndex:8];
NSDictionary *ui = [self frameEventForFrameNumber:9 animation:@"attack"];
ninth.userInfo=ui;
CCAction *action = [CCSequence actions:
[CCAnimate actionWithAnimation:anim],
[CCCallFunc actionWithTarget:self selector:@selector(resumeAttackerIdle)],
nil
];
return action;
}