[1]CLIP
[2]動畫編輯器
[3]動畫剪輯
[4]編輯動畫序列
[5]編輯序列幀動畫
[6]編輯時間曲線
[7]添加動畫事件
[8]腳本控制Animation
[9]AnimationState
[10]動畫事件
前面的話
cocos 動畫系統支援任意元件屬性和使用者自定義屬性的驅動,再加上可任意編輯的時間曲線和移動軌迹編輯功能,就可以制作出各種動态效果
概述
Animation 元件可以以動畫方式驅動所在節點和子節點上的節點群組件屬性,包括使用者自定義腳本中的屬性
點選屬性檢查器下面的添加按鈕,然後從添加其他元件中選擇Animation,即可添加 Animation 元件到節點上
【屬性】
Default Cilp: 預設的動畫剪輯,如果這一項設定了值,并且 Play On Load 為 true,那麼動畫會在加載完成後自動播放 Default Clip 的内容
Clips: 清單類型,預設為空,在這裡面添加的 AnimationClip 會反映到動畫編輯器中,使用者可以在動畫編輯器裡編輯 Clips 的内容
Play On Load: 布爾類型,是否在動畫加載完成後自動播放 Default Clip 的内容
CLIP
cocos Animation是節點上的一個元件,clip 動畫剪輯是一份動畫的聲明資料,将它挂載在 Animation 元件上,就可以将這份動畫資料應用到節點上
資料中索引節點的方式是以挂載 Animation 元件的節點為根節點的相對路徑,是以在同一個父節點下的同名節點,隻能夠産生一份動畫資料,并且隻能應用到第一個同名節點上
【參數】
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 個主要部分
1、常用按鈕區域,這裡負責顯示一些常用功能按鈕,從左到右依次是:開關錄制狀态、傳回第一幀、上一幀、播放/暫停、下一幀、建立動畫剪輯、插入動畫事件
2、時間軸與事件,這裡主要是顯示時間軸,添加的自定義事件也會在這裡顯示
3、層級管理(節點樹),目前動畫剪輯可以影響到的節點資料
4、節點内關鍵幀的預覽區域,這裡主要是顯示各個節點上的所有幀的預覽時間軸
5、屬性清單,顯示目前選中的節點在選中的動畫剪輯中已經包含了的屬性清單
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 元件,建立的方法有兩種:
1、選中相應的節點,在屬性檢查器中點選右上方的 +,或者下方的 添加元件, 在其他元件中選擇 Animation
2、打開動畫編輯器,然後在層級管理器中選中需要添加動畫的節點,在動畫編輯器中點選 添加Animation元件 按鈕
【建立與挂載動畫剪輯】
動畫剪輯有兩種建立方式:
1、在資料總管中點選左上方的 +,或者右鍵空白區域,選擇 Animation Clip,這時會在管理器中建立一個名為 'New AnimationClip'的剪輯檔案。在層級管理器中點選剛剛的節點,在屬性檢查器中找到 Animation,這時的 Clips 顯示的是 0,将它改成1,然後将剛剛在資料總管中建立的'New AnimationClip',拖入剛剛出現的 animation-clip 選擇框内
2、如果 Animation 元件中還沒有添加動畫剪輯檔案,則可以在動畫編輯器中直接點選 建立 AnimationClip 按鈕,根據彈出的視窗建立一個新的動畫剪輯檔案。要注意的是,如果選擇覆寫已有的剪輯檔案,被覆寫的檔案内容會被清空
【資料剪輯】
一個動畫剪輯内可能包含了多個節點,每一個節點上挂在多個動畫屬性,每個屬性内的資料才是實際的關鍵幀
動畫剪輯通過節點的名字定義資料的位置,本身忽略了根節點,其餘的子節點通過與根節點的相對路徑索引找到對應的資料
如果在制作完成動畫後,将節點重命名,會造成動畫資料出現問題,如下圖所示
這時,要手動指定資料對應的節點,可以将滑鼠移入節點,點選節點右側出現的更多按鈕,并選擇“移動資料”
如上圖所示,New Node/test 節點沒有資料,想将 /New Node/efx_flare 上的資料移到這裡
1、滑鼠移動丢失的節點 /New Node/efx_flare 上
2、點選右側出現的按鈕
3、選擇移動資料
4、将路徑改為 /New Node/test,并回車
編輯動畫序列
動畫屬性包括了節點自有的 position、rotation 等屬性,也包含了元件 Component 中自定義的屬性。元件包含的屬性會加上元件的名字,比如 cc.Sprite.spriteFrame
【添加新的屬性軌道】
先選中節點,然後在屬性區域右上角點選 +。彈出菜單中,選中想要添加的屬性,就會對應新增一個軌道
【删除一個屬性軌道】
将滑鼠焦點移動到要删除的屬性軌道上,右邊會顯示一個“三道杠”按鈕,點選按鈕,在彈出菜單中選擇删除屬性,選中後對應的屬性就會從動畫資料中删除
【添加關鍵幀】
在屬性清單中點選對應屬性軌道右側的“三道杠”按鈕,在彈出的菜單中選擇 插入關鍵幀 按鈕
【選擇關鍵幀】
點選建立的關鍵幀後,關鍵幀會呈現選中狀态,此時關鍵幀由藍變白,如果需要多選,可以按住 ctrl 再次選擇其他關鍵幀,或者直接在屬性區域拖拽框選擇
【移動關鍵幀】
将滑鼠移動到任意一個被選中的關鍵幀上,按下滑鼠左鍵,滑鼠會變換成左右箭頭,這時就可以拖拽所有被選中的節點了
【更改關鍵幀】
在時間軸上需要修改的關鍵幀,直接在屬性檢查器内修改相對應的屬性即可(要確定動畫編輯器處于編輯狀态)。例如,屬性清單中 position、x、y 三個屬性軌道,選中關鍵幀後,可以修改屬性檢查器中的 position、x、y 屬性
或者在時間軸上選擇一個沒有關鍵幀的位置,然後在屬性檢查器中修改相對應的屬性,便會自動插入一幀
【删除關鍵幀】
選中關鍵幀後,點選對應屬性軌道的“三道杠”按鈕,選擇删除選中幀,或者直接按下鍵盤上的 delete 按鍵,則所有被選中的節點都會被删除
【複制關鍵幀】
在動畫編輯器内選中關鍵幀後,可以按下 cmd + c 複制目前的關鍵幀,然後選中某一個時間軸上的點,按下 cmd + v 将剛剛複制的關鍵幀粘貼到選中的時間點上
【節點操作】
動畫是按照節點的名字來進行索引關聯的,有時會在層級管理器内改變節點的層級關系,而動畫編輯器内的動畫就會找不到當初指定對應的節點
這時我們需要手動更改一下動畫上節點的搜尋路徑:
1、滑鼠移動到要遷移的節點上,點選右側出現的菜單按鈕
2、選擇移動節點資料
3、修改節點的路徑資料
編輯序列幀動畫
下面來看具體怎麼建立一個幀動畫
1、首先需要讓節點正常顯示紋理,為節點增加 Sprite 元件,選中節點後在屬性檢查器中通過 添加元件 按鈕,選擇 添加渲染元件 -> Sprite
2、節點可以正常顯示紋理後,還需要為紋理建立一個動畫軌道。在動畫編輯器中點選 add Property,然後選擇 cc.Sprite.spriteFrame
3、從資料總管中,将紋理拖拽到屬性幀區域,放在 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);
好的代碼像粥一樣,都是用時間熬出來的