延迟操作
延迟操作 API 提供完整的定时器系统,可在延迟后执行代码,并全面控制时间、暂停、取消和循环。此系统类似于 Unreal Engine 的定时器系统。
概述
所有延迟操作都在游戏线程执行,并返回可用于控制操作的句柄。操作归创建它的 Mod 所有,避免不同 Mod 相互干扰。
创建延迟操作
ExecuteInGameThreadWithDelay
在指定延迟后执行回调。
重载 1:自动生成句柄
local handle = ExecuteInGameThreadWithDelay(delayMs, callback)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 执行前的延迟,单位为毫秒 |
| 2 | function | 要执行的回调 |
| 返回值 | integer | 创建的操作的句柄 |
重载 2:用户提供句柄(UE Delay 风格)
ExecuteInGameThreadWithDelay(handle, delayMs, callback)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 句柄(由 MakeActionHandle() 生成) |
| 2 | integer | 延迟,单位为毫秒 |
| 3 | function | 要执行的回调 |
此重载仅在该句柄尚未处于活动状态时创建操作,与 Unreal Engine 的 Delay 节点行为一致。
RetriggerableExecuteInGameThreadWithDelay
在延迟后执行回调;如果使用相同句柄再次调用,则重置定时器。
RetriggerableExecuteInGameThreadWithDelay(handle, delayMs, callback)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 句柄(由 MakeActionHandle() 生成) |
| 2 | integer | 延迟,单位为毫秒 |
| 3 | function | 要执行的回调 |
适用于防抖:每次调用都会重置定时器,因此只有在整个延迟期间没有新调用时,回调才会触发。
LoopInGameThreadWithDelay
创建重复定时器,以固定时间间隔执行回调。
local handle = LoopInGameThreadWithDelay(delayMs, callback)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 两次执行之间的延迟,单位为毫秒 |
| 2 | function | 要执行的回调 |
| 返回值 | integer | 创建的循环的句柄 |
循环会持续运行,直到调用 CancelDelayedAction(handle) 取消。
ExecuteInGameThreadAfterFrames
等待指定帧数后执行回调。
local handle = ExecuteInGameThreadAfterFrames(frames, callback)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 要等待的帧数 |
| 2 | function | 要执行的回调 |
| 返回值 | integer | 创建的操作的句柄 |
注意: 需要 EngineTick 钩子。使用前请检查 EngineTickAvailable。
LoopInGameThreadAfterFrames
创建重复定时器,每隔 N 帧执行一次回调。
local handle = LoopInGameThreadAfterFrames(frames, callback)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 两次执行之间的帧数 |
| 2 | function | 要执行的回调 |
| 返回值 | integer | 创建的循环的句柄 |
注意: 需要 EngineTick 钩子。使用前请检查 EngineTickAvailable。
MakeActionHandle
生成可用于延迟函数的唯一句柄。
local handle = MakeActionHandle()
| # | 类型 | 说明 |
|---|---|---|
| 返回值 | integer | 可用于延迟函数的唯一句柄 |
控制延迟操作
CancelDelayedAction
取消等待中或活动中的延迟操作。
local success = CancelDelayedAction(handle)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 要取消的操作的句柄 |
| 返回值 | boolean | 找到并取消操作时为 true |
PauseDelayedAction
暂停延迟操作,并保留剩余时间。
local success = PauseDelayedAction(handle)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 要暂停的操作的句柄 |
| 返回值 | boolean | 找到并暂停操作时为 true |
UnpauseDelayedAction
恢复已暂停的延迟操作。
local success = UnpauseDelayedAction(handle)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 要恢复的操作的句柄 |
| 返回值 | boolean | 找到并恢复操作时为 true |
ResetDelayedActionTimer
使用原始延迟重新启动定时器。
local success = ResetDelayedActionTimer(handle)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 要重置的操作的句柄 |
| 返回值 | boolean | 找到并重置操作时为 true |
SetDelayedActionTimer
更改延迟并重新启动定时器。
local success = SetDelayedActionTimer(handle, newDelayMs)
| # | 类型 | 说明 |
|---|---|---|
| 1 | integer | 要修改的操作的句柄 |
| 2 | integer | 新延迟,单位为毫秒 |
| 返回值 | boolean | 找到并修改操作时为 true |
ClearAllDelayedActions
取消属于当前 Mod 的全部延迟操作。
local count = ClearAllDelayedActions()
| # | 类型 | 说明 |
|---|---|---|
| 返回值 | integer | 已取消的操作数量 |
注意: 仅影响调用此函数的 Mod 所创建的操作,不会影响其他 Mod 的操作。
查询延迟操作
IsValidDelayedActionHandle
检查句柄是否指向一个存在且未取消的操作。
local valid = IsValidDelayedActionHandle(handle)
IsDelayedActionActive
检查操作当前是否处于活动状态(未暂停,也未等待移除)。
local active = IsDelayedActionActive(handle)
IsDelayedActionPaused
检查操作当前是否已暂停。
local paused = IsDelayedActionPaused(handle)
GetDelayedActionRate
获取操作配置的延迟。
local delayMs = GetDelayedActionRate(handle)
对于基于时间的操作,返回配置的延迟毫秒数;对于基于帧的操作,返回帧数。句柄无效时返回 -1。
GetDelayedActionTimeRemaining
获取距离操作触发的剩余时间。
local remainingMs = GetDelayedActionTimeRemaining(handle)
对于基于时间的操作,返回剩余毫秒数;对于基于帧的操作,返回剩余帧数。句柄无效时返回 -1。
GetDelayedActionTimeElapsed
获取操作启动或重置后经过的时间。
local elapsedMs = GetDelayedActionTimeElapsed(handle)
对于基于时间的操作,返回经过的毫秒数;对于基于帧的操作,返回经过的帧数。句柄无效时返回 -1。
全局变量
EngineTickAvailable
表示 EngineTick 钩子是否可用的布尔值。
if EngineTickAvailable then
-- Frame-based delays are available
end
ProcessEventAvailable
表示 ProcessEvent 钩子是否可用的布尔值。
if ProcessEventAvailable then
-- ProcessEvent-based execution is available
end
示例
简单延迟
ExecuteInGameThreadWithDelay(2000, function()
print("This prints after 2 seconds\n")
end)
自行取消的循环
先声明 loopHandle,再赋值,确保闭包能够捕获它。每秒执行一次,计数达到 5 后取消循环。
local counter = 0
local loopHandle -- Declare first for closure capture
loopHandle = LoopInGameThreadWithDelay(1000, function()
counter = counter + 1
print(string.format("Tick %d\n", counter))
if counter >= 5 then
CancelDelayedAction(loopHandle)
print("Loop stopped\n")
end
end)
防抖操作
仅在最后一次按键后的 500 毫秒触发。
local debounceHandle = MakeActionHandle()
RegisterKeyBind(Key.F, function()
-- Only fires 500ms after the last key press
RetriggerableExecuteInGameThreadWithDelay(debounceHandle, 500, function()
print("Debounced action fired\n")
end)
end)
可暂停的定时器
定时器在 2 秒后暂停,在 5 秒后恢复。
local timerHandle = ExecuteInGameThreadWithDelay(10000, function()
print("Timer completed\n")
end)
-- Pause after 2 seconds
ExecuteInGameThreadWithDelay(2000, function()
PauseDelayedAction(timerHandle)
print("Timer paused\n")
end)
-- Resume after 5 seconds
ExecuteInGameThreadWithDelay(5000, function()
UnpauseDelayedAction(timerHandle)
print("Timer resumed\n")
end)
UE 风格延迟(仅在不存在时创建)
只有该句柄尚未处于活动状态时才创建延迟。
local cooldownHandle = MakeActionHandle()
RegisterKeyBind(Key.E, function()
-- Only creates the delay if not already active
ExecuteInGameThreadWithDelay(cooldownHandle, 1000, function()
print("Ability ready!\n")
end)
print("Ability used (1s cooldown)\n")
end)
基于帧的延迟
if EngineTickAvailable then
ExecuteInGameThreadAfterFrames(60, function()
print("Fired after 60 frames\n")
end)
end
重要注意事项
-
闭包捕获:在循环自己的回调内使用循环句柄时,必须先声明变量,再赋值:
local loopHandle -- Declare first loopHandle = LoopInGameThreadWithDelay(1000, function() CancelDelayedAction(loopHandle) -- Now correctly captured end) -
Mod 所有权:每个 Mod 只能控制自己的延迟操作。向
CancelDelayedAction、PauseDelayedAction等函数传入其他 Mod 的句柄时,操作会失败。 -
基于帧的延迟:需要 EngineTick 钩子。使用
ExecuteInGameThreadAfterFrames或LoopInGameThreadAfterFrames前,始终检查EngineTickAvailable。 -
回退行为:默认执行方式不可用时,如果另一种方式可用,系统会自动回退到另一种方式。
原文:docs/lua-api/global-functions/delayedactions.md · 固定提交 560411f18512 · 来源与 MIT 许可