清理和重置

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

是时候编写游戏最后阶段的代码:清理和重置。在这个阶段的代码确保游戏循环中断,以及未来的比赛对每个玩家都一样开始。

更新 GUI

在进行清理和重置之前,通过向玩家显示管理器显示适当的状态来告知玩家游戏结束的方式。

获取胜利者的名字

首先获取胜利玩家的名字,如果有一个。以前,代码检查了激活玩家表的大小是否降至 1。要获取剩余玩家的名称,返回该表的第一个索引的名称。

  1. 在 PlayerManager 中,启动名为 getWinnerName() 的新模块功能。


    function PlayerManager.getWinnerName()
    end
    -- 事件
    Players.PlayerAdded:Connect(onPlayerJoin)
  2. 添加一个如果声明,如果在 activePlayers[1] 中存在某些东西,将运行。虽然桌子数量在检查之前已检查,但玩家可能已断开或离开游戏。


    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. 匹配管理器 中,编写一个名为 getEndStatus() 的新模块函数,其参数名为 endState 。要存储将发送的消息,请添加一个名为 statusToReturn 的空变量。


    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 和 elseif 语句设置 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

显示和测试

在游戏管理器中获取更新公告,并将其显示给使用显示管理器的玩家。

  1. 打开 游戏管理器 。在 while 真实循环中, 删除 最后一句打印声明。然后,创建一个名为 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()。代码将移除激活装备或放入玩家背包的个人玩家的武器。


    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 循环通过活跃玩家表。在循环中,调用 removePlayerWeapon() 并传递找到的玩家。


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

在比赛之间清理

清理将在 MatchManager 中成为自己的函数。目前,清理将仅使用之前创建的函数来移除玩家武器。随着您扩展游戏,可以添加更多功能,例如在比赛期间更改的地图重置函数。

  1. 打开匹配管理器。添加一个名为 cleanupMatch() 的新模块函数。在该函数中,调用 playerManager.removeAllWeapons()


    function MatchManager.cleanupMatch()
    playerManager.removeAllWeapons()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  2. 接下来,调用清理函数。打开 游戏管理器 并找到 while 真正循环。因此,玩家在结束中场休息时移除武器,在最后 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 循环来遍历活跃的玩家。
    • 在循环中,调用 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. 打开匹配管理器。编写一个名为 resetMatch() 的新模块函数,并调用 playerManager.resetPlayers()


    function MatchManager.resetMatch()
    playerManager.resetPlayers()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  4. 返回到 游戏管理器 . 在 while 真实循环结束时,调用 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

匹配管理器脚本


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