CocosCreator 讓角色動起來 (第六篇)

前言:
要使得一個角色動起來,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()

這篇動作篇有點長,不過這些都挺重要的,還是要記住,這樣在遊戲開發時能夠能更快,代碼也可以更精煉,效果更好!

推薦閱讀:
一個小時完成CocosCreator射擊小遊戲 (適合初學者)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章