【问题标题】:how to determine when specific animation frames are running如何确定特定动画帧何时运行
【发布时间】:2013-07-09 08:38:54
【问题描述】:

我想知道动画的某些帧何时运行以设置各种条件。在下面的代码中,如何使用计数器或设置条件来确定特定动画帧(例如第 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];

【问题讨论】:

    标签: animation cocos2d-iphone


    【解决方案1】:

    如果您使用 cocos2d 2.0,现在会按帧提供通知。直接来自文档:

    /*******************/
    /** Notifications **/
    /*******************/
    /** @def CCAnimationFrameDisplayedNotification
        Notification name when a CCSpriteFrame is displayed
     */
    #define CCAnimationFrameDisplayedNotification @"CCAnimationFrameDisplayedNotification"
    

    创建动画时,您可以向每一帧添加一个用户信息字典,该字典将随通知一起接收。这是来自 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;
    }
    

    【讨论】:

    • 感谢您的回答。如果您能解释gotFrameframeEventForFrameNumberframeEventForFrameNumber 方法中发生的情况,我将不胜感激。另外我想知道frameEventListenerWithContentsOfDictionaryframeEventForListenerFrameEvent的定义。
    • FrameEvent 是我刚刚为我自己的目的而创建的一个类,它为我提供了一种标准方法来管理在“gotFrame”类型的回调中发生的事情。您可以使用任何普通的 NSDictionry 对象,您可以根据自己的需要定义其内容。我这样做是因为我计划在我的应用程序的多个控制器中拥有“框架”通知,只是在这里提前计划。
    • 所以最主要的是attackActionFor方法。
    • 我有点搞混了。我真的不确定要为我的字典定义什么,就像您在上面的 NSDictionary *ui = [self frameEventForFrameNumber:9 animation:@"attack"]; 中所做的那样。请帮忙。
    【解决方案2】:

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

    认为每次任何一个精灵碰到那个帧时它都会触发通知,我最终放弃了那段代码,因为我不知道如何协调哪个精灵触发它,并且最终采用了不同的方法,因为我无法让它发挥作用。

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

    【讨论】:

    • 这应该是对另一个答案的评论,而不是它自己的答案。如果您提到您的不同方法作为答案,那将更加有益。
    • @redux :见下面的代码,我在第一次单元测试中得到了“表现”。
    猜你喜欢
    • 2023-03-31
    • 1970-01-01
    • 2021-07-22
    • 2022-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-02
    相关资源
    最近更新 更多