游戏计时

Time:10 分钟

几乎所有游戏都需要以某种方式计时。在 Roblox 中,脚本有多种计时以及等待的方法,又名 yielding(暂停)

使用 wait 的简单暂停 ```

print("我们来玩等待游戏吧。")
wait(5)
print("你赢了!")
## 简单暂停

最简单的暂停可以使用 `wait` 函数实现,这将暂停指定的秒数。它的用法非常直截了当:

当 `wait` 被调用时,Roblox 的内部计划程序会让线程暂停尽可能地接近给定时间,然后发出信号让线程再次恢复。

### 与 Unity 的 StartCoroutine/IEnumerator 对比

下面的示例取自 [Unity 脚本编写 API:WaitForSeconds](https://docs.unity3d.com/ScriptReference/WaitForSeconds.html).
    
    
    using UnityEngine;
    using System.Collections;
    
    public class WaitForSecondsExample : MonoBehaviour
    {
        void Start()
        {
            StartCoroutine(Example());
        }
    
        IEnumerator Example()
        {
            print(Time.time);
            yield return new WaitForSeconds(5);
            print(Time.time);
        }
    }
    

在 Roblox 中,与之作用类似的代码如下:

Roblox Lua Comparison 与 Unity 的 WaitForSeconds 的比较 ```    
    
    local function Start()
    	-- 这里 `spawn` 的作用与 MonoBehaviour 的 `StartCoroutine` 类似。
    	-- 注意:我们以函数名称对其进行引用而不是调用!
    	spawn(Example)
    end
    
    local function Example()
    	print(time())
    	wait(5)
    	print(time())
    end
    
    Start()
    
    
    0
    5

用函数暂停

有时定义一个函数并在给定的秒数后运行更加容易。‘delay’ 函数在这方面是完美的选择:以秒为单位指定等待时间,并在指定时间过后运行一个函数:

延迟示例 ```

local function explode()
	print("轰隆!")
end
delay(5, explode)


Kaboom!
### 与 Unity 中 MonoBehavior 的 Invoke 对比

下面是一段 Unity C# 脚本示例,它将在两秒后运行 `Explode` 方法。这是为了展示 Unity 中 MonoBehavior 的 [Invoke]([https://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html)与](https://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html%EF%BC%89%E4%B8%8E) Roblox 中的 `delay` 函数的相似性。
    
    
    using UnityEngine;
    
    public class ExampleScript : MonoBehaviour
    {
        void Start()
        {
            Invoke("Explode", 2);
        }
    
        void Explode()
        {
        	print("轰隆!");
        }
    }
    

上面的示例类似 Roblox 中的以下代码:

Roblox Lua Comparison 与 Unity C# 中 MonoBehavior 的 Invoke 的比较# ```    
    
    local function Start()
    	-- 注意:这里我们将 Explode 函数作为参考而不是字符串传递。
    	delay(2, Explode)
    end
    
    local function Explode()
    	print("轰隆!")
    end
    
    Start()
    
    
    Kaboom!

Invokedelay 都不会暂停当前线程。换句话说,脚本将在计划函数调用后立即继续运行。

每帧计时

更常见情况的是,脚本会有必须尽可能频繁地运行的逻辑。RunService/Stepped 事件会在游戏运行时的每帧触发,差不多每秒 60 帧。在 Studio 中,这是在点击 “Run(运行)”或 “Play Solo(单人游戏)”之后开始。该事件以当前游戏时间触发,然后是自上一帧以来的时间(增量时间)。

RunService Stepped 示例 ```

local RunService = game:GetService("RunService")

local function onStepped(t, dt)
	-- 此函数每帧运行。
	-- t: 游戏运行的时间,以秒为单位
	-- dt: 自上次 Stepped 触发后经过的时间,以秒为单位
	print("自上一帧之后的秒数: " .. dt)
end
RunService.Stepped:Connect(onStepped)


Seconds since last frame: 0.015212
有时已经无需再每帧运行这样的函数。为此,可以保存一个由 `Connect` 返回的 Connection 对象的引用,之后再调用 `Disconnect`。下面的示例是“简单的暂停”示例中基于事件的实现。

用 RunService Stepped 等待 ```    
    
    local RunService = game:GetService("RunService")
    
    local connection
    local countedTime = 0
    local goalTime = 5
    
    local function onStepped(t, dt)
    	countedTime = countedTime + dt
    	if countedTime >= goalTime then
    		print("You win!")
    		-- 我们不再需要计时,因此这里断开连接:
    		connection:Disconnect()
    		-- 如果我们要数 `goalTime` 的每一秒,可以从 `countedTime` 删减而不是断开连接:
    		countedTime = countedTime - goalTime
    	end
    end
    print("我们来玩等待游戏吧。")
    connection = RunService.Stepped:Connect(onStepped)
    
    
    Let's play the waiting game.
    You win!

基于事件的方法有利于保持代码简洁。有关事件的更多信息,请参见关于事件的文章。

与 Unity C# 中 MonoBehavior 的 Update 对比

在 Roblox 中连接至 RunService/Stepped 与在 Unity 中的 MonoBehaviour 定义 Update 函数非常相似。

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
	void Update()
	{
		print(Time.time);
	}
}

上面的示例类似于 Roblox 中的以下代码:

local RunService = game:GetService("RunService")

local function Update(t, dt)
	print(time())
end

RunService.Stepped:Connect(Update)

渲染函数步骤

有时 LocalScript 需要负责处理视觉效果。例如,让箭头指向某个对象。这种视觉效果应该在屏幕渲染之前更新。在 Roblox 中,您可以使用 RunService/BindToRenderStep 函数来实现:

RunService BindToRenderStep 示例 ```

local RunService = game:GetService("RunService")
local function runEveryRenderStep()
	-- 此函数在屏幕显示时允许
end
RunService:BindToRenderStep("renderStepDemo", 1, runEveryRenderStep)
-- 之后您可能需要解绑此函数。为此,请使用:
RunService:UnbindFromRenderStep("renderStepDemo")


***__Roblox官方链接__:[游戏计时](https://developer.roblox.com/zh-cn/articles/keeping-time)