前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CocosCreator之控制游戏速率实现倍速与慢动作

CocosCreator之控制游戏速率实现倍速与慢动作

作者头像
一枚小工
发布2020-10-30 14:38:47
2.5K0
发布2020-10-30 14:38:47
举报
文章被收录于专栏:Cocos Creator开发

CocosCreator之控制游戏速率实现倍速与慢动作

摘要

在游戏开发中,游戏速率控制一直是一个需求,官方提供了计时器的控制接口以及动作系统的 cc.speed,但是使用起来不是很方便且无法影响到 update 控制逻辑以及物理系统,那么如何实现这一需求呢?

正文

使用版本

CocosCreator 版本 2.3.4

思维过程

想问题还是要去根上找,跑到源码里先看看官方实现的计时器控制逻辑是怎么样的?在 CCSchedule.js 中可以看到有这样一个方法:

代码语言:javascript
复制
setTimeScale: function (timeScale) {
    this._timeScale = timeScale;
}

这个私有属性是如何控制速率的呢?一番寻找,是在 update 中进行了计算:

代码语言:javascript
复制
update: function (dt) {
    this._updateHashLocked = true;
    if(this._timeScale !== 1)
        dt *= this._timeScale;

    var i, list, len, entry;
    //......
}

这样就明白了,实际上就是把被计时器控制的组件的 dt 时间给改了,那我们想实现全局的控制应该再往根源处寻找。

导演类控制

正常讲游戏循环是每秒 60 帧,那么每帧的主循环逻辑应该不是在 CCGame.js 就是在 CCDirector.js 中,果然在导演类中看到了 mainLoop 方法,而其中有这么一段代码(省略了无关代码):

代码语言:javascript
复制
// calculate "global" dt
this.calculateDeltaTime(now);

// Update
if (!this._paused) {
    // before update
    this.emit(cc.Director.EVENT_BEFORE_UPDATE);

    // Call start for new added components
    this._compScheduler.startPhase();

    // Update for components
    this._compScheduler.updatePhase(this._deltaTime);

    // Engine update with scheduler
    this._scheduler.update(this._deltaTime);

    // Late update for components
    this._compScheduler.lateUpdatePhase(this._deltaTime);

    // After life-cycle executed
    this._compScheduler.clearup();

    // User can use this event to do things after update
    this.emit(cc.Director.EVENT_AFTER_UPDATE);
    
    // Destroy entities that have been removed recently
    Obj._deferredDestroy();
}

在没暂停的情况,计算完 dt 后分发下去,那我们在 this.calculateDeltaTime(now) 方法里面把 this._deltaTime 给改了不就可以了,比如这样:

代码语言:javascript
复制
calculateDeltaTime: function (now) {
    if (!now) now = performance.now();

    this._deltaTime = now > this._lastUpdate ? (now - this._lastUpdate) / 1000 : 0;
    if (CC_DEBUG && (this._deltaTime > 1))
        this._deltaTime = 1 / 60.0;
    this._lastUpdate = now;

    // 乘以 2 实现倍数
    this._deltaTime *= 2;
},

或者把这个乘以逻辑放在 calculateDeltaTime 调用的下面也可以:

代码语言:javascript
复制
// calculate "global" dt
this.calculateDeltaTime(now);

// 乘以 2 实现倍数
this._deltaTime *= 2;
更好的实现

试了试还真实现了,能够做到全局控制速率,但是这个方法要魔改下引擎,换项目或者引擎版本无法做到复用,有没有更好的办法呢?当然,是可以不改引擎还能改引擎的(怪怪的,嘿嘿)。其实就是在自己的代码里去更改引擎代码,但是又涉及一个顺序问题,要确保引擎的更改顺序早于你使用的逻辑。

如果你翻过文档,你会知道插件脚本就能实现这个需求,在 CocosCreator 中脚本执行顺序为:Cocos2d 引擎最先执行,然后是插件脚本(有多个的话按项目中的路径字母顺序依次加载),最后才是我们写的普通脚本(打包后只有一个文件,内部按 require 的依赖顺序依次初始化)。

那就写个引擎扩展脚本 k-cocos.js 去扩展引擎就行了,不用魔改引擎,完美!

cc.kSpeed()诞生

接下来就是在这个插件脚本中修改一下引擎计算 dt 的方法,为了方便控制,可以引入一个变量,然后在计算后让时间乘以这个变量,变量默认为 1 代表正常速度,想倍数我们把变量改为 2 就可以了。导演类作为一个单例对象让这个实现更加简单,在 k-cocos.js 中写入:

代码语言:javascript
复制
// 游戏速率变量
cc.director._kSpeed = 1;

var _originCalculateDeltaTime = cc.Director.prototype.calculateDeltaTime;
cc.director.calculateDeltaTime = function (now) {
    _originCalculateDeltaTime.call(this, now);
    this._deltaTime *= this._kSpeed;
}

// 将方法挂到 cc 对象上
cc.kSpeed = function (speed) {
    cc.director._kSpeed = speed;
}

因为是单例对象,直接为其声明 _kSpeed 这个私有变量,然后重写 calculateDeltaTime 方法,在调用保留后的原方法后进行一次乘法即可!(call 方法中的 this 换成 cc.director 也是一样的,如果用箭头函数记得改)

为了不与未来引擎的接口冲突,所有扩展的属性方法都加个 k 字母,这样 cc.kSpeed() 就诞生啦!可以在任何地方愉快的进行 cc.kSpeed(0.3) 这种写法了。

效果图:

干脆开源吧

实现了想要的效果,到这里文章其实应该结束了,但是谁让阔阔这么有奉献精神,独乐乐不如众乐乐,论坛那么多人问游戏倍速的问题,干脆开源吧!名称就叫 KCocos 扩展库,再给自己设计一个图标:

不仅开源,再写个文档,写就写的高大上点!

结语

扩展脚本已经开源,还实现了全局触点数量控制、也扩展了节点的一些属性和方法,还有许多想法没加进去,比如 _hitTest 等!

GitHub地址:https://github.com/KuoKuo666/k-cocos

码云地址:https://gitee.com/kuokuo666/k-cocos

对应文档地址:https://kuokuo666.github.io

2020!我们一起进步!O(∩_∩)O~~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一枚小工 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CocosCreator之控制游戏速率实现倍速与慢动作
    • 摘要
      • 正文
        • 使用版本
        • 思维过程
        • 导演类控制
        • 更好的实现
        • cc.kSpeed()诞生
        • 干脆开源吧
      • 结语
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档