2

我想知道动画的某些帧何时运行以设置各种条件。在下面的代码中,如何使用计数器或设置条件来确定特定动画帧(例如第 3 帧和第 8 帧)当前正在运行的时间?

NSMutableArray *frameArray = [NSMutableArray array];
 for(int i = 1; i < 12; i++) 
{
    CCLOG(@"item %d added", i);
    [frameArray addObject:
     [birdSpriteFrameCache spriteFrameByName:
      [NSString stringWithFormat:@"Sprite%d.png", i]]];    } 

//Starting the Animation
CCAnimation *animation = [CCAnimation animationWithSpriteFrames:frameArray delay: 0.3];

id action =[CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation :animation]];
[firstSprite runAction:action];
4

2 回答 2

2

如果你使用 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;
}
于 2013-07-09T12:48:13.510 回答
0

正如其他人提到的那样,这是在通知中,但作为提醒:前段时间我遇到了一些麻烦,当时我有 2 个不同的精灵从稍微不同的时间开始运行相同的动画。

认为每次任何一个精灵命中该帧时它都会触发通知,我最终放弃了那段代码,因为我无法弄清楚如何协调哪个精灵触发它,并以不同的方法结束,因为我不能让它表现出来。

如果您得到古怪的结果,请注意一些事情。

于 2013-07-09T15:21:47.640 回答