cocos 动画系统

前面的话

  cocos 动画系统支持任意组件属性和用户自定义属性的驱动,再加上可任意编辑的时间曲线和移动轨迹编辑功能,就能够制做出各类动态效果node

 

概述

   Animation 组件能够以动画方式驱动所在节点和子节点上的节点和组件属性,包括用户自定义脚本中的属性数组

  点击属性检查器下面的添加按钮,而后从添加其余组件中选择Animation,便可添加 Animation 组件到节点上编辑器

【属性】函数

  Default Cilp: 默认的动画剪辑,若是这一项设置了值,而且 Play On Load 为 true,那么动画会在加载完成后自动播放 Default Clip 的内容oop

  Clips: 列表类型,默认为空,在这里面添加的 AnimationClip 会反映到动画编辑器中,用户能够在动画编辑器里编辑 Clips 的内容动画

  Play On Load: 布尔类型,是否在动画加载完成后自动播放 Default Clip 的内容this

 

CLIP

  cocos Animation是节点上的一个组件,clip 动画剪辑是一份动画的声明数据,将它挂载在 Animation 组件上,就能够将这份动画数据应用到节点上spa

  数据中索引节点的方式是以挂载 Animation 组件的节点为根节点的相对路径,因此在同一个父节点下的同名节点,只可以产生一份动画数据,而且只能应用到第一个同名节点上插件

【参数】  code

sample: 定义当前动画数据每秒的帧率,默认为60,这个参数会影响时间轴上每两个整数秒刻度之间的帧数量,也就是两秒以内有多少格
speed: 当前动画的播放速度,默认为1
duration: 当动画播放速度为1时,动画的持续时间
real time: 动画从开始播放到结束,真正持续的时间
wrap mode: 循环模式

【动态建立】

    var animation = this.node.getComponent(cc.Animation);
    // frames 这是一个 SpriteFrame 的数组.
    var clip = cc.AnimationClip.createWithSpriteFrames(frames, 17);
    clip.name = "anim_run";
    clip.wrapMode = cc.WrapMode.Loop;

    // 添加帧事件
    clip.events.push({
        frame: 1,               // 准确的时间,以秒为单位。这里表示将在动画播放到 1s 时触发事件
        func: "frameEvent",     // 回调函数名称
        params: [1, "hello"]    // 回调参数
    });

    animation.addClip(clip);
    animation.play('anim_run');

 

动画编辑器

  动画在普通模式下是不容许编辑的,只有在动画编辑模式下,才可以编辑动画文件,可是在编辑模式下,没法对节点进行 增长/删除/更名操做

  动画编辑器一共能够划分为 6 个主要部分

  一、经常使用按钮区域,这里负责显示一些经常使用功能按钮,从左到右依次是:开关录制状态、返回第一帧、上一帧、播放/暂停、下一帧、新建动画剪辑、插入动画事件

  二、时间轴与事件,这里主要是显示时间轴,添加的自定义事件也会在这里显示

  三、层级管理(节点树),当前动画剪辑能够影响到的节点数据

  四、节点内关键帧的预览区域,这里主要是显示各个节点上的全部帧的预览时间轴

  五、属性列表,显示当前选中的节点在选中的动画剪辑中已经包含了的属性列表

  六、关键帧,每一个属性相对应的帧都会显示在这里

【时间轴】

  时间轴上刻度的表示法是 01-05,该数值由两部分组成,冒号前面的是表示当前秒数,冒号后面的表示在当前这一秒里的第几帧

  01-05 表示该刻度在时间轴上位于从动画开始通过了 1 秒又 5 帧的时间

  由于帧率能够随时调整,所以同一个刻度表示的时间点也会随着帧率变化而有所不一样

  当帧率为 30 时,01-05 表示动画开始后 1 + 5/30 = 1.1666 秒

  当帧率为 10 时,01-05 表示动画开始后 1 + 5/10 = 1.5 秒

  虽然当前刻度表示的时间点会随着帧率变化,但一旦在一个位置添加了关键帧,该关键帧所在的总帧数是不会改变的,假如咱们在帧率 30 时向 01-05 刻度上添加了关键帧,该关键帧位于动画开始后总第 35 帧。以后把帧率修改成 10,该关键帧仍然处在动画开始后第 35 帧,而此时关键帧所在位置的刻度读数为 03-05,换算成时间之后正好是以前的 3 倍

【基本操做】

更改时间轴缩放比例:滚动鼠标滚轮,能够放大,或者缩小时间轴的显示比例
移动显示区域: 按下鼠标右键拖拽
更改当前选中的时间轴节点: 在时间轴区域内点击任意位置或拖拽,或者在上图 4 区域拖拽标示的红线
修改 clip 属性: 在插件底部,修改对应属性,在输入框失去焦点时会更新到实际的 clip 数据中

【快捷键】

left 向前移动一帧,若是已经在第 0 帧,则忽略当前操做
right 向后移动一帧
delete 删除当前选中的关键帧
k 正向播放动画,抬起后中止
j 反向插话动画,抬起后中止
cmd + left 跳转到第 0 帧
cmd + right 跳转到有效的最后一帧

 

动画剪辑

【建立 Animation 组件】

  若是要在节点上建立动画,必须为它新建一个 Animation 组件,建立的方法有两种:

  一、选中相应的节点,在属性检查器中点击右上方的 +,或者下方的 添加组件, 在其余组件中选择 Animation

  二、打开动画编辑器,而后在层级管理器中选中须要添加动画的节点,在动画编辑器中点击 添加Animation组件 按钮

【建立与挂载动画剪辑】

  动画剪辑有两种建立方式:

  一、在资源管理器中点击左上方的 +,或者右键空白区域,选择 Animation Clip,这时会在管理器中建立一个名为 'New AnimationClip'的剪辑文件。在层级管理器中点选刚刚的节点,在属性检查器中找到 Animation,这时的 Clips 显示的是 0,将它改为1,而后将刚刚在资源管理器中建立的'New AnimationClip',拖入刚刚出现的 animation-clip 选择框内

  二、若是 Animation 组件中尚未添加动画剪辑文件,则能够在动画编辑器中直接点击 新建 AnimationClip 按钮,根据弹出的窗口建立一个新的动画剪辑文件。要注意的是,若是选择覆盖已有的剪辑文件,被覆盖的文件内容会被清空

【数据剪辑】

  一个动画剪辑内可能包含了多个节点,每个节点上挂在多个动画属性,每一个属性内的数据才是实际的关键帧

  动画剪辑经过节点的名字定义数据的位置,自己忽略了根节点,其他的子节点经过与根节点的相对路径索引找到对应的数据

  若是在制做完成动画后,将节点重命名,会形成动画数据出现问题,以下图所示

  这时,要手动指定数据对应的节点,能够将鼠标移入节点,点击节点右侧出现的更多按钮,并选择“移动数据”

  如上图所示,New Node/test 节点没有数据,想将 /New Node/efx_flare 上的数据移到这里

  一、鼠标移动丢失的节点 /New Node/efx_flare 上

  二、点击右侧出现的按钮

  三、选择移动数据

  四、将路径改成 /New Node/test,并回车

 

编辑动画序列

  动画属性包括了节点自有的 position、rotation 等属性,也包含了组件 Component 中自定义的属性。组件包含的属性会加上组件的名字,好比 cc.Sprite.spriteFrame

【添加新的属性轨道】

  先选中节点,而后在属性区域右上角点击 +。弹出菜单中,选中想要添加的属性,就会对应新增一个轨道

【删除一个属性轨道】

  将鼠标焦点移动到要删除的属性轨道上,右边会显示一个“三道杠”按钮,点击按钮,在弹出菜单中选择删除属性,选中后对应的属性就会从动画数据中删除

【添加关键帧】

  在属性列表中点击对应属性轨道右侧的“三道杠”按钮,在弹出的菜单中选择 插入关键帧 按钮

【选择关键帧】

  点击建立的关键帧后,关键帧会呈现选中状态,此时关键帧由蓝变白,若是须要多选,能够按住 ctrl 再次选择其余关键帧,或者直接在属性区域拖拽框选择

【移动关键帧】

  将鼠标移动到任意一个被选中的关键帧上,按下鼠标左键,鼠标会变换成左右箭头,这时就能够拖拽全部被选中的节点了

【更改关键帧】

  在时间轴上须要修改的关键帧,直接在属性检查器内修改相对应的属性便可(要确保动画编辑器处于编辑状态)。例如,属性列表中 position、x、y 三个属性轨道,选中关键帧后,能够修改属性检查器中的 position、x、y 属性

  或者在时间轴上选择一个没有关键帧的位置,而后在属性检查器中修改相对应的属性,便会自动插入一帧

【删除关键帧】

  选中关键帧后,点击对应属性轨道的“三道杠”按钮,选择删除选中帧,或者直接按下键盘上的 delete 按键,则全部被选中的节点都会被删除

【复制关键帧】

  在动画编辑器内选中关键帧后,能够按下 cmd + c 复制当前的关键帧,而后选中某一个时间轴上的点,按下 cmd + v 将刚刚复制的关键帧粘贴到选中的时间点上

【节点操做】

  动画是按照节点的名字来进行索引关联的,有时会在层级管理器内改变节点的层级关系,而动画编辑器内的动画就会找不到当初指定对应的节点

  这时咱们须要手动更改一下动画上节点的搜索路径:

  一、鼠标移动到要迁移的节点上,点击右侧出现的菜单按钮

  二、选择移动节点数据

  三、修改节点的路径数据

 

编辑序列帧动画

  下面来看具体怎么建立一个帧动画

  一、首先须要让节点正常显示纹理,为节点增长 Sprite 组件,选中节点后在属性检查器中经过 添加组件 按钮,选择 添加渲染组件 -> Sprite

  二、节点能够正常显示纹理后,还须要为纹理建立一个动画轨道。在动画编辑器中点击 add Property,而后选择 cc.Sprite.spriteFrame

  三、从资源管理器中,将纹理拖拽到属性帧区域,放在  cc.Sprite.spriteFrame 轨道上,再将下一帧须要显示的纹理拖到指定位置,而后点击播放就能够预览刚刚建立的动画了

 

编辑时间曲线

  有时,咱们须要在两帧之间实现 EaseInOut 等缓动效果,须要在一条轨道上建立两个不相等的帧,好比在 position 上建立两帧,从 0,0 到 100,100,这里两帧之间会出现一根链接线(链接两关键帧之间的蓝色线段),双击链接线,则能够打开时间曲线编辑器

  在曲线编辑器左侧能够选择预设的各类效果,好比 EaseIn等,选中后右侧上方还会出现一些预设的参数,能够根据需求选择

  固然,也能够本身修改曲线,右侧预览图内,有两个灰色的控制点,拖拽控制点能够更改曲线的轨迹。若是控制点须要拖出视野外,则可使用鼠标滚轮或右上角的小比例尺缩放预览图,支持的比例从 0.1 到 1

 

添加动画事件

【添加事件】

  首先选中某个位置,而后点击按钮区域最右侧的按钮,这时在时间轴上会出现一个白色的小块,这就是添加的事件

【删除事件】

  双击刚刚出现的白色小块,打开事件编辑器后点击 function 后面的回收图标,会提示是否删除这个 event,点击确认则删除。也能够在动画编辑器中右键点击 event,选择 删除

【设置事件】

  双击刚刚出现的白色小块,打开事件编辑器,在编辑器内,能够手动输入须要触发的 funtion 名字,触发时会根据这个函数名,去各个组件内匹配相应的方法

  若是须要添加传入的参数,则在 Params 旁点击 + 或者 -,只支持 Boolean、String、Number 三种类型的参数

 

脚本控制Animation

  Animation 组件提供了一些经常使用的动画控制函数,若是只是须要简单的控制动画,能够经过获取节点的 Animation 组件来作一些操做

【播放】

var anim = this.getComponent(cc.Animation);

// 若是没有指定播放哪一个动画,而且有设置 defaultClip 的话,则会播放 defaultClip 动画
anim.play();

// 指定播放 test 动画
anim.play('test');

// 指定从 1s 开始播放 test 动画
anim.play('test', 1);

// 使用 play 接口播放一个动画时,若是还有其余的动画正在播放,则会先中止其余动画
anim.play('test2');

  Animation 对一个动画进行播放的时候会判断这个动画以前的播放状态来进行下一步操做

  若是动画处于 中止 状态,则 Animation 会直接从新播放这个动画

  若是动画处于 暂停 状态,则 Animation 会恢复动画的播放,并从当前时间继续播放下去

  若是动画处于 播放 状态,则 Animation 会先中止这个动画,再从新播放动画

【播放多个】

  Animation 支持同时播放多个动画,播放不一样的动画并不会影响其余动画的播放状态,这对于作一些复合动画有帮助

var anim = this.getComponent(cc.Animation);

// 播放第一个动画
anim.playAdditive('position-anim');

// 播放第二个动画
// 使用 playAdditive 播放动画时,不会中止其余动画的播放。若是还有其余动画正在播放,则同时会有多个动画进行播放
anim.playAdditive('rotation-anim');

【暂停和中止】

var anim = this.getComponent(cc.Animation);

anim.play('test');

// 指定暂停 test 动画
anim.pause('test');

// 暂停全部动画
// anim.pause();

// 指定恢复 test 动画
anim.resume('test');

// 恢复全部动画
// anim.resume();

// 指定中止 test 动画
anim.stop('test');

// 中止全部动画
// anim.stop();

【设置动画当前时间】

  能够在任什么时候候对动画设置当前时间,可是动画不会马上根据设置的时间进行状态的更改,须要在下一个动画的 update 中才会根据这个时间从新计算播放状态

var anim = this.getComponent(cc.Animation);

anim.play('test');

// 设置 test 动画的当前播放时间为 1s
anim.setCurrentTime(1, 'test');

// 设置全部动画的当前播放时间为 1s
// anim.setCurrentTime(1);

 

AnimationState

  Animation 只提供了一些简单的控制函数,但愿获得更多的动画信息和控制的话,须要使用到 AnimationState

  若是说 AnimationClip 做为动画数据的承载,那么 AnimationState 则是 AnimationClip 在运行时的实例,它将动画数据解析为方便程序中作计算的数值。 Animation 在播放一个 AnimationClip 的时候,会将 AnimationClip 解析成 AnimationState。 Animation 的播放状态实际都是由 AnimationState 来计算的,包括动画是否循环,怎么循环,播放速度等

【获取 AnimationState】

var anim = this.getComponent(cc.Animation);
// play 会返回关联的 AnimationState
var animState = anim.play('test');

// 或是直接获取
var animState = anim.getAnimationState('test');

【获取动画信息】

var anim = this.getComponent(cc.Animation);
var animState = anim.play('test');

// 获取动画关联的clip
var clip = animState.clip;

// 获取动画的名字
var name = animState.name;

// 获取动画的播放速度
var speed = animState.speed;

// 获取动画的播放总时长
var duration = animState.duration;

// 获取动画的播放时间
var time = animState.time;

// 获取动画的重复次数
var repeatCount = animState.repeatCount;

// 获取动画的循环模式
var wrapMode = animState.wrapMode

// 获取动画是否正在播放
var playing = animState.isPlaying;

// 获取动画是否已经暂停
var paused = animState.isPaused;

// 获取动画的帧率
var frameRate = animState.frameRate;

【设置动画播放速度】

  speed 值越大,速度越快,值越小则速度越慢

var anim = this.getComponent(cc.Animation);
var animState = anim.play('test');

// 使动画播放速度加速
animState.speed = 2;

// 使动画播放速度减速
animState.speed = 0.5;

【设置动画循环模式和循环次数】

  AnimationState 容许动态设置循环模式,目前提供了多种循环模式,这些循环模式能够从 cc.WrapMode中获取到。若是动画的循环类型为 Loop 类型的话,须要与 repeatCount 配合使用才能达到效果。 默认在解析动画剪辑的时候,若是动画循环类型为 Loop 类型,repeatCount 将被设置为 Infinity,即无限循环;若是动画循环类型为 Normal 类型,repeatCount 将被设置为 1

var anim = this.getComponent(cc.Animation);
var animState = anim.play('test');

// 设置循环模式为 Normal
animState.wrapMode = cc.WrapMode.Normal;

// 设置循环模式为 Loop
animState.wrapMode = cc.WrapMode.Loop;

// 设置动画循环次数为2次
animState.repeatCount = 2;

// 设置动画循环次数为无限次
animState.repeatCount = Infinity;

 

动画事件

  动画事件的回调其实就是一个普通的函数,在动画编辑器里添加的帧事件会映射到动画根节点的组件上

  假设在动画的结尾添加了一个帧事件,以下图

  那么,在脚本中能够这么写:

cc.Class({
    extends: cc.Component,

    onAnimCompleted: function (num, string) {
        console.log('onAnimCompleted: param1[%s], param2[%s]', num, string);
    }
});

  将上面的组件加到动画的 根节点 上,当动画播放到结尾时,动画系统会自动调用脚本中的 onAnimCompleted 函数。 动画系统会搜索动画根节点中的全部组件,若是组件中有实现动画事件中指定的函数的话,就会对它进行调用,并传入事件中填的参数

  要特别注意的是,该脚本必须绑定到 node 节点上,不然脚本中的函数将不会被执行

【注册事件回调】

  除了动画编辑器中的帧事件提供了回调外,动画系统还提供了动态注册回调事件的方式

  目前支持的回调事件有:

play: 开始播放时
stop: 中止播放时
pause: 暂停播放时
resume: 恢复播放时
lastframe: 假如动画循环次数大于1,当动画播放到最后一帧时
finished: 动画播放完成时

  当在 cc.Animation 注册了一个回调函数后,它会在播放一个动画时,对相应的 cc.AnimationState 注册这个回调,在 cc.AnimationState 中止播放时,对 cc.AnimationState 取消注册这个回调

  cc.AnimationState 其实才是动画回调的发送方,若是但愿对单个 cc.AnimationState 注册回调的话,那么能够获取到这个 cc.AnimationState 再单独对它进行注册

var animation = this.node.getComponent(cc.Animation);

// 注册
animation.on('play',      this.onPlay,        this);
animation.on('stop',      this.onStop,        this);
animation.on('lastframe', this.onLastFrame,   this);
animation.on('finished',  this.onFinished,    this);
animation.on('pause',     this.onPause,       this);
animation.on('resume',    this.onResume,      this);

// 取消注册
animation.off('play',      this.onPlay,        this);
animation.off('stop',      this.onStop,        this);
animation.off('lastframe', this.onLastFrame,   this);
animation.off('finished',  this.onFinished,    this);
animation.off('pause',     this.onPause,       this);
animation.off('resume',    this.onResume,      this);

// 对单个 cc.AnimationState 注册回调
var anim1 = animation.getAnimationState('anim1');
anim1.on('lastframe',    this.onLastFrame,      this);
相关文章
相关标签/搜索