清理和重置

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

游戏的最后一阶段是清理和重置。在这个阶段中,代码确保游戏循环到中场休息,并且未来的每场比赛都会为每个玩家开始相同。

更新图形用户界面

在清理和重置之前,向玩家发布显示器管理器以显示适当状态。

获胜者名称

如果有一个胜利玩家的名字,请先获取其名字。 以前,代码会检查是否有玩家的活跃玩家表的大小已经减少 1 。 要获得剩余玩家的名字,请在该表的第一个索引中返回该名字。

  1. 在 PlayerManager 中,开始一个名为 getWinnerName() 的新模块功能。


    function PlayerManager.getWinnerName()
    end
    -- 事件
    Players.PlayerAdded:Connect(onPlayerJoin)
  2. activePlayers[1] 中添加一个 if 声明,该 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

获取端状态

使用模块函数从正确的端状态中获取信息,无论是否结束计时器或是否剩余一名玩家。然后,将该状态变量发送到显示管理器更新状态图形用户界面以显示状态。

  1. MatchManager 中,代码 a 新模块功能名为 getEndStatus() 与参数名为 endState 。要存储发送的消息,请添加一个空变量名为 1> statusToReturn1> 。


    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 和 else 语句设置 statusToReturn 的值。检查端状态变量: FoundWinnerTimerUp。为错误检查包括一个 else 在最结束。


    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 中获取更新公告,并将其显示给使用显示器的玩家。

  1. 打开 GameManager 。在此时,真的循环 删除 最后的打印声明。然后,创建一个名为 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() 。代码将从单个玩家的武器上移除 if 它是被动装备或在玩家的背包中。


    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 循环来通过 active 玩家表。在循环中,调用 removePlayerWeapon() 并通过发现的玩家传递。


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

在比赛之间清除

清理将是其自己的功能在 MatchManager 中。 为了现在,清理只会使用以前创建的函数来移除玩家武器。 随着游戏的扩展,更多可以添加,例如将在一场比匹配中更改的地图重置。

  1. 打开MatchManager。 添加一个名为 cleanupMatch() 的新模块功能。 在该功能中,调用 playerManager.removeAllWeapons()


    function MatchManager.cleanupMatch()
    playerManager.removeAllWeapons()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  2. 然后,调用清理函数。打开 GameManager 并找到 while true do loop。因此,玩家在结束中场休息时会有武器被移除。在最后的 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 循环,以在 activePlayers 上迭代。
    • 在循环中,调用 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. 打开 MatchManager。 编写一个名为 resetMatch() 的新模块功能,并调用 playerManager.resetPlayers()


    function MatchManager.resetMatch()
    playerManager.resetPlayers()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  4. 回到 游戏管理器 。在时间结束时,如果matchManager.resetMatch()为真,请调用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

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