how to determine when specific animation frames are running

不羁岁月 提交于 2019-12-22 13:56:59

问题


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

回答1:


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"

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

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: not tried, but should work for you.

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



回答2:


This is in notifications as someone else mentioned, but as a heads up: I had some trouble with this a while ago when I had 2 different sprites running the same animation starting at slightly different times.

I think it was triggering the notification every time either sprite hit that frame, and I eventually scrapped that chunk of code because I couldn't figure out how to coordinate which sprite was triggering it, and wound up with a different approach because I couldn't get it to behave.

Just something to watch for if you're getting wacky results.



来源:https://stackoverflow.com/questions/17543659/how-to-determine-when-specific-animation-frames-are-running

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!