結束比賽

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

比賽可以結束在幾個條件,包括計時器結束或單一玩家被剩下。

管理擊敗的玩家

目前,擊敗的玩家會在競技場重生。 相反,將他們發送回大廳等待下一場比相符。

  1. 在 PlayerManager 中,創建名為 respawnPlayerInLobby() 的本地函數。在該函數中,您必須做 следующее:
  • 將玩家的 RespawnLocation 設定為 лоббиSpawn。
  • 使用 Player:LoadCharacter() 重新載入角色。記住,LoadCharacter() 會在他們生成時重新創建玩家,並且移除任何他們擁有的工具。

使用匿名函數

匿名函數在特定情況下常常使用。在定義它們之前,重要的是要了解您的腳本可能遇到的情況。

考慮這個:要將擊敗的玩家傳送到大廳,傳送功能必須連接到玩家的死亡事件。 但有一個問題。 如果您連接過去的事件,就沒有辦法從死亡事件中獲取玩家的名稱。 此腳本需要這個名稱才能從桌子上跟蹤活動的玩家中移除一名擊敗的玩家。

要取得玩家啟動死亡事件的名稱,請使用匿名函數。 匿名函數 沒有名稱,可以直接在 Connect() 內創建。

以下是一個示範的匿名函數,它會顯示語法。


myPlayer.Died:Connect(function()
print(player)
end)

編寫死亡事件

對於此功能,每次玩家的角色死亡時,他們會啟動重生程式。

  1. 要取得玩家的死亡事件,在 PlayerManager > preparePlayer() 中,添加一個變數代表玩家的人形。


    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")
    end
  2. 建立一個匿名的函數,連接死亡事件。 開始時,輸入 humanoid.Died:Connect() 。 然後,在 內部 裡,輸入 Connect(),按下 1> 按Enter1> 自動完成 4> en結束4>,並刪除額外的括號。


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    end)
  3. 在匿名函數中,呼叫 respawnPlayerInLobby()。 通過 player ,變量存儲玩家準備進入一場相符。


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    end)
  4. 開始一個 伺服器 並進行一場相符。測試玩家死亡時會在大廳重生。要擊敗玩家,請走到他們身邊並使用您的武器直到您確認他們在大廳重生。

    攻擊玩家 2
    重生後的玩家2在大廳中

注意,也有一些想要的測試方式。

  • 要擊殺玩家,在服務器 > 輸出窗口 > 指令條中,複製並粘貼: workspace.Player1.Humanoid.Health = 0。按下 輸入 以執行指令。要移除其他玩家,請使用 Player2、Player3、等等。
  • 將 GameSettings > matchDuration 設置為更長時間可以給你更多時間來尋找並擊殺所有玩家。
  • 要進行更快的測試,請將 GameSettings > minimumPlayers 變更為較小的數字,例如 2。

結束遊戲

擊敗玩家重生後,開始努力結束遊戲。記得創建「結束遊戲」事件嗎?它會在計時器結束或找到勝利者時被發射。

要告訴其他腳本哪一個條件結束了遊戲,請創建一個包含變數為 TimerUpFoundWinner 的表。當發生比賽結束事件時,它會傳入一個變數,以便其他腳本可以回應。

  1. 在GameSettings中,創建名為 endStates 的模組表。


    local GameSettings = {}
    -- 遊戲變量
    GameSettings.intermissionDuration = 5
    GameSettings.matchDuration = 10
    GameSettings.minimumPlayers = 2
    GameSettings.transitionTime = 5
    -- 可能發生的遊戲結束方式。
    GameSettings.endStates = {
    }
    return GameSettings
  2. 創建兩個名為 TimerUpFoundWinner 的變數。將每個變數設置為與名稱相匹配的字串。這些字串將用於測試代碼。


GameSettings.endStates = {
TimerUp = "TimerUp",
FoundWinner = "FoundWinner"
}

結束時計時器

當計時器結束時,發射匹配結束事件並傳送相應的結束狀態變量。這樣,其他聽到該事件的聽觀者可以相應地回應。記住,當事件發出信號時,也可以傳送受到聽觀者聽取的資料,例如 TimerUpFoundWinner

  1. GameManager 中,在 while 真的循環中,找到行 matchEnd.Event:Wait() 。在線路的開始,添加 local 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()
    end
  2. 要確認正確狀態已收到,請包含 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()
    print("Game ended with: " .. endState)
    end
  3. 在 MatchManager 中,找到 timeUp()remove 打印語句。然後,要發射結束比賽的事件,請輸入 matchEnd:Fire() 並在 1> gameSettings.endSettings.timerUp1> 中傳入。


    -- 值
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local timeLeft = displayValues:WaitForChild("TimeLeft")
    -- 建立一個新的計時器對象,可用來跟蹤比賽時間。
    local myTimer = timer.new()
    -- 本地函數
    local function timeUp()
    matchEnd:Fire(gameSettings.endStates.TimerUp)
    end
  4. 測試一個匹相符。一旦計時器結束,請確認打印語句包含 TimerUp 變量中儲存的字串。

排障提示

此時訊息未顯示,請從以下列中嘗試。

  • 檢查任何端狀變量的所在位置,它們是否正確寫入,例如: gameSettings.endStates.TimerUp
  • 請務必使用 : ( colon 操作器) 與 Fire() 以代替 點操作器,如在 matchEnd:Fire() 中。

編寫獲勝比賽

然後,該指令碼需要識別勝利玩家,移除失敗玩家,並執行清理,例如停止計時器。比賽將也會結束,如果一個玩家被剩下。要查看是否達到 FoundWinner 狀態,你需要一個查看表中跟蹤玩家數的函數。

檢查玩家數量

如果只剩下一名玩家,則比賽將會結束。若要檢查此情況,請使用跟蹤指令將玩家跟蹤在一回合中。一旦有一名玩家被淘汰,就可以分配勝利。

  1. 在 PlayerManager 中,定義以下變量:

    • ModuleScripts 資料夾
    • GameSettings 模組 - 用於存取結束狀態變量
    • 事件資料夾和 MatchEnd 事件:發射事件

    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")
  2. 在 respawnPlayerInLobby() 以上,添加名為 checkPlayerCount 的新本地功能。


    -- 玩家變數
    local activePlayers = {}
    local playerWeapon = ServerStorage.Weapon
    local function checkPlayerCount()
    end
    local function respawnPlayerInLobby(player)
  3. 在該函數內,使用 if 然後的語句來檢查獲勝者。在該語句中:

    • 檢查 activePlayers 桌子的大小。
    • 如果是,請發射 matchEnd 並在 gameSettings.endStates.FoundWinner

    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end

移除玩家

除非玩家被移除,否則不能保持準確的伺服器統計。當玩家被擊敗時,通過將他們從玩家桌中移除來保持準確的玩家統計。然後,檢查啟用的玩家桌子大小來確認是否有勝利。

  1. checkPlayerCount() 下,創建名為 removeActivePlayer() 的新本地函數,並且將 player 參數命名為。


    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end
    local function removeActivePlayer(player)
    end
  2. 要在 activePlayers 桌子中找到玩家,請使用 for 循環來它。然後,添加一個 if 聲明,該聲明會在玩家與名稱一致的玩家被找到時執行。


    local function removeActivePlayer(player)
    for playerKey, whichPlayer in activePlayers do
    if whichPlayer == player then
    end
    end
    end
  3. 要移除玩家,在 if 句中:

    • 调用 table.remove() 。在括號內,通過 activePlayers 、表來看,和 playerKey - 玩家從桌子上移除。
    • playersLeft 對象的值設為 #activePlayers
    • 使用 checkPlayerCount() 檢查獲勝玩家。

    local function removeActivePlayer(player)
    for playerKey, whichPlayer in activePlayers do
    if whichPlayer == player then
    table.remove(activePlayers, playerKey)
    playersLeft.Value = #activePlayers
    checkPlayerCount()
    end
    end
    end

連接事件和測試

要使用剛剛創建的函數,請從玩家的 Died 事件連接到隱藏的函數中呼叫。

  1. preparePlayer() 的基準上找到 removeActivePlayer() 。在 Died 事件連接的匿名函數中,呼叫 RemoveActivePlayer 。然後,將玩家作為參數傳入。


    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    removeActivePlayer(player)
    end)
  2. 要確認有贏家玩家是否存在,請開始一個 測試服務器 。當有只有一個玩家剩下時,您應該在輸出窗口中看到 FoundWinner。

  3. 繼續測試並讓比賽結束。注意新比賽開始時,會在輸出視窗中出現一個錯誤:

此錯誤是因為計時器沒有停止,這將在下一部分中解決。

停止計時器

當匹配結束時,勝利玩家時,計時器也應該停止。 要在時間到達時停止計時器,請在每次比賽結束時發生時,讓計時器停止。這是創建事件的一些好處。它們可以在多個情況下重用。

  1. 在 MatchManager 中,創建名為 stopTimer() 的新本地函數。內部輸入 myTimer:stop() 來停止計時器。


    -- 建立一個新的計時器對象,可用來跟蹤比賽時間。
    local myTimer = timer.new()
    -- 本地函數
    local function stopTimer()
    myTimer:stop()
    end
    local function timeUp()
    matchEnd:Fire(gameSettings.endStates.TimerUp)
    end
  2. 要停止計時器結束時,連接「停止時間」事件到 stopTimer()


    -- 模組功能
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    matchStart:Fire()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  3. 測試 發生以前的錯誤不再顯示啟動 伺服器 。移除所有玩家,然後等待一些秒鐘,一旦比賽結束。

下一步

兩個獲勝條件完成後,還剩下一些任務需要完成遊戲循環。例個體、實例,獲勝玩家不會被傳送到大廳。在下一個課題中,您將顯示比賽結束於玩家的方式,並重設遊戲,最終完成整個循環。

已完成的指令碼

下面是完成審核您的工作的指令碼。

PlayerManager 指令碼


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)
end
end
local function removeActivePlayer(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 onPlayerJoin(player)
player.RespawnLocation = lobbySpawn
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
-- 模組功能
function PlayerManager.sendPlayersToMatch()
local arenaSpawns = spawnLocations:GetChildren()
for playerKey, whichPlayer in Players:GetPlayers() do
table.insert(activePlayers, whichPlayer)
local spawnLocation = table.remove(arenaSpawns, 1)
preparePlayer(whichPlayer, spawnLocation)
end
playersLeft.Value = #activePlayers
end
-- 事件
Players.PlayerAdded:Connect(onPlayerJoin)
return PlayerManager

GameSettings 指令碼


local GameSettings = {}
-- 遊戲變量
GameSettings.intermissionDuration = 5
GameSettings.matchDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.transitionTime = 5
-- 可能發生的遊戲結束方式。
GameSettings.endStates = {
TimerUp = "TimerUp",
FoundWinner = "FoundWinner"
}
return GameSettings

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 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()
print("Game ended with: " .. endState)
end

MatchManager 指令碼


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 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()
print("Timer started")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
while myTimer:isRunning() do
-- 將 +1 添加到螢幕的計時器顯示為 1 而不是 0。
timeLeft.Value = (math.floor(myTimer:getTimeLeft() + 1))
-- 通過未設定等待時間,它提供更準確的重複
task.wait()
end
end
-- 模組功能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager