清理和重設

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

是時候編寫遊戲最後一個階段的代碼:清理和重設。在這個階段的代碼確保遊戲循環進入中場休息,並且未來的比賽對每一位玩家都一樣開始。

更新介面

在進行清理和重置之前,通過向玩家顯示管理器顯示遊戲結束的狀態來告知玩家遊戲結束的方式。

取得勝利者的名稱

先從獲得勝利的玩家名稱開始,如果有一個。以前,代碼檢查是否有活動玩家表的大小降至 1。要取得剩下的玩家名稱,請在該表的第一個索引返回名稱。

  1. 在 PlayerManager 中,啟動名為 getWinnerName() 的新模組功能。


    function PlayerManager.getWinnerName()
    end
    -- 事件
    Players.PlayerAdded:Connect(onPlayerJoin)
  2. 添加在 activePlayers[1] 中運行的 if 聲明,如果存在某些東西。雖然之前檢查過桌子數量,但玩家可能已經斷線或離開遊戲。


    function PlayerManager.getWinnerName()
    local winningPlayer = activePlayers[1]
    if winningPlayer then
    end
    end
  3. 在 if 聲明中:

    • 返回玩家的名稱。
    • 對於其他,返回錯誤字串。

    function PlayerManager.getWinnerName()
    local winningPlayer = activePlayers[1]
    if winningPlayer then
    return winningPlayer.Name
    else
    return "Error: No winning player found"
    end
    end

取得最終狀態

使用模組功能從正確的終狀態取得資訊,無論定時器結束或一名玩家被留下。然後,將那個狀態變量傳送到顯示管理器,以更新狀態GUI以顯示適當的訊息。

  1. 配對管理器 中,編寫一個新模組功能名為 getEndStatus() 的參數名為 endState 的功能。要儲存將傳送的訊息,請新增名為 statusToReturn 的空變量。


    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    matchStart:Fire()
    end
    function MatchManager.getEndStatus(endState)
    local statusToReturn
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  2. 使用 if 和 elseif 文件來設置 statusToReturn 的值。檢查終狀態變量:FoundWinnerTimerUp 。對於錯誤檢查,在結尾包含其他內容。


    function MatchManager.getEndStatus(endState)
    local statusToReturn
    if endState == gameSettings.endStates.FoundWinner then
    elseif endState == gameSettings.endStates.TimerUp then
    else
    end
    end
  3. 為每個條件添加以下內容:

    FoundWinner

    • 使用 playerManager.getWinnerName() 的勝利者變量。
    • 使用字串更新 statusToReturn 宣布勝利者。

    TimerUp

    • 使用字串宣布時間到期來更新 statusToReturn

    Else

    • 在更新 statusToReturn 時遇到終場遊戲訊息獲得問題的情況下,發出錯誤訊息以進行更新。

    function MatchManager.getEndStatus(endState)
    local statusToReturn
    if endState == gameSettings.endStates.FoundWinner then
    local winnerName = playerManager.getWinnerName()
    statusToReturn = "Winner is : " .. winnerName
    elseif endState == gameSettings.endStates.TimerUp then
    statusToReturn = "Time ran out!"
    else
    statusToReturn = "Error found"
    end
    end
  4. 透過輸入 return statusToReturn 將訊息傳回。


    function MatchManager.getEndStatus(endState)
    local statusToReturn
    if endState == gameSettings.endStates.FoundWinner then
    local winnerName = playerManager.getWinnerName()
    statusToReturn = "Winner is : " .. winnerName
    elseif endState == gameSettings.endStates.TimerUp then
    statusToReturn = "Time ran out!"
    else
    statusToReturn = "Error found"
    end
    return statusToReturn
    end

顯示和測試

在 GameManager 中獲得更新的公告,並將其顯示給使用 DisplayManager 的玩家。

  1. 開啟 遊戲管理器 。在 while 真實做循環期間, 刪除 最後一個印字聲明。然後,創建一個名為 endStatus 的變量。將其設為等於呼叫 matchManager.getEndStatus(endState)


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    local endStatus = matchManager.getEndStatus(endState)
    end
  2. 要在 GUI 標籤中顯示返回的訊息,請呼叫 displayManager.updateStatus() 並傳入 endStatus


    local endStatus = matchManager.getEndStatus(endState)
    displayManager.updateStatus(endStatus)
  3. 因此,遊戲暫停,讓玩家看到訊息,並使用 transitionTime 添加等待。


    local endStatus = matchManager.getEndStatus(endState)
    displayManager.updateStatus(endStatus)
    task.wait(gameSettings.transitionTime)
  4. 啟動 測試伺服器 並檢查玩家是否看到以下訊息,以確認時間到和獲勝玩家條件。

    時間已過條件
    獲勝玩家條件

排除故障提示

在這個時候,您無法看到訊息,請嘗試以下方法之一。

  • 如果您的結束狀態訊息是「發現錯誤」,沒有任何條件成功。請在 MatchManager.getEndStatus() 對代碼樣本進行比較,以確認代碼是否正確。
  • 如果結束狀態未顯示,請檢查 task.wait(gameSettings.transitionTime) 是否在傳送訊息給顯示管理器之後顯示。

開始新的賽局

在開始新比賽之前,會有短暫的過渡。這讓玩家有時間查看最終狀態,並讓被傳送到大廳的感覺變得較為突然。

在轉換結束時,剩餘的玩家將被從競技場移除,所有代碼將重置。這樣可以確保玩家會在下一場比賽開始時使用清潔版本的遊戲。

處理轉換

當玩家進入轉換狀態時,移除他們的武器。

  1. 在 PlayerManager 中,找到本地功能。複製並粘貼下方的強調代碼removePlayerWeapon()。代碼會移除已主動配備或存在於玩家背包中的個別玩家武器。


    local function removePlayerWeapon(whichPlayer)
    -- 檢查是否存在玩家,以防他們斷線或離開。
    if whichPlayer then
    local character = whichPlayer.Character
    -- 如果玩家目前擁有它在他們的角色上
    local weapon = character:FindFirstChild("Weapon")
    if weapon then
    weapon:Destroy()
    end
    -- 如果玩家在背包中擁有武器
    local backpackWeapon = whichPlayer.Backpack:FindFirstChild("Weapon")
    if backpackWeapon then
    backpackWeapon:Destroy()
    end
    else
    print("No player to remove weapon")
    end
    end
  2. 啟動名為 removeAllWeapons() 的新模組功能。


    function PlayerManager.removeAllWeapons()
    end
    -- 事件
    Players.PlayerAdded:Connect(onPlayerJoin)
    return PlayerManager
  3. 在那個功能中,使用 for 循環來通過活動玩家表。在循環中,呼叫 removePlayerWeapon() 並傳送找到的玩家。


    function PlayerManager.removeAllWeapons()
    for playerKey, whichPlayer in activePlayers do
    removePlayerWeapon(whichPlayer)
    end
    end

在比賽之間清理

清理將在 MatchManager 中自己的功能。目前,清理將只使用先前創建的功能來移除玩家武器。隨著您擴展遊戲,可以新增更多功能,例如用於重設在比賽期間發生變更的地圖的功能。

  1. 開啟配對管理器。新增名為 cleanupMatch() 的新模組功能。在該功能中,呼叫 playerManager.removeAllWeapons()


    function MatchManager.cleanupMatch()
    playerManager.removeAllWeapons()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  2. 接下來,呼叫清理函數。開啟 遊戲管理器 並找到 while 真正循環。因此,玩家在結束中場休息時會移除武器,在最後一次 matchManager.cleanupMatch() 之前呼叫 task.wait()


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    local endStatus = matchManager.getEndStatus(endState)
    displayManager.updateStatus(endStatus)
    matchManager.cleanupMatch()
    task.wait(gameSettings.transitionTime)
    end
  3. 啟動測試伺服器並執行一場比賽。等待計時器耗盡,確認玩家的武器在比賽結束期間被移除。

    在比賽期間
    比賽結束後

重置匹配項

您可能已經注意到遊戲中的其他一些事情,例如玩家在比賽結束後仍然在競技場上。匹配清理完畢後,下一步重設遊戲。這包括將在競技場的玩家送回大廳並清除已啟用的玩家表。配置重置後,遊戲循環可以無限期運行。

首先,啟動一個功能將玩家帶回大廳。

  1. 在 PlayerManager 中:

    • 創建名為 resetPlayers() 的模組功能。
    • 添加一個 for 循環來在活動玩家中循環。
    • 在循環中,呼叫 respawnPlayerInLobby() 並將玩家傳送為參數。

    function PlayerManager.resetPlayers()
    for playerKey, whichPlayer in activePlayers do
    respawnPlayerInLobby(whichPlayer)
    end
    end
    -- 事件
    Players.PlayerAdded:Connect(onPlayerJoin)
    return PlayerManager
  2. 確保下一場比賽的 activePlayers 表是空的,通過將其設為 {} 來重設為空表的快速方式。


    function PlayerManager.resetPlayers()
    for playerKey, whichPlayer in activePlayers do
    respawnPlayerInLobby(whichPlayer)
    end
    activePlayers = {}
    end
  3. 開啟配對管理器。編寫名為 resetMatch() 的新模組功能,並呼叫 playerManager.resetPlayers()


    function MatchManager.resetMatch()
    playerManager.resetPlayers()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  4. 返回到 遊戲管理器 。在 while 真實循環結束時,呼叫 matchManager.resetMatch()


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    local endStatus = matchManager.getEndStatus(endState)
    displayManager.updateStatus(endStatus)
    matchManager.cleanupMatch()
    task.wait(gameSettings.transitionTime)
    matchManager.resetMatch()
    end
  5. 啟動測試伺服器並執行一場比賽。確認您至少可以通過兩個遊戲循環而不發生任何錯誤。

已完成的腳本

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

遊戲管理員腳本


-- 服務
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 displayManager = require(moduleScripts:WaitForChild("DisplayManager"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
while true do
displayManager.updateStatus("Waiting for Players")
repeat
task.wait(gameSettings.intermissionDuration)
until #Players:GetPlayers() >= gameSettings.minimumPlayers
displayManager.updateStatus("Get ready!")
task.wait(gameSettings.transitionTime)
matchManager.prepareGame()
local endState = matchEnd.Event:Wait()
local endStatus = matchManager.getEndStatus(endState)
displayManager.updateStatus(endStatus)
matchManager.cleanupMatch()
task.wait(gameSettings.transitionTime)
matchManager.resetMatch()
end

匹配管理員腳本


local MatchManager = {}
-- 服務
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 模組腳本
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- 值
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local timeLeft = displayValues:WaitForChild("TimeLeft")
-- 創建一個新的計時器對象,用於跟蹤比賽時間。
local myTimer = timer.new()
-- 本地功能
local function stopTimer()
myTimer:stop()
end
local function timeUp()
matchEnd:Fire(gameSettings.endStates.TimerUp)
end
local function startTimer()
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
while myTimer:isRunning() do
-- 添加 +1 可確保計時器顯示結束於 1 而不是 0。
timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
-- 通過不設置等待時間,它提供更準確的循環
task.wait()
end
end
-- 模組功能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
function MatchManager.getEndStatus(endState)
local messageToReturn
if endState == gameSettings.endStates.FoundWinner then
local winnerName = playerManager.getWinnerName()
messageToReturn = "Winner is : " .. winnerName
elseif endState == gameSettings.endStates.TimerUp then
messageToReturn = "Time ran out!"
else
messageToReturn = "Error found"
end
return messageToReturn
end
function MatchManager.cleanupMatch()
playerManager.removeAllWeapons()
end
function MatchManager.resetMatch()
playerManager.resetPlayers()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager

玩家管理員腳本


local PlayerManager = {}
-- 服務
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 模組
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
-- 地圖變量
local lobbySpawn = workspace.Lobby.StartSpawn
local arenaMap = workspace.Arena
local spawnLocations = arenaMap.SpawnLocations
-- 值
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local playersLeft = displayValues:WaitForChild("PlayersLeft")
-- 玩家變量
local activePlayers = {}
local playerWeapon = ServerStorage.Weapon
local function checkPlayerCount()
if #activePlayers == 1 then
matchEnd:Fire(gameSettings.endStates.FoundWinner)
print("Found winner")
end
end
local function removeActivePlayer(player)
print("removing player")
for playerKey, whichPlayer in activePlayers do
if whichPlayer == player then
table.remove(activePlayers, playerKey)
playersLeft.Value = #activePlayers
checkPlayerCount()
end
end
end
local function respawnPlayerInLobby(player)
player.RespawnLocation = lobbySpawn
player:LoadCharacter()
end
local function preparePlayer(player, whichSpawn)
player.RespawnLocation = whichSpawn
player:LoadCharacter()
local character = player.Character or player.CharacterAdded:Wait()
-- 給玩家一個工具
local sword = playerWeapon:Clone()
sword.Parent = character
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
respawnPlayerInLobby(player)
removeActivePlayer(player)
end)
end
local function onPlayerJoin(player)
player.RespawnLocation = lobbySpawn
end
local function removePlayerWeapon(whichPlayer)
-- 檢查是否存在玩家,以防他們斷線或離開。
if whichPlayer then
local character = whichPlayer.Character
-- 如果玩家目前擁有它在他們的角色上
local weapon = character:FindFirstChild("Weapon")
if weapon then
weapon:Destroy()
end
-- 如果玩家在背包中擁有武器
local backpackWeapon = whichPlayer.Backpack:FindFirstChild("Weapon")
if backpackWeapon then
backpackWeapon:Destroy()
end
else
print("No player to remove weapon")
end
end
function PlayerManager.sendPlayersToMatch()
local availableSpawnPoints = spawnLocations:GetChildren()
for playerKey, whichPlayer in Players:GetPlayers() do
table.insert(activePlayers,whichPlayer)
-- 獲得生成位置,然後從表中移除它,以便下一位玩家獲得下一個生成
local spawnLocation = table.remove(availableSpawnPoints, 1)
preparePlayer(whichPlayer, spawnLocation)
end
playersLeft.Value = #activePlayers
end
function PlayerManager.getWinnerName()
local winningPlayer = activePlayers[1]
if winningPlayer then
return winningPlayer.Name
else
return "Error: No player found"
end
end
function PlayerManager.removeAllWeapons()
for playerKey, whichPlayer in activePlayers do
removePlayerWeapon(whichPlayer)
end
end
function PlayerManager.resetPlayers()
for playerKey, whichPlayer in activePlayers do
respawnPlayerInLobby(whichPlayer)
end
activePlayers = {}
end
-- 事件
Players.PlayerAdded:Connect(onPlayerJoin)
return PlayerManager