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射击小游戏 (适合初学者)

发布了31 篇原创文章 · 获赞 39 · 访问量 8143

猜你喜欢

转载自blog.csdn.net/qq_45021180/article/details/104382381