动画

像素动画画面帧率间隔脚本大脑游戏游戏引擎

  1. import { _decorator, Component, Node, CCObject } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * Predefined variables
  5. * Name = NewComponent
  6. * DateTime = Sat Apr 16 2022 14:10:06 GMT+0800 (中国标准时间)
  7. * Author = gycarver127
  8. * FileBasename = NewComponent.ts
  9. * FileBasenameNoExtension = NewComponent
  10. * URL = db://assets/NewComponent.ts
  11. * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
  12. *
  13. */
  14. @ccclass('NewComponent')
  15. export class NewComponent extends Component {
  16. // [1]
  17. // dummy = '';
  18. @property
  19. label:cc.label = null;
  20. @property
  21. text:string = "hello";
  22. // [2]
  23. // @property
  24. // serializableDummy = 0;
  25. start () {
  26. // [3]
  27. }
  28. update (deltaTime: number) {
  29. if(this.node.x > 200) return;
  30. this.node.x += 5; //将节点移动5像素
  31. }
  32. }
  33. /**
  34. * [1] Class member could be defined like this.
  35. * [2] Use `property` decorator if your want the member to be serializable.
  36. * [3] Your initialization goes here.
  37. * [4] Your update function goes here.
  38. *
  39. * Learn more about scripting: https://docs.cocos.com/creator/3.4/manual/zh/scripting/
  40. * Learn more about CCClass: https://docs.cocos.com/creator/3.4/manual/zh/scripting/decorator.html
  41. * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.4/manual/zh/scripting/life-cycle-callbacks.html
  42. */

文字记录

这章里边我们讲一下动画的实现,这章的内容主要是讲以程序的方式来编写动画效果,这个比上一章的内容要高级一些,比上一章的cc.tween应该说是更本质一些。加载我们的游戏之后,会有一个小猪佩奇的这样的一个角色,它会自动从左侧默默的移动到了右侧,这个并不是使用 cc.tween 来实现的,而是我们使用的所谓帧动画来实现的。

我们先创建一个佩奇的节点,给它添加一个脚本,创建一个 TypeScript ,名字还是叫做 pigscript ,然后把这个脚本附加给佩奇节点,保存一下,再打开这个脚本,默认给我们创建的脚本是这个。

  1. import { _decorator, Component, Node } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * Predefined variables
  5. * Name = NewComponent_001
  6. * DateTime = Sun Apr 17 2022 16:37:46 GMT+0800 (中国标准时间)
  7. * Author = gycarver127
  8. * FileBasename = NewComponent-001.ts
  9. * FileBasenameNoExtension = NewComponent-001
  10. * URL = db://assets/NewComponent-001.ts
  11. * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
  12. *
  13. */
  14. @ccclass('NewComponent_001')
  15. export class NewComponent_001 extends Component {
  16. // [1]
  17. // dummy = '';
  18. // [2]
  19. // @property
  20. // serializableDummy = 0;
  21. start () {
  22. // [3]
  23. }
  24. // update (deltaTime: number) {
  25. // // [4]
  26. // }
  27. }
  28. /**
  29. * [1] Class member could be defined like this.
  30. * [2] Use `property` decorator if your want the member to be serializable.
  31. * [3] Your initialization goes here.
  32. * [4] Your update function goes here.
  33. *
  34. * Learn more about scripting: https://docs.cocos.com/creator/3.4/manual/zh/scripting/
  35. * Learn more about CCClass: https://docs.cocos.com/creator/3.4/manual/zh/scripting/decorator.html
  36. * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.4/manual/zh/scripting/life-cycle-callbacks.html
  37. */

以前我们已经用过了 onload 初始化加载的时候,start第一次启动的时候, update 我们还没有用过,这个就是我们这一章要关注的东西。

update()回调方法

这个回调方法是什么意思呢?就是帧动画的绘制。这个方法每秒钟会被这个游戏引擎调用 60 次,我们可以在这里边来加一些动画的逻辑。
image.png
那你怎么知道它每秒钟会被这个游戏引擎调用 60 次, 我们可以先加一些日志来观测一下,比如说在这里边我加上一个日志,加上一个时间戳,把当前的时间给打印一下。当前时间怎么样来写呢?这样的话就能够把当前的时间的毫秒值给打印出来,把这个游戏运行一下,观察下这个日志输出。

  1. update(){
  2. cc.log("update() is called,time=" + new Date().getTime());
  3. }

打开这个开发者工具,可以看到在这里边刷的是非常快的。
image.png
因为我们刚才已经告诉大家他是每秒钟刷大概六十次,也就是每 16 毫秒就有一句打印。所以这个打印实际上是非常多的,我们可以把它给暂停一下。可以看到这个它的打印的时间大概是每间隔 16 毫秒左右,会打印一次,我刚才说的是没有错误的。

帧率

刚才说告诉大家这个 update 的方法会被游戏引擎每秒钟大概调用是 60 次左右。这个 60 次我们就称之为这个帧率,对应的英文术语叫 frames for second ,每秒钟多少帧,那么默认情况下这个是 60 帧,简称FPS

既然有了这样的一个方法,我们可以考虑把这个动画逻辑放在这个里边,因为它是每秒钟调用 60 次。那我每次向右移动一定距离。比如说我每次向右移动 5 个像素,那么一秒钟下来就移动了 60 次,60次乘以 5 个像素,一秒钟下来它会均匀的向右移动,大概是 300 个像素。好的,我们现在把这个逻辑给加上来直接拷贝一下,填写到update 方法里边。

看一下我们的update 里边的实现,因为我们想要的效果是让这个小猪从左边移动到右边,怎么移呢?我们让它每次 update 的时候都把它的坐标向右移动 5 个像素 ,x += 5,你可以想象每次移动一点点,那么一秒钟移动 60 次,那么整体上就是一种均匀的移动的效果了,当然在上面加上一个边界的控制,因为你不能让它一直向右移动。我们这里面加一个限制,如果这 X 的坐标大于等于 200 的话就停止运动。

  1. update (deltaTime: number) {
  2. if(this.node.x > 200) return;
  3. this.node.x += 5; //将节点移动5像素
  4. }

这两行代码控制一下,把这个代码保存一下,再刷新一下,再运行游戏。这时候我们打开游戏会发现这个小猪就是自动往右移,直到它的坐标到达 200 像素为止。

那看起来其实是一个很连贯很连续的动作,你看不到中间有任何的间隔,正是因为这个移动的速度,它调用的速度实际上是非常快的,每秒钟调用 60 次,每次它移动这个五个像素。那对于人眼来说,基本上无法区分中间的这个抖动,它就是一个连续的画面。

要做一个动画,设置为 60 FPS 肯定是够的,实际上设为30,也就基本上无法区分了,这个就是所谓的帧动画,其实在做电影的时候,电影动画片也都是一个意思,它都是每秒钟连续的播放一些画面,这样的话对于我们观众而言是看不到中间这样的一个间隔的,因为这个画面在大脑里边实际上是有大概是 0.05 秒的残留,大脑认为这个画面就是一个连续的画面。