是时候编写游戏最后阶段的代码:清理和重置。在这个阶段的代码确保游戏循环中断,以及未来的比赛对每个玩家都一样开始。
更新 GUI
在进行清理和重置之前,通过向玩家显示管理器显示适当的状态来告知玩家游戏结束的方式。
获取胜利者的名字
首先获取胜利玩家的名字,如果有一个。以前,代码检查了激活玩家表的大小是否降至 1。要获取剩余玩家的名称,返回该表的第一个索引的名称。
在 PlayerManager 中,启动名为 getWinnerName() 的新模块功能。
function PlayerManager.getWinnerName()end-- 事件Players.PlayerAdded:Connect(onPlayerJoin)添加一个如果声明,如果在 activePlayers[1] 中存在某些东西,将运行。虽然桌子数量在检查之前已检查,但玩家可能已断开或离开游戏。
function PlayerManager.getWinnerName()local winningPlayer = activePlayers[1]if winningPlayer thenendend在 if 声明中:
- 返回玩家的名称。
- 对于其他,返回一个错误字符串。
function PlayerManager.getWinnerName()local winningPlayer = activePlayers[1]if winningPlayer thenreturn winningPlayer.Nameelsereturn "Error: No winning player found"endend
获取最终状态
使用模块函数从正确的终端状态获取信息,无论是计时器结束还是一个玩家被留下。然后,将那个状态变量发送到显示管理器,以更新状态图形用户界面,发送适当的消息。
在 匹配管理器 中,编写一个名为 getEndStatus() 的新模块函数,其参数名为 endState 。要存储将发送的消息,请添加一个名为 statusToReturn 的空变量。
function MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endfunction MatchManager.getEndStatus(endState)local statusToReturnendmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManager使用 if 和 elseif 语句设置 statusToReturn 的值。检查结束状态变量:FoundWinner和TimerUp。对于错误检查,在结尾包含另一个 else。
function MatchManager.getEndStatus(endState)local statusToReturnif endState == gameSettings.endStates.FoundWinner thenelseif endState == gameSettings.endStates.TimerUp thenelseendend为每个条件添加以下内容:
FoundWinner
- 使用 playerManager.getWinnerName() 的胜利者变量。
- 用带有胜利者宣布的字符串更新 statusToReturn 。
TimerUp
- 用一个宣布时间已过的字符串更新 statusToReturn 。
Else
- 在获取最终游戏消息时出现问题的情况下,更新 statusToReturn 以发送错误消息。
function MatchManager.getEndStatus(endState)local statusToReturnif endState == gameSettings.endStates.FoundWinner thenlocal winnerName = playerManager.getWinnerName()statusToReturn = "Winner is : " .. winnerNameelseif endState == gameSettings.endStates.TimerUp thenstatusToReturn = "Time ran out!"elsestatusToReturn = "Error found"endend通过输入 return statusToReturn 发送回消息。
function MatchManager.getEndStatus(endState)local statusToReturnif endState == gameSettings.endStates.FoundWinner thenlocal winnerName = playerManager.getWinnerName()statusToReturn = "Winner is : " .. winnerNameelseif endState == gameSettings.endStates.TimerUp thenstatusToReturn = "Time ran out!"elsestatusToReturn = "Error found"endreturn statusToReturnend
显示和测试
在游戏管理器中获取更新公告,并将其显示给使用显示管理器的玩家。
打开 游戏管理器 。在 while 真实循环中, 删除 最后一句打印声明。然后,创建一个名为 endStatus 的变量。将其设置为调用 matchManager.getEndStatus(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()local endStatus = matchManager.getEndStatus(endState)end要在 GUI 标签中显示返回的消息,请调用 displayManager.updateStatus() 并传递 endStatus 。
local endStatus = matchManager.getEndStatus(endState)displayManager.updateStatus(endStatus)因此,游戏暂停以让玩家看到消息,添加使用 transitionTime 的等待。
local endStatus = matchManager.getEndStatus(endState)displayManager.updateStatus(endStatus)task.wait(gameSettings.transitionTime)启动一个 测试服务器 并检查玩家是否看到以下消息,用于倒计时和获胜玩家条件。
时间到条件 获胜玩家条件
排除问题的提示
在这一点上,您无法看到消息,请尝试以下方法之一。
- 如果你的终端状态消息是“错误发现”,没有任何条件成功。检查 MatchManager.getEndStatus() 对代码样本的代码与代码样本对比。
- 如果最终状态未显示,请检查 task.wait(gameSettings.transitionTime) 是否在向显示管理器发送消息后显示。
开始新的比赛
在开始新比赛之前,将发生短暂的过渡。这给玩家留时间查看最终状态,使被传送到大厅的感觉变得更平缓。
在转换结束时,剩余的玩家将被从竞技场中移除,所有代码都将重置。这确保玩家将开始下一场比赛时使用游戏的清洁版本。
处理过渡
当玩家进入过渡状态时,移除他们的武器。
在 PlayerManager 中,找到本地函数。复制并粘贴下面突出显示的代码 removePlayerWeapon()。代码将移除激活装备或放入玩家背包的个人玩家的武器。
local function removePlayerWeapon(whichPlayer)-- 检查是否存在玩家,以防他们断开或离开。if whichPlayer thenlocal character = whichPlayer.Character-- 如果玩家目前拥有它在他们的角色上local weapon = character:FindFirstChild("Weapon")if weapon thenweapon:Destroy()end-- 如果玩家在背包中拥有武器local backpackWeapon = whichPlayer.Backpack:FindFirstChild("Weapon")if backpackWeapon thenbackpackWeapon:Destroy()endelseprint("No player to remove weapon")endend启动一个名为 removeAllWeapons() 的新模块功能。
function PlayerManager.removeAllWeapons()end-- 事件Players.PlayerAdded:Connect(onPlayerJoin)return PlayerManager在那个函数中,使用 for 循环通过活跃玩家表。在循环中,调用 removePlayerWeapon() 并传递找到的玩家。
function PlayerManager.removeAllWeapons()for playerKey, whichPlayer in activePlayers doremovePlayerWeapon(whichPlayer)endend
在比赛之间清理
清理将在 MatchManager 中成为自己的函数。目前,清理将仅使用之前创建的函数来移除玩家武器。随着您扩展游戏,可以添加更多功能,例如在比赛期间更改的地图重置函数。
打开匹配管理器。添加一个名为 cleanupMatch() 的新模块函数。在该函数中,调用 playerManager.removeAllWeapons() 。
function MatchManager.cleanupMatch()playerManager.removeAllWeapons()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManager接下来,调用清理函数。打开 游戏管理器 并找到 while 真正循环。因此,玩家在结束中场休息时移除武器,在最后 matchManager.cleanupMatch() 之前调用 task.wait() .
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()local endStatus = matchManager.getEndStatus(endState)displayManager.updateStatus(endStatus)matchManager.cleanupMatch()task.wait(gameSettings.transitionTime)end启动测试服务器并进行匹配。等待计时器耗尽,确认玩家的武器在游戏结束期间被移除。
在比赛期间 比赛结束后
重置匹配
你可能还注意到了游戏中的一些其他事情,比如玩家在比赛结束后仍然留在竞技场。与匹配清理后,下次重置游戏。这包括将在竞技场中的玩家发送回大厅以及清理活跃玩家表。在位置重置的情况下,游戏循环可以无限期运行。
首先,启动一个函数将玩家发送回大厅。
在 PlayerManager 中:
- 创建一个名为 resetPlayers() 的模块函数。
- 添加一个 for 循环来遍历活跃的玩家。
- 在循环中,调用 respawnPlayerInLobby() 并将玩家传递为参数。
function PlayerManager.resetPlayers()for playerKey, whichPlayer in activePlayers dorespawnPlayerInLobby(whichPlayer)endend-- 事件Players.PlayerAdded:Connect(onPlayerJoin)return PlayerManager确保下一场比赛的 activePlayers 表是空的,通过将其设置为 {} 来重置为空的表,这是一种快速的方法。
function PlayerManager.resetPlayers()for playerKey, whichPlayer in activePlayers dorespawnPlayerInLobby(whichPlayer)endactivePlayers = {}end打开匹配管理器。编写一个名为 resetMatch() 的新模块函数,并调用 playerManager.resetPlayers() 。
function MatchManager.resetMatch()playerManager.resetPlayers()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManager返回到 游戏管理器 . 在 while 真实循环结束时,调用 matchManager.resetMatch() .
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()local endStatus = matchManager.getEndStatus(endState)displayManager.updateStatus(endStatus)matchManager.cleanupMatch()task.wait(gameSettings.transitionTime)matchManager.resetMatch()end启动测试服务器并进行匹配。确认您至少可以通过两个游戏循环而不出现任何错误。
已完成的脚本
以下是完成的脚本来检查您的工作。
游戏管理器脚本
-- 服务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()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