如何确定特定动画帧何时运行

如何确定特定动画帧何时运行

本文介绍了如何确定特定动画帧何时运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to know when certain frames of an animation are running in order to set various conditions. In the code below, how can I use a counter or set conditions to determine when specific animation frames, say 3rd and 8th are currently running?

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];


推荐答案

如果您使用cocos2d 2.0,以每帧为基础进行服务。直接从文档:

If you use cocos2d 2.0, there is now a notification being served on a per frame basis. Straight from the docs:

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

创建动画时,您可以向每个框架添加一个将随通知一起接收的userInfo字典。这是来自CCActionInterval的行:

When creating an animation, you can add to each frame a userInfo dictionary that will be received with the notification. Here is the line from CCActionInterval :

NSDictionary *dict = [frame userInfo];
if( dict )
    [[NSNotificationCenter defaultCenter]
          postNotificationName:CCAnimationFrameDisplayedNotification
          object:target_
          userInfo:dict
    ];

所以我想你可以添加一个dict对象框架3和8和'做你的事通知回拨。

so i guess you can add a dict object for frames 3 and 8 and 'do your thing' in the notification call back.

ob cit:未尝试,但应该为您工作。

ob cit: not tried, but should work for you.

尝试。我花了我一个小时,把一个非常笨重的基于时间的算法转换为一个坚实的事件驱动的实现在我的一个游戏的combatController类。我得到的通知只有2帧:攻击动画的第9帧(我现在可以完美同步播放武器声音)和伤害动画的第11帧(其中,如果受害者死亡,我可以停止动画和慢慢淡出小动物)。方式去cocos2d团队。不是所有的硬,API是干净和脆。

EDIT : now tried. It took me all but one hour to convert a very clunky time-based algorithm to a solid event-driven implementation in one of my game's combatController class. I get served a notification for 2 frames only : the 9th frame of the attack animation (where i can now in perfect sync play a weapon sound) and the 11th frame of the hurt animation (where, if the victim dies, i can just stop the animation and fade out slowly the critter). Way to go cocos2d team. Not all that hard, the API is clean and crisp.

这里是代码的一部分(我的第一个破解,不自豪:)),代码使用我的其他一些东西,但你应该能够开始

Here is part of the code (my first crack at it, not proud :) ) , the code uses some of my other stuff but you should be able to get started with the general idea.

-(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]);
    }
}

最后是关键部分,框架:

and finally the key part, put a user info on a frame :

- (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;
}

这篇关于如何确定特定动画帧何时运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 14:58