對局可以在時間到或單一玩家被拋棄的幾種條件中結束。
管理擊敗的玩家
目前,被擊敗的玩家在競技場重生。相反,將他們送回大廳等待下一場比相符。
- 在 PlayerManager 中,創建名為 respawnPlayerInLobby() 的本地函數。在該函數中,執行以追蹤中操作:
- 將玩家的重生位置屬性設為 lobbySpawn。
- 使用 Player:LoadCharacter() 重新載入角色。記住,LoadCharacter() 會在玩家生成時創建他們,移除任何他們擁有的工具。
使用匿名函數
匿名函數在特定情況下通常會在進階腳本中使用。在定義它們之前,了解您的腳本可能遇到的情況是很重要的。
考慮這個:要將被擊敗的玩家傳送到大廳,重生功能必須連接到玩家死亡事件。不過有一個問題。如果您以過往的方式連接事件,就無法從死亡事件中獲得玩家的名稱。腳本需要那個名稱來從跟蹤活動玩家的表中移除被擊敗的玩家。
若要取得啟動死亡事件的玩家名稱,請使用匿名函數。 匿名功能 沒有名稱,可以直接在Connect(),而不是獨立創建。
下面是一個示例匿名函數,顯示了語法。
myPlayer.Died:Connect(function()
print(player)
end)
編寫死亡事件
對於這個功能,每當玩家的角色死亡時,它們都會觸發重生他們的功能。
若要存取玩家的死亡事件,請在 PlayerManager > preparePlayer() 中新增一個變量,用於玩家的人形。
local function preparePlayer(player, whichSpawn)player.RespawnLocation = whichSpawnplayer:LoadCharacter()local character = player.Character or player.CharacterAdded:Wait()local sword = playerWeapon:Clone()sword.Parent = characterlocal humanoid = character:WaitForChild("Humanoid")end創建一個匿名函數,連接到死亡事件。開始輸入 humanoid.Died:Connect() 。然後, 內部 Connect() , 輸入 function() , 按下 Enter 以自動完成 end , 並刪除額外的括號。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()end)在匿名函數中,呼叫 respawnPlayerInLobby() 。傳入 player ,一個變量存儲玩家準備進入相符賽的變量。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()respawnPlayerInLobby(player)end)啟動一個 伺服器 並進行比相符。測試玩家死亡時會在大廳重生。要擊敗玩家,走到他們身邊並使用你的武器,直到你確認他們在大廳重生為止。
攻擊玩家2 重生後的大廳中玩家2
注意,如果需要,也可以使用不同的測試方式。
- 要殺死一名玩家,在伺服器 > 輸出窗口 > 指令欄中,複製並貼上:workspace.Player1.Humanoid.Health = 0。按下 Enter 以執行指令。要移除其他玩家,請使用 Player2、Player3 等。
- 將「遊戲設定」matchDuration設置為更長時間,可以給你更多時間來找到並取出所有玩家。
- 若要進行更快的測試,請將「遊戲設定」變更為小於 2 的數字,例如 2。
结束游遊戲
現在擊敗的玩家重生了,開始工作以結束遊戲。記得創建了「比賽結束」事件嗎?當計時器到期或找到勝利者時,它將被發射。
要告訴其他腳本哪一個條件結束了遊戲,創建一個包含變量 TimerUp 和 FoundWinner 的表。當匹配結束事件發生時,會傳送變量給其他腳本,以便它們回應。
在遊戲設定中,創建一個名為 endStates 的空模組表。
local GameSettings = {}-- 游戲變量GameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- 遊戲可能結束的方式。GameSettings.endStates = {}return GameSettings創建兩個變量名為 TimerUp 和 FoundWinner 的變量。將每個變量設為與名稱匹配的字串。這些字串將用於測試代碼。
GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}
以定時器結束
當計時器結束時,發射匹配結束事件並傳送匹配的結束狀態變量。這樣,其他聆聽該事件的腳本可以適當回應。請記住,當事件發射信號時,也可以傳送收到的資料,例如 TimerUp 或 FoundWinner 。
在 遊戲管理器 中,在 while 真實循環期間,找到線 matchEnd.Event:Wait() 。在線的開頭添加 local endState = 。
while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()end要確認收到正確狀態,請添加包含 endState 的列印聲明。
while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()print("Game ended with: " .. endState)end在匹配管理器中,找到 timeUp() 並 移除 列印聲明。然後,要發射匹配結束事件,請輸入 matchEnd:Fire() 並傳入 gameSettings.endStates.TimerUp 。
-- 值local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")local timeLeft = displayValues:WaitForChild("TimeLeft")-- 創建一個新的計時器對象,用於跟蹤比賽時間。local myTimer = timer.new()-- 本地功能local function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)end測試一個相符。一旦計時器耗盡,請檢查打印聲明包含在 TimerUp 變量中的字串。
排除故障提示
在這個時候,訊息未顯示,請嘗試以下其中一項。
- 檢查終狀態變量在任何地方被呼叫時,是否正確寫入,如下:gameSettings.endStates.TimerUp。
編寫勝利的相符
接下來,腳本需要識別勝利玩家、移除失敗玩家,並執行清理操作,例如停止計時器。如果一名玩家被淘汰,對戰也會結束。若要查看是否滿足 FoundWinner 條件,你需要一個檢查比相符中跟蹤玩家的表中剩餘數量的函數。
檢查玩家數量
如果只剩下一名玩家,對戰就會結束。要檢查這一點,腳本需要跟蹤玩家在一輪中。一旦一名玩家被淘汰,就可以指定一名勝利者。
在 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")上面的 respawnPlayerInLobby() , 添加一個新的本地功能名稱為 checkPlayerCount() 的。
-- 玩家變量local activePlayers = {}local playerWeapon = ServerStorage.Weaponlocal function checkPlayerCount()endlocal function respawnPlayerInLobby(player)在該功能中,使用 if 然後指令來檢查獲勝者。在該聲明中:
- 檢查 activePlayers 表的大小是否為 1。
- 如果是,發射 matchEnd 並傳入 gameSettings.endStates.FoundWinner 。
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
移除一名玩家
除非玩家被移除,否則無法保持準確的數量。當玩家被擊敗時,請從玩家表中移除他們,以保持準確的玩家數量。然後,檢查活動玩家表的大小,看看有沒有勝利者。
在 checkPlayerCount() 下,創建一個新的本地函數名為 removeActivePlayer() 的參數名為 player 的參數。
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endendlocal function removeActivePlayer(player)end要在 activePlayers 表中找到玩家,使用 for 循環進行循環。然後,添加一個 if 聲明,如果找到匹配名稱的玩家進入函數,就會執行。
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thenendendend要移除玩家,在 if 聲明中:
- 將 playersLeft 對象的值設為 #activePlayers 。
- 透過執行 checkPlayerCount() 來檢查獲勝玩家。
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thentable.remove(activePlayers, playerKey)playersLeft.Value = #activePlayerscheckPlayerCount()endendend
連接事件和測試
若要使用剛剛創建的功能,請從匿名函數中呼叫它,連接到玩家的 Died 事件。
尋找 preparePlayer() 。在死亡事件連線的匿名函數中,呼叫 removeActivePlayer() 。然後,將玩家傳送為參數。
humanoid.Died:Connect(function()respawnPlayerInLobby(player)removeActivePlayer(player)end)要查看是否找到勝利玩家,請啟動 測試伺服器 。當只剩下一名玩家時,您應該在輸出窗口中看到 FoundWinner。
繼續測試並讓比賽結束。當新比賽開始時,輸出窗口會出現錯誤:
這個錯誤是因為定時器沒有停止,這將在下一個部分中修正。
停止計時器
每當比賽以勝利玩家結束時,計時器也應停止。若要在時間到之停止計時器,在匹配結束事件發生時讓計時器停止。這是創建事件的好處之一。它們可以在多種情況下重複使用,以撰寫原因和效果關係。
在 MatchManager 中,創建一個新的本地函數名為 stopTimer() 。內部,輸入 myTimer:stop() 來停止計時器。
-- 創建一個新的計時器對象,用於跟蹤比賽時間。local myTimer = timer.new()-- 本地功能local function stopTimer()myTimer:stop()endlocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)end要停止計時器在比賽結束時,連接 matchEnd 事件到 stopTimer() 。
-- 模組功能function MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endmatchStart.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)
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 = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- 遊戲可能結束的方式。GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}return GameSettings
遊戲管理員指令碼
-- 服務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 dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()print("Game ended with: " .. endState)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 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 = (myTimer:getTimeLeft() + 1) // 1
-- 通過不設置等待時間,它提供更準確的循環
task.wait()
end
end
-- 模組功能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager