計時器和事件

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

在回合過程中,腳本需要跟蹤時間並在不同的腳本之間發送信號。時間將使用時間腳本來管理,而事件,作為 Roblox 編碼中的一個概念,將發出比賽結束等變化的信號。

使用事件發送信號

隨著玩家進入競技場,可以使用事件來發信號來開始比賽,並且計時器的代碼可以開始。稍後,事件還可以用來發出比賽結束的信號,並且是時候將玩家轉回大廳了。

這些事件不是預建的,因此需要創建稱為 可綁定事件 的自定義事件對象。可綁定事件通常用於玩家引發的動作,並且類似於 TouchedChanged 等事件。

多個腳本可以監聽相同的可綁定事件。這使您的代碼保持整潔,並在需要時更容易為比賽的開始或結束添加其他代碼。

創建可綁定事件

首先創建可綁定事件對象,用於比賽的開始和結束。由於可綁定事件不與客戶端互動,因此可以將其存放在 Server Storage 中。

  1. 在 ServerStorage 中,創建一個名為 Events 的新文件夾。在該文件夾中,創建兩個名為 MatchStart 和 MatchEnd 的 BindableEvents

使用事件

目前,當玩家進入競技場時,休息時間不斷重啟,而不是開始計時器。需要告訴主遊戲循環停止並等待 MatchEnd 事件觸發,才能繼續執行代碼的下一部分。

事件有兩個內置函數:Connect()Wait()。與之前使用 Connect() 不同,對 MatchEnd 調用 Wait() 來暫停遊戲管理器腳本,直到觸發 MatchEnd。在這種情況下,等待函數會暫停代碼,直到遊戲管理器接收到比賽結束的信號。

  1. GameManager 中,創建變量以存儲 Events 文件夾和 MatchEnd 事件。


    -- 模組腳本
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    -- 事件
    local events = ServerStorage:WaitForChild("Events")
    local matchEnd = events:WaitForChild("MatchEnd")
  2. 讓腳本在移動之前等待比賽結束事件的觸發。在 循環結尾 中,輸入:matchEnd.Event:Wait()


    while true do
    repeat
    task.wait(gameSettings.intermissionDuration)
    print("正在重啟休息")
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    print("休息結束")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    -- 占位符等待比賽的長度。
    matchEnd.Event:Wait()
    end
  3. 測試 遊戲。確認一旦玩家在競技場中,休息循環 不會 繼續。現在腳本正在等待 matchEnd 信號的觸發。

疑難排解提示

在此時,代碼不按預期工作,請嘗試以下幾種方法。

  • 再次檢查 matchEnd.Event:Wait() 中的點或冒號運算符的使用。
  • 確保 MatchEnd 是一個 BindableEvent,而不是其他類型,例如 RemoteEvent。

使用計時器

導致比賽結束的條件之一是計時器到期,這將通過腳本處理。

設置計時器

要將計時器添加到遊戲中,請使用以下步驟中的預製模組腳本。它包含開始和結束計時器的函數,以及返回剩餘時間的函數。

  1. 在 ServerStorage > ModuleScripts 中,創建一個名為 Timer 的新模組腳本。

    用以下代碼替換所需的代碼。


    local Timer = {}
    Timer.__index = Timer
    function Timer.new()
    local self = setmetatable({}, Timer)
    self._finishedEvent = Instance.new("BindableEvent")
    self.finished = self._finishedEvent.Event
    self._running = false
    self._startTime = nil
    self._duration = nil
    return self
    end
    function Timer:start(duration)
    if not self._running then
    task.spawn(function()
    self._running = true
    self._duration = duration
    self._startTime = tick()
    while self._running and tick() - self._startTime < duration do
    task.wait()
    end
    local completed = self._running
    self._running = false
    self._startTime = nil
    self._duration = nil
    self._finishedEvent:Fire(completed)
    end)
    else
    warn("警告:計時器無法再次啟動,因為它已經在運行。")
    end
    end
    function Timer:getTimeLeft()
    if self._running then
    local now = tick()
    local timeLeft = self._startTime + self._duration - now
    if timeLeft < 0 then
    timeLeft = 0
    end
    return timeLeft
    else
    warn("警告:無法獲取剩餘時間,計時器沒有運行。")
    end
    end
    function Timer:isRunning()
    return self._running
    end
    function Timer:stop()
    self._running = false
    end
    return Timer
  2. 在 MatchManager 中,要求 GameSettings 和 Timer 模組。


    local MatchManager = {}
    -- 服務
    local ServerStorage = game:GetService("ServerStorage")
    -- 模組腳本
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    local timer = require(moduleScripts:WaitForChild("Timer"))
  3. 在變量下面,通過將一個名為 myTimer 的變量設置為 timer.new() 創建一個新的計時器對象。這個對象將用於調用開始和停止計時器的函數。


    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    local timer = require(moduleScripts:WaitForChild("Timer"))
    -- 創建一個新的計時器對象以跟蹤比賽時間。
    local myTimer = timer.new()

開始和停止

現在已經創建了計時器,在比賽中使用包含的函數 start()stop()。以下是每個函數的描述以及它接受的參數。

  • start(time) - 啟動計時器,參數為秒數。
  • finished:Connect(functionName) - 當計時器完成時,運行作為參數傳遞的函數。
  1. MatchManager 中,創建一個名為 timeUp() 的新函數,當計時器完成時運行。包括一個測試打印語句。


    local myTimer = timer.new()
    -- 本地函數
    local function timeUp()
    print("時間到了!")
    end
    -- 模組函數
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    end
    return MatchManager
  2. timeUp() 下添加一個名為 startTimer() 的函數,並添加一條打印語句。稍後將在遊戲中顯示計時器。


    -- 本地函數
    local function timeUp()
    print("時間到了!")
    end
    local function startTimer()
    print("計時器開始")
    end
  3. 為了啟動和停止計時器,在 startTimer() 中:

    • 調用 myTimer.start()。傳入 gameSettings.matchDuration
    • 調用 myTimer.finished:Connect()。傳入 timeUp()

    -- 本地函數
    local function startTimer()
    print("計時器開始")
    myTimer:start(gameSettings.matchDuration)
    myTimer.finished:Connect(timeUp)
    end

啟動計時器

計時器可以在比賽開始時通過 Match Start 事件觸發。

  1. 在 MatchManager 中,在模組變量下創建變量以存儲 Events 文件夾、MatchStart 和 MatchEnd(在未來的課程中使用)。


    -- 模組腳本
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    local timer = require(moduleScripts:WaitForChild("Timer"))
    -- 事件
    local events = ServerStorage:WaitForChild("Events")
    local matchStart = events:WaitForChild("MatchStart")
    local matchEnd = events:WaitForChild("MatchEnd")
    -- 創建計時器
    local myTimer = timer.new()
  2. return MatchManager 之前,將比賽開始事件連接到 startTimer()


    -- 模組函數
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    end
    matchStart.Event:Connect(startTimer)
    return MatchManager
  3. 為了觸發比賽開始事件,在 prepareGame() 中輸入 matchStart:Fire()


    -- 模組函數
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    matchStart:Fire()
    end
  4. 測試遊戲。在輸出窗口中確認您可以看到計時器的開始和停止函數的打印語句。

完整腳本

以下是完成的腳本,以便檢查您的工作。

MatchManager 腳本


local MatchManager = {}
-- 服務
local ServerStorage = game:GetService("ServerStorage")
-- 模組腳本
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- 創建一個新的計時器對象以跟蹤比賽時間。
local myTimer = timer.new()
-- 本地函數
local function timeUp()
print("時間到了!")
end
local function startTimer()
print("計時器開始")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
end
-- 模組函數
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
return MatchManager

GameManager 腳本


-- 服務
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- 模組腳本
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
while true do
repeat
task.wait(gameSettings.intermissionDuration)
print("正在重啟休息")
until #Players:GetPlayers() >= gameSettings.minimumPlayers
print("休息結束")
task.wait(gameSettings.transitionTime)
matchManager.prepareGame()
-- 占位符等待比賽的長度。
matchEnd.Event:Wait()
end