如何在cocos里面合理执行耗时计算又不卡住界面?

  • Creator 版本: 3.8.2
  • 目标平台: iOS / Android / 可能会Web

我们计划用cocos做一款棋类游戏,当中会涉及到机器人对弈的AI计算,我们测试过,点击按钮触发计算的话,大约需要4秒钟才能完成计算过程,这个过程中,按钮一直是按下状态,然后整个界面都是卡死的

所以如果我们需要点击按钮后,触发AI计算,并且显示“机器人思考中”,然后计算完毕后关闭提示语并刷新界面,这个应该怎样做比较合理呢?

劳烦大佬们指教

1赞

分帧计算呗,存下来上一帧的计算数据…不过4s的计算听起来就好复杂的样子 :rofl:

另外开个线程计算,web 用worker 就可以。

web我知道用worker,但是在安卓和ios甚至鸿蒙平台我都没找到该怎么办好,难道大家都不会遇到这种耗时计算的吗?

脑补了一下FC里面的中国象棋,好像是要等一下的 体验也不糟糕,不过4s确实太久了

看ai的难度等级,我们也可以调低,但是调高难度对于某些用户还是需要的,在unity里面我们用协程搞定的,cocos里面文档都没这个概念

安卓和ios,可以开个线程做计算,不过计算逻辑得放到原生端了,建议c++写一套就行,ios和安卓都能调

我在github上push了一个pr,让Creator原生也有worker能力,有兴趣可以参考自己集成

这四秒一直耗cpu吗,在unity中都可以用协程搞定,在cocos中当然也可以用协程搞定

写在哪里问题不大,几个平台我都熟,ndk也能用,就是鸿蒙我现在头疼,没有原生交互能力

一直都在深度遍历计算,cocos文档里面搜线程协程好像都找不到,所以协程是所谓分帧计算?

让后端算------ 转移矛盾

同问同问 正好遇到相同的问题

印象里creator还没有真正的协程一说,分帧只是权宜之计

服务器算力可能也就是两三台手机的算力,这不划算啊

JavaScript 是单线程的,这意味着在主线程上执行的复杂或耗时的算法可能会阻塞用户界面的更新和用户交互,从而导致界面卡住。为了解决这个问题,可以采取以下几种策略:

  1. Web Workers** : Web Workers 允许你在后台线程中运行代码,从而不会阻塞主线程。你可以将复杂的算法放在一个 Worker 中执行,然后将结果传回主线程。

// main.js
const worker = new Worker(‘worker.js’);
worker.onmessage = function(e) {
console.log(‘Message received from worker:’, e.data);
};
worker.postMessage(‘start’); // 向 worker 发送消息以开始处理
// worker.js
onmessage = function(e) {
if (e.data === ‘start’) {
// 执行复杂算法
const result = performComplexAlgorithm();
postMessage(result); // 将结果发送回主线程
}
};
function performComplexAlgorithm() {
// 复杂的计算…
return ‘some result’;
}

  1. 异步函数(Async/Await):
    如果算法可以被分解为多个异步步骤,可以使用 async/await 来避免阻塞。尽管这不会减少算法的总执行时间,但可以让主线程有机会处理其他任务,比如更新界面。

async function complexAlgorithm() {
await step1();
await step2();
// …
}

  1. 分时处理(Time slicing)** : 将复杂算法分解成小的任务块,并在每个任务块执行完毕后,使用 setTimeoutrequestAnimationFrame 让出控制权,给予浏览器更新界面的机会。

function performComplexAlgorithm(steps) {
if (steps.length === 0) {
return;
}
// 执行下一步骤
const nextStep = steps.shift();
nextStep();
// 让出控制权,并在稍后继续执行
setTimeout(() => performComplexAlgorithm(steps), 0);
}
const steps = [step1, step2, /* … */];
performComplexAlgorithm(steps);

4. 优化算法:
重新审视并优化算法本身,减少不必要的计算和内存使用,提高效率。例如,使用更高效的数据结构,减少循环的次数,避免重复计算等。
5. 使用第三方库:
有时候,第三方库已经对某些复杂的算法进行了优化。使用这些库可能会比自己实现算法更高效。

选择哪种策略取决于算法的特点和应用程序的需求。在某些情况下,你可能需要结合使用多种策略来达到最佳效果。
1赞

你的性能消耗点在ai模型上。若是一定要本地计算,只有优化模型了。
我个人观点:

  1. 设计模型时,输入参数里,多一个设备档次。搞个if分支,参数低的就减少对应层数和每层参数量
  2. 激活函数用ReLU等公式简单的,不用sigmoid
  3. 尽量基于简单的模型来,不用很复杂计算量很大的基础模型

js 本身是单线程的,别想开协程了,除非搞原生,单独开线程来做

原生平台就直接用c++的线程就可以,不过你ai要写2套,一套给web的worker用,一套cpp给native线程用。
鸿蒙就不知道了。不过基本上都会支持线程这类的吧。

还有种办法,用async/await在js里面虽然也是单线程的。但是你可以把算法本身拆了很多await在里面,把每个步骤或者循环里面,多嵌入一些await timer类的语句。这样就把算法分拆开了,又能保持上下文。其实就是相当于分帧了。我想你们unity的协程写法应该也是类似的吧

有个想法不确定行不行,客户端本地启动一个wesocket服务器,在本地的服务器里计算,不知道他们是不是在同一个线程

unity我们没有深入研究,因为毕竟不开源,分帧的话就很不友好了,本来可以全力计算一个下棋步骤,分帧的话我还需要克制地安排计算步骤,这种模式还真是不太好。我估计还是考虑弹出到原生,使用java和oc的线程来解决问题。