使用腳本控制動畫
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 會先停止這個動畫,再重新播放動畫
var anim = this.getComponent(cc.Animation); // 播放第一個動畫 anim.playAdditive('position-anim'); // 播放第二個動畫 // 使用 playAdditive 播放動畫時,不會停止其他動畫的播放。如果還有其他動畫正在播放,則同時會有多個動畫進行播放 anim.playAdditive('rotation-anim');
Animation 是支持同時播放多個動畫的,播放不同的動畫並不會影響其他的動畫的播放狀態,這對於做一些復合動畫比較有幫助。
暫停 恢復 停止
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();
暫停,恢復, 停止 幾個函數的調用比較接近。
暫停 會暫時停止動畫的播放,當 恢復 動畫的時候,動畫會繼續從當前時間往下播放。 而 停止 則會終止動畫的播放,再對這個動畫進行播放的時候會重新從開始播放動畫。
設置動畫的當前時間
var anim = this.getComponent(cc.Animation); anim.play('test'); // 設置 test 動畫的當前播放時間為 1s anim.setCurrentTime(1, 'test'); // 設置所有動畫的當前播放時間為 1s // anim.setCurrentTime(1);
你可以在任何時候對動畫設置當前時間,但是動畫不會立刻根據設置的時間進行狀態的更改,需要在下一個動畫的 update 中才會根據這個時間重新計算播放狀態。
AnimationState
Animation 只提供了一些簡單的控制函數,希望得到更多的動畫信息和控制的話,需要使用到 AnimationState。
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;
從 AnimationState 中可以獲取到所有動畫的信息,你可以利用這些信息來判斷需要做哪些事情。
設置動畫播放速度
var anim = this.getComponent(cc.Animation); var animState = anim.play('test'); // 使動畫播放速度加速 animState.speed = 2; // 使動畫播放速度減速 animState.speed = 0.5;
speed 值越大速度越快,值越小則速度越慢
設置動畫 循環模式 與 循環次數
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;
AnimationState 允許動態設置循環模式,目前提供了多種循環模式,這些循環模式可以從 cc.WrapMode中獲取到。 如果動畫的循環類型為 Loop 類型的話,需要與 repeatCount 配合使用才能達到效果。 默認在解析動畫剪輯的時候,如果動畫循環類型為:
- Loop 類型,repeatCount 將被設置為 Infinity, 即無限循環
- Normal 類型,repeatCount 將被設置為 1
動畫事件
在動畫編輯器里支持可視化編輯幀事件 (如何編輯請參考 這里 ),在腳本里書寫動畫事件的回調也非常簡單。 動畫事件的回調其實就是一個普通的函數,在動畫編輯器里添加的幀事件會映射到動畫根節點的組件上。
實例:
假設在動畫的結尾添加了一個幀事件,如下圖:
那么在腳本中可以這么寫:
cc.Class({ extends: cc.Component, onAnimCompleted: function (num, string) { console.log('onAnimCompleted: param1[%s], param2[%s]', num, string); } });
將上面的組件加到動畫的 根節點 上,當動畫播放到結尾時,動畫系統會自動調用腳本中的 onAnimCompleted
函數。 動畫系統會搜索動畫根節點中的所有組件,如果組件中有實現動畫事件中指定的函數的話,就會對它進行調用,並傳入事件中填的參數。
注冊動畫回調
除了動畫編輯器中的幀事件提供了回調外,動畫系統還提供了動態注冊回調事件的方式。
目前支持的回調事件有:
- 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);
動態創建 Animation Clip
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');