如何使用游戏更新调度本页总览如何使用游戏更新调度 Dora SSR 提供了灵活的调度机制,让开发者可以方便地控制游戏逻辑的更新。本教程将带你了解如何使用游戏更新调度系统,包括异步处理的协程任务和每帧重复调用的更新函数。 1. 理解游戏更新调度 游戏更新调度是游戏引擎中用于管理和执行游戏逻辑更新的机制。它允许开发者在每一帧或特定条件下执行代码, 从而实现动态的游戏体验。游戏引擎的本质就是一个不间断的循环程序,每一次循环称为一帧,游戏逻辑的更新就是在每一帧中进行的。 一个典型的游戏逻辑更新流程如下,在 60 帧执行的引擎下,这个流程会在每秒执行 60 次: 2. 协程任务与更新函数的区别 协程任务(Coroutine Tasks): 异步处理:可以在多个帧之间暂停和恢复。 使用场景:适合处理需要等待的操作,如加载资源、计时器等。 实现方式:通过 thread、threadLoop、once、loop 等函数。 更新函数(Update Functions): 同步处理:在每一帧都会被调用。 使用场景:适合处理每帧都需要更新的逻辑,如移动、碰撞检测等。 实现方式:通过 node:schedule()、node:onUpdate() 函数。 3. 使用协程任务实现异步处理 协程任务允许您在执行过程中暂停,等待条件满足或一定的时间,然后继续执行。允许你在不阻塞主线程的情况下执行耗时操作。这对于处理异步事件非常有用。 3.1 全局协程任务与节点关联的协程任务 在 Dora SSR 中,协程任务的执行有两种方式: 全局协程任务:使用 thread(function() ... end) 创建的协程任务,其生命周期由引擎的全局调度模块管理。除非手动移除,这些任务会一直运行,直到引擎退出时才会清理所有正在执行的调度。 节点关联的协程任务:使用 node:schedule(once(function() ... end)) 创建的协程任务,其生命周期与关联的节点相同。当节点被清理时,调度在其上的函数也会被停止并清理。 示例:执行一个全局协程任务 LuaTealTypeScriptYueScriptlocal thread <const> = require("thread")local sleep <const> = require("sleep")local Content <const> = require("Content")thread(function() print("开始异步加载资源") local resourceData = Content:loadAsync("path/to/resource") sleep(2) -- 模拟额外的耗时操作 print("资源加载完成") -- 在资源加载完成后执行后续逻辑end)local thread <const> = require("thread")local sleep <const> = require("sleep")local Content <const> = require("Content")thread(function() print("开始异步加载资源") local resourceData = Content:loadAsync("path/to/resource") sleep(2) -- 模拟额外的耗时操作 print("资源加载完成") -- 在资源加载完成后执行后续逻辑end)import { thread, sleep, Content } from "Dora";thread(() => { print("开始异步加载资源"); const resourceData = Content.loadAsync("path/to/resource"); sleep(2); // 模拟额外的耗时操作 print("资源加载完成"); // 在资源加载完成后执行后续逻辑});_ENV = Dorathread -> print "开始异步加载资源" resourceData = Content\loadAsync "path/to/resource" sleep 2 -- 模拟额外的耗时操作 print "资源加载完成" -- 在资源加载完成后执行后续逻辑 在上述示例中,thread(function() ... end) 创建了一个协程任务,loadAsync 异步加载资源,sleep(2) 模拟耗时操作。协程使得长时间运行的任务不会阻塞主线程,任务的生命周期由引擎全局管理。 提示 在 Dora SSR 中,通常带有 async 后缀的函数都是异步函数,例如 Content.loadAsync 和 Cache.loadAsync,需要放在协程任务中来异步执行。 示例:节点关联的协程任务 LuaTealTypeScriptYueScriptlocal Node <const> = require("Node")local sleep <const> = require("sleep")local node = Node()node:once(function() print("开始节点关联的异步操作") sleep(2) -- 模拟耗时操作 print("节点关联的异步操作完成")end)local Node <const> = require("Node")local sleep <const> = require("sleep")local node = Node()node:once(function() print("开始节点关联的异步操作") sleep(2) -- 模拟耗时操作 print("节点关联的异步操作完成")end)import { Node, sleep } from "Dora";const node = Node();node.once(() => { print("开始节点关联的异步操作"); sleep(2); // 模拟耗时操作 print("节点关联的异步操作完成");});_ENV = Doranode = Node!node\once -> print "开始节点关联的异步操作" sleep 2 -- 模拟耗时操作 print "节点关联的异步操作完成" 这里,node:once(function() ... end) 创建了一个与节点 node 关联的协程任务。当 node 被清理时,任务也会自动停止并清理。 3.2 两种协程任务使用的区别 生命周期管理: 全局协程任务:生命周期独立于任何节点,由引擎全局调度模块管理,需要手动移除或等待引擎退出时清理。 节点关联的协程任务:生命周期与关联节点绑定,当节点被销毁时,任务自动停止并清理。 适用场景: 全局协程任务:适合需要在整个游戏生命周期中持续运行的任务,如全局事件监听。 节点关联的协程任务:适合与特定场景或对象关联的任务,如角色的动画控制。 3.3 使用协程控制函数