游戏的最后一阶段是清理和重置。在这个阶段中,代码确保游戏循环到中场休息,并且未来的每场比赛都会为每个玩家开始相同。
更新图形用户界面
在清理和重置之前,向玩家发布显示器管理器以显示适当状态。
获胜者名称
如果有一个胜利玩家的名字,请先获取其名字。 以前,代码会检查是否有玩家的活跃玩家表的大小已经减少 1 。 要获得剩余玩家的名字,请在该表的第一个索引中返回该名字。
在 PlayerManager 中,开始一个名为 getWinnerName() 的新模块功能。
function PlayerManager.getWinnerName()end-- 事件Players.PlayerAdded:Connect(onPlayerJoin)在 activePlayers[1] 中添加一个 if 声明,该 if 声明可以运行,如果在表中检查时发生错误,玩家可能已经断开或离开游戏。
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
获取端状态
使用模块函数从正确的端状态中获取信息,无论是否结束计时器或是否剩余一名玩家。然后,将该状态变量发送到显示管理器更新状态图形用户界面以显示状态。
在 MatchManager 中,代码 a 新模块功能名为 getEndStatus() 与参数名为 endState 。要存储发送的消息,请添加一个空变量名为 1> statusToReturn1> 。
function MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endfunction MatchManager.getEndStatus(endState)local statusToReturnendmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManager使用 if 和 else 语句设置 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
显示和测试
在 GameManager 中获取更新公告,并将其显示给使用显示器的玩家。
打开 GameManager 。在此时,真的循环 删除 最后的打印声明。然后,创建一个名为 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() 。代码将从单个玩家的武器上移除 if 它是被动装备或在玩家的背包中。
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 循环来通过 active 玩家表。在循环中,调用 removePlayerWeapon() 并通过发现的玩家传递。
function PlayerManager.removeAllWeapons()for playerKey, whichPlayer in activePlayers doremovePlayerWeapon(whichPlayer)endend
在比赛之间清除
清理将是其自己的功能在 MatchManager 中。 为了现在,清理只会使用以前创建的函数来移除玩家武器。 随着游戏的扩展,更多可以添加,例如将在一场比匹配中更改的地图重置。
打开MatchManager。 添加一个名为 cleanupMatch() 的新模块功能。 在该功能中,调用 playerManager.removeAllWeapons() 。
function MatchManager.cleanupMatch()playerManager.removeAllWeapons()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManager然后,调用清理函数。打开 GameManager 并找到 while true do loop。因此,玩家在结束中场休息时会有武器被移除。在最后的 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 循环,以在 activePlayers 上迭代。
- 在循环中,调用 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打开 MatchManager。 编写一个名为 resetMatch() 的新模块功能,并调用 playerManager.resetPlayers()。
function MatchManager.resetMatch()playerManager.resetPlayers()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManager回到 游戏管理器 。在时间结束时,如果matchManager.resetMatch()为真,请调用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
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 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 = (math.floor(myTimer:getTimeLeft() + 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
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)
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