前言:
要使得一個角色動起來,CocosCreator提供了動作系統,裏面有很多的API函數,可以通過調用不同的API函數來控制角色的運動,動作系統可以在一定時間內對節點完成位移,縮放,旋轉等各種動作。需要注意的是,動作系統並不能取代 動畫系統,動作系統提供的是面向程序員的 API 接口,而動畫系統則是提供在編輯器中來設計的。
一、動作系統應用
1. 動作系統API
這裏提醒一下:這些動作系統的API都是相對節點而言的,是用來操作節點的,千萬別給組件加動作.
一定用在節點上
// 創建一個動作
var action = cc.moveTo(1, 100, 100);// 參數:維持時間、X座標、y座標
// 節點執action行動作
node.runAction(action);
// 停止一個動作
node.stopAction(action);
// 停止所有動作
node.stopAllActions();
開發者還可以給動作設置 tag,並通過 tag 來控制動作。
這就相當於給一個動作貼上一個標籤,編一個號之類的。
// 給 action 設置 tag
var action_tag = 1;
action.setTag(action_tag);
// 通過 tag 獲取 action
node.getActionByTag(action_tag);
// 通過 tag 停止一個動作
node.stopActionByTag(action_tag);
2. 動作類型
由於CocosCreator裏面的動作有很多,這裏介紹一些很常用的。
基礎動作
基礎動作就是實現各種形變,位移動畫的動作,比如
cc.moveTo
用來移動節點到某個位置;
cc.rotateBy
用來旋轉節點一定的角度;
cc.scaleTo
用來縮放節點。
基礎動作中分爲時間間隔動作和即時動作:
時間間隔動作是在一定時間間隔內完成的漸變動作,前面提到的都是時間間隔動作,它們全部繼承自 cc.ActionInterval
。
即時動作則是立即發生的,比如用來調用回調函數的cc.callFunc
;用來隱藏節點的cc.hide
,它們全部繼承自cc.ActionInstant
。
容器動作
容器動作就是對已有的一些動作驚進行管理和修飾,使其具有一些特定的效果。
1. 順序動作cc.sequence
:
順序動作可以讓一系列子動作按順序一個個執行。
// 讓節點在兩個點之間來回移動
var seq = cc.sequence(cc.moveBy(1, 200, 0), cc.moveBy(1, -200, 0));
node.runAction(seq);
2. 同步動作cc.spawn
:
同步動作可以同步執行對一系列子動作,子動作的執行結果會疊加起來
修改節點的屬性。
// 讓節點在向上移動的同時縮放
var spawn = cc.spawn(cc.moveBy(1, 0, 50), cc.scaleTo(0.5, 0.8, 1.4));
node.runAction(spawn);
3. 重複動作 cc.repeat
:
重複動作用來多次重複一個動作。
// 讓節點左右來回移動,並重復5次
var seq = cc.repeat(
cc.sequence(
cc.moveBy(2, 200, 0),
cc.moveBy(2, -200, 0)
), 5);
node.runAction(seq);
4. 永遠重複動作 cc.repeatForever
:
顧名思義,這個動作容器可以讓目標動作一直重複,直到手動停止。
// 讓節點左右來回移動並一直重複
var seq = cc.repeatForever(
cc.sequence(
cc.moveBy(2, 200, 0),
cc.moveBy(2, -200, 0)
));
5. 速度動作cc.speed
:
速度動作可以改變目標動作的執行速率,讓動作更快或者更慢完成。
// 讓目標動作速度加快一倍,相當於原本2秒的動作在1秒內完成
var action = cc.speed(
cc.spawn(
cc.moveBy(2, 0, 50),
cc.scaleTo(2, 0.8, 1.4)
), 2);
node.runAction(action);
緩動動作
緩動動作不可以單獨存在,它永遠是爲了修飾基礎動作而存在的,它可以用來修改基礎動作的時間曲線,讓動作有快入、緩入、快出或其它更復雜的特效
。需要注意的是,只有時間間隔動作才支持緩動:
var action = cc.scaleTo(0.5, 2, 2);
action.easing(cc.easeIn(3.0));
基礎的緩動動作類是 cc.ActionEase
。
回調動作
第一個參數是一個執行時函數,第二個參數指定了處理回調方法的 context(也就是綁定 this),第三個參數是向處理回調方法的傳參。
// 動作回調函數的聲明:兩種
var finished = cc.callFunc(this.myMethod, this, opt);// 方法一
var finished = cc.callFunc(function(target, score) { // 方法二
this.score += score;
}, this, 100);//動作完成後會給玩家加100分
// 在聲明瞭回調動作 finished 後,您可以配合 cc.sequence 來執行一整串動作並觸發回調:
var myAction = cc.sequence(cc.moveBy(1, cc.v2(0, 100)), cc.fadeOut(1), finished);
// 在同一個 sequence 裏也可以多次插入回調:
var myAction = cc.sequence(cc.moveTo(1, cc.v2(0, 0)), finished1, cc.fadeOut(1), finished2);
// 注意:finished1, finished2 都是使用 cc.callFunc 定義的回調動作
注意: 在 cc.callFunc 中不應該停止自身動作,由於動作是不能被立即刪除,
如果在動作回調中暫停自身動作會引發一系列遍歷問題,導致更嚴重的 bug。
二、動作彙總
容器動作
動作名稱 | 描述 | 動作名稱 | 描述 |
---|---|---|---|
cc.sequence | 順序執行動作 | cc.spawn | 同步執行動作 |
cc.repeat | 重複執行動作 | cc.repeatForever | 永遠重複動作 |
cc.speed | 修改動作速率 API 描述 |
即時動作
動作名稱 | 描述 | 動作名稱 | 描述 |
---|---|---|---|
cc.show | 立即顯示 | cc.hide | 立即隱藏 |
cc.toggleVisibility | 顯隱狀態切換 | cc.removeSelf | 從父節點移除自身 |
cc.flipX | X軸翻轉 | cc.flipY | Y軸翻轉 |
cc.place | 放置在目標位置 | cc.callFunc | 執行回調函數 |
cc.targetedAction | 用已有動作和一個新的目標節點創建動作 |
時間間隔動作
動作名稱 | 描述 | 動作名稱 | 描述 |
---|---|---|---|
cc.moveTo | 移動到目標位置 | cc.moveBy | 移動指定的距離 |
cc.rotateTo | 旋轉到目標角度 | cc.rotateBy | 旋轉指定的角度 |
cc.scaleTo | 將節點大小縮放到指定的倍數 | cc.scaleBy | 按指定的倍數縮放節點大小 |
cc.skewTo | 偏斜到目標角度 | cc.skewBy | 偏斜指定的角度 |
cc.jumpBy | 用跳躍的方式移動指定的距離 | cc.jumpTo | 用跳躍的方式移動到目標位置 |
cc.follow | 追蹤目標節點的位置 | cc.bezierTo | 按貝賽爾曲線軌跡移動到目標位置 |
cc.bezierBy | 按貝賽爾曲線軌跡移動指定的距離 | cc.blink | 閃爍(基於透明度) |
cc.fadeTo | 修改透明度到指定值 | cc.cardinalSplineTo | 按基數樣條曲線軌跡移動到目標位置 |
cc.fadeOut | 漸隱 | cc.catmullRomTo | 按 Catmull Rom 樣條曲線軌跡移動到目標位置 |
cc.tintBy | 按照指定的增量修改顏色 | cc.delayTime | 延遲指定的時間量 |
cc.reverseTime | 反轉目標動作的時間軸 | cc.fadeIn | 漸顯 |
cc.cardinalSplineBy | 按基數樣條曲線軌跡移動指定的距離 | cc.tintTo | 修改顏色到指定值 |
cc.catmullRomBy | 按 Catmull Rom 樣條曲線軌跡移動指定的距離 |
緩動動作
cc.easeIn | cc.easeOut | cc.easeInOut | cc.easeExponentialIn |
---|---|---|---|
cc.easeExponentialOut | cc.easeExponentialInOut | cc.easeSineIn | cc.easeSineOut |
cc.easeSineInOut | cc.easeElasticIn | cc.easeElasticOut | cc.easeElasticInOut |
cc.easeBounceIn | cc.easeBounceOut | cc.easeBounceInOut | cc.easeBackIn |
cc.easeBackOut | cc.easeBackInOut | cc.easeBezierAction | cc.easeQuadraticActionIn |
cc.easeQuadraticActionOut | cc.easeQuadraticActionInOut | cc.easeQuarticActionIn | cc.easeQuarticActionOut |
三、緩動系統(cc.tween)
cc.tween
會比 cc.Action
更加簡潔易用,因爲 cc.tween 提供了鏈式創建的方法,可以對任何對象進行操作,並且可以對對象的任意屬性進行緩動。
動作系統只支持在節點屬性上使用,並且如果要支持新的屬性就需要再添加一個新的動作。
爲了提供更好的 API, cc.tween 在 動作系統 的基礎上做了一層 API 封裝
。
下面是 cc.Action 與 cc.tween 在使用上的對比:
// cc.Action:
this.node.runAction(
cc.sequence(
cc.spawn(
cc.moveTo(1, 100, 100),
cc.rotateTo(1, 360),
),
cc.scale(1, 2)
)
)
// cc.tween:
cc.tween(this.node)
.to(1, { position: cc.v2(100, 100), rotation: 360 })
.to(1, { scale: 2 })
.start()
1. 鏈式API
cc.tween 在調用 start 時會將之前生成的 action 隊列重新組合生成一個 cc.sequence
隊列,所以 cc.tween 的鏈式結構是依次執行每一個 API 的
,也就是會執行完一個 API 再執行下一個 API
。
cc.tween(this.node)
// 0s 時,node 的 scale 還是 1
.to(1, { scale: 2 })
// 1s 時,執行完第一個 action,scale 爲 2
.to(1, { scale: 3 })
// 2s 時,執行完第二個 action,scale 爲 3
.start()
// 調用 start 開始執行 cc.tween
2. 設置緩動屬性
cc.tween 提供了兩個設置屬性的 API:
• to
:對屬性進行絕對
值計算,最終的運行結果即是設置的屬性值;
• by
:對屬性進行相對
值計算,最終的運行結果是設置的屬性值加上開始
運行時節點的屬性值;
cc.tween(node)
.to(1, {scale: 2}) // node.scale === 2
.by(1, {scale: 2}) // node.scale === 4 (2+2)
.by(1, {scale: 1}) // node.scale === 5
.to(1, {scale: 2}) // node.scale === 2
.start()
3. 支持緩動任意對象的任意屬性
let obj = { a: 0 }
cc.tween(obj)
.to(1, { a: 100 })
.start()
4. 同時執行多個屬性
cc.tween(this.node)
// 同時對 scale, position, rotation 三個屬性緩動
.to(1, { scale: 2, position: cc.v2(100, 100), rotation: 90 })
.start()
5. easing
你可以使用 easing 來使緩動更生動, cc.tween 針對不同的情況提供了多種使用方式。
// 傳入 easing 名字,直接使用內置 easing 函數
cc.tween().to(1, { scale: 2 }, { easing: 'sineOutIn'})
// 使用自定義 easing 函數
cc.tween().to(1, { scale: 2 }, { easing: t => t*t; })
// 只對單個屬性使用 easing 函數
// value 必須與 easing 或者 progress 配合使用
cc.tween().to(1, { scale: 2, position: { value: cc.v3(100, 100, 100), easing: 'sineOutIn' } })
6. 自定義 progress
相對於 easing,自定義 progress 函數可以更自由的控制緩動的過程。
// 對所有屬性自定義 progress
cc.tween().to(1, { scale: 2, rotation: 90 }, {
progress: (start, end, current, ratio) => {
return start + (end - start) * ratio;
}
})
// 對單個屬性自定義 progress
cc.tween().to(1, {
scale: 2,
position: {
value: cc.v3(),
progress: (start, end, current, t) => {
// 注意,傳入的屬性爲 cc.Vec3,所以需要使用 Vec3.lerp 進行插值計算
return start.lerp(end, t, current);
}
}
})
7. 複製緩動
clone 函數會克隆一個當前的緩動,並接受一個 target 作爲參數。
// 先創建一個緩動作爲模板
let tween = cc.tween().to(4, { scale: 2 })
// 複製 tween,並使用節點 Canvas/cocos 作爲 target
tween.clone(cc.find('Canvas/cocos')).start()
// 複製 tween,並使用節點 Canvas/cocos2 作爲 target
tween.clone(cc.find('Canvas/cocos2')).start()
8. 插入其他的緩動到隊列中
你可以事先創建一些固定的緩動,然後通過組合這些緩動形成新的緩動來減少代碼的編寫。
let scale = cc.tween().to(1, { scale: 2 })
let rotate = cc.tween().to(1, { rotation: 90})
let move = cc.tween().to(1, { position: cc.v3(100, 100, 100)})
// 先縮放再旋轉
cc.tween(this.node).then(scale).then(rotate)
// 先縮放再移動
cc.tween(this.node).then(scale).then(move)
9. 並行執行緩動
cc.tween 在鏈式執行時是按照 sequence 的方式來執行的,但是在編寫複雜緩動的時候可能會需要同時並行執行多個隊列, cc.tween 提供了 parallel 接口來滿足這個需求。
let t = cc.tween;
t(this.node)
// 同時執行兩個 cc.tween
.parallel(
t().to(1, { scale: 2 }),
t().to(2, { position: cc.v2(100, 100) })
)
.call(() => {
console.log('All tweens finished.')
})
.start()
10. 回調
cc.tween(this.node)
.to(2, { rotation: 90})
.to(1, { scale: 2})
// 當前面的動作都執行完畢後纔會調用這個回調函數
.call(() => { cc.log('This is a callback') })
.start()
11. 重複執行
repeat/repeatForever 函數會將前一個 action 作爲作用對象。但是如果有參數提供了其他的 action 或者 tween,則 repeat/repeatForever 函數會將傳入的 action 或者 tween 作爲作用對象。
cc.tween(this.node)
.by(1, { scale: 1 })
// 對前一個 by 重複執行 10次
.repeat(10)
// 最後 node.scale === 11
.start()
// 也可以這樣用
cc.tween(this.node)
.repeat(10,
cc.tween().by(1, { scale: 1 })
)
.start()
// 一直重複執行下去
cc.tween(this.node)
.by(1, { scale: 1 })
.repeatForever()
.start()
12. 延遲執行
cc.tween(this.node)
// 延遲 1s
.delay(1)
.to(1, { scale: 2 })
// 再延遲 1s
.delay(1)
.to(1, { scale: 3 })
.start()
這篇動作篇有點長,不過這些都挺重要的,還是要記住,這樣在遊戲開發時能夠能更快,代碼也可以更精煉,效果更好!