CocosCreator 让角色动起来 (第六篇)

Stella981
• 阅读 765

前言:
要使得一个角色动起来,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射击小游戏 (适合初学者)

本文同步分享在 博客“战 胜”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
CuterCorley CuterCorley
3年前
uni-app入门教程(6)接口的扩展应用
前言本文主要介绍了接口的扩展应用:设备相关的接口包括获取系统信息、网络状态、拨打电话、扫码等;导航栏的动态设置;下拉刷新、上拉加载更多的实现,通过动作链获取节点信息;用条件编译实现小程序、APP等多端兼容;提示框、Loading、模态弹窗等的交互反馈。一、设备相关1.系统信息uni.getSystemInfo(OBJECT)接口用来异步
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python调用API接口的几种方式
Python调用API接口的几种方式相信做过自动化运维的同学都用过API接口来完成某些动作。API是一套成熟系统所必需的接口,可以被其他系统或脚本来调用,这也是自动化运维的必修课。本文主要介绍python中调用API的几种方式,下面是python中会用到的库。\urllib2\httplib2\pycurl\reque
Stella981 Stella981
2年前
CocosCreator 教你玩转Animation动画(第十四篇)
前言:Animation动画在游戏中是必不可少的,各种人物的走跑跳飞,以及各种表情动作,反正做游戏Animation动画是必修课了。这一篇章可以学会制作和控制各种动画,主要从一下几个方面介绍:1.动画制作流程;2.使用Animation动画编辑器制作动画;3.代码控制动画;一、动画制作的流程
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
JSP动作元素
JSP动作元素JSP动作元素用来控制JSP容器的动作,可以动态插入文件、重用JavaBean组件、导向另一个页面等。动作元素与指令元素不同,动作元素是在客户端请求时动态执行的,每次有客户端请求时可能都会被执行一次,而指令元素是在编译时被编译执行,它只会被编译一次。可用的标准动作元素如下:1<jsp:useBea
Stella981 Stella981
2年前
Android 动画和图形概述
Android提供了非常多强大的API来为UI元素应用动画,及绘制定制的2D和3D图形。下面的部分提供了一个APIs和可用的系统功能的概述,并帮助你确定,对于你的需求而言,哪种方法是最好的。动画Androidframework提供了两种动画系统:属性动画(在Android3.0中引入)和view动画。两种动画系统都是可行的选择,但通常而言
Stella981 Stella981
2年前
Noark入门之异步事件
引入异步事件主要是为了各模块的解耦,每当完成一个动作时,向系统发布一个事件,由关心的模块自己监听处理,可选择同步处理,异步处理,延迟处理。何时发布事件,当其他模块关心此动作时<br比如获得道具时,任务系统模块要判定完成进度,BI模块需要上报等等都可以监听此事件,已达模块解耦0x00事件源一个实现xyz.noark.core.event
绣鸾 绣鸾
5个月前
Moho Pro 14 for Mac(2D动画制作软件)
是一款专业的2D动画制作软件。它具有强大的功能和工具,适用于动画制作师、插画师和设计师。MohoPro14提供了丰富的动画功能,包括骨骼动画、形状插值、帧逐帧动画等。您可以使用骨骼工具来创建复杂的角色动画,通过设置骨骼关节和控制器,实现自然流畅的动作。形状