• CocosBuilder 学习笔记(3) AnimationManager 与 ccbi 文件解析


    1. 相关的类

    先介绍和AnimationManager相关的几个类:

    CCBSequence

    时间线。有成员duration(时间线时间,默认10秒)、name(时间线名)、SequenceId(Id)、ChainedSequenceId(重复执行的时间线Id)、SequenceProperty* mCallbackChannel(关键帧执行回调)、SequenceProperty* mSoundChannel(关键帧执行Sound)。

    CCBSequenceProperty

    存储keyframe的容器。

    有成员name、int type、Vector keyframes(存储关键帧keyframe)。

    对于动画而言,Property的name是动画改变的属性的名字,例如position、rotation等。

    CCBKeyframe

    关键帧。CCB的动画是以关键帧为基础的,我们可以在时间线上设置关键帧,并为关键帧设置属性,CCB能够实现在关键帧之间实现动画。关键帧不仅可以用来设置动画属性,也能用于触发回调、声音。

    有相关成员value(属性值)、time(发生的时间)、EasingType easingType(特效类型)、easingOpt(特效的值,部分特效有用)。

    一个动画,需要关键帧才能呈现出动画效果。

    2. 部分成员变量

    CCBReader有成员animationManager,关联了一个动画管理器。还有成员Map<Node*, CCBAnimationManager*> animationManagers,将解析到的node和动画管理器关联。

    AnimationManager是CCB项目中所有动画的管理中心。

    成员Vector sequences,实际存储的是动画的时间线。

    成员map<Node*, map<int, Map<string, SequenceProperty*>>> nodeSequences,其结构较复杂,用下图较为容易理解:

    简而言之:

    nodeSequences存储的是动画管理器管理的node和node对应的所有Property,Property存储关键帧,同一Property存储的关键帧是在同一变换(动画的属性、回调等)中起作用的。

    node对应的Property按照Property所属的时间线(Sequence)Id进行分类。

    3. 解析过程中 AnimationManager 相关操作

    解析ccbi文件之前,设置成员rootContainerSize为屏幕大小,设置成员owner为this(执行CCBReader解析方法的场景或层)。

    在解析ccbi文件时,执行CCBReader的readSequences方法解析时间线设置Sequence成员变量,每个时间线存储到容器sequences之中,并设置动画管理器成员autoPlaySequenceId,作为自动执行的时间线Id。

    对于每个时间线,还可以设置CallbackChannel和SoundChannel,这两者都是SequenceProperty类型,在关键帧执行回调或声音。

    接下来执行readNodeGraph方法,设置node相关的动画内容,并存储到容器nodeSequences之中。项目的根节点Layer作为成员rootNode。

    .ccbi文件解析完成之后,把根节点Layer和动画管理器加入CCBReader成员容器animationManagers之中。

    之后执行CCBReader关联的animationManager的runAnimationsForSequenceIdTweenDuration方法,参数:自动执行的时间线Id(解析文件时获取并设置的),0。

    4. runAnimationsForSequenceIdTweenDuration 方法

    就动画方面,readNodeGraph方法只是将动画需要的属性设置到了关键帧,并存储在动画管理器的容器中。真正将关键帧的动画属性转为实际的动画效果是依赖本方法。

    1. 删除根节点Layer的所有action(removeAllActionsFromTarget)。

    2. 遍历nodeSequences。对node删除所有action。获取当前node在当前时间线Id上的所有Property。

    3. 遍历这些Property。对每个Property,先通过第一个关键帧设置初始状态。再设置动作序列。

    动作序列设置流程:

    1. Property内的关键帧数量最少为2。

    2. 根据第一个关键帧的起始时间,设置延迟动作DelayTime。

    3. 创建两帧之间的动作。两帧时间差作为动作时间,第二帧的状态作为动作结束时的状态。动作特效保存在第一帧,读取第一帧中的特效,对动作进行包装,得到新动作。

    4. 还有帧的情况下,进行循环,帧下标+1,对此时两帧执行第三步(创建两帧的动作)。

    5. 所有动作加入动作序列,对当前node执行动作序列(runAction)。

    4. 获取当前时间线时间长度,根节点layer在时间线结束时,执行函数动作调用函数AnimationManager::sequenceCompleted。

    回调函数是在时间线结束后,可以通过ChainedSequenceId,设置并执行要重复执行的时间线。

    5. 通过CallbackChannel的关键帧,生成一个回调函数动作序列,根节点Layer执行该动作序列(runAction)。

    6. 通过SoundChannel的关键帧,生成一个声音动作序列,根节点Layer执行该动作序列(runAction)。

    7. 此时的时间线Id作为runningSequence。在时间线运行结束后调用的sequenceCompleted方法会获取该值,用来获取当前时间线,从而设置下一时间线id并执行下一时间线。

    5. 总结

    CCB动画的实质是多个动作的组合。

    在解析ccbi文件NodeGraph后,时间线和动画相关内容已经全部读取完成,并存储到了相应的容器里。接下来就要根据容器内动画相关内容,设置动作,并交给对应的node执行动作。

    node的动画信息(关键帧)是由SequenceProperty存储,通过AnimationManager的容器关联Node和Property。

    node可能在多个时间线有动画,所以要通过时间线Id给Node的Property进行分类。

    Sequence仅作为时间线使用。时间线也有Property,其中的关键帧作为触发回调函数或声音使用。

  • 相关阅读:
    cors解决跨域
    神经网络和keras
    tensorflow笔记
    5.聚类算法-kmeans
    4.回归类算法-目标值连续型
    3.分类算法-目标值离散型
    Phaser.js开发小游戏之洋葱头摘星星
    VS Code 插件之 vscode-debug-visualizer
    Phaser.js开发小游戏之Phaser.js介绍
    微信小程序中写threejs系列之 threejs-miniprogram
  • 原文地址:https://www.cnblogs.com/deepcho/p/cocosbuiler-animationmanager-sequence-property-keyframe.html
Copyright © 2020-2023  润新知