cocos 動畫系統支持任意組件屬性和用戶自定義屬性的驅動,再加上可任意編輯的時間曲線和移動軌跡編輯功能,就能夠製做出各類動態效果node
Animation 組件能夠以動畫方式驅動所在節點和子節點上的節點和組件屬性,包括用戶自定義腳本中的屬性數組
點擊屬性檢查器下面的添加按鈕,而後從添加其餘組件中選擇Animation,便可添加 Animation 組件到節點上編輯器
【屬性】函數
Default Cilp: 默認的動畫剪輯,若是這一項設置了值,而且 Play On Load 爲 true,那麼動畫會在加載完成後自動播放 Default Clip 的內容oop
Clips: 列表類型,默認爲空,在這裏面添加的 AnimationClip 會反映到動畫編輯器中,用戶能夠在動畫編輯器裏編輯 Clips 的內容動畫
Play On Load: 布爾類型,是否在動畫加載完成後自動播放 Default Clip 的內容this
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 組件來作一些操做
【播放】
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);
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);