结束比赛

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

匹配可以在几个条件下结束,包括计时器结束或单个玩家被离开。

管理败场玩家

现在,击败的玩家会在竞技场重生。 相反,将他们发送回大厅等待下一场比匹配。

  1. 在 PlayerManager 中,创建一个名为 respawnPlayerInLobby() 的本地函数。在该函数中,您需要完成以关注中/正在关注操作:
  • 将玩家的 RespawnLocation 设置为 лобSpawn。
  • 使用 Player:LoadCharacter() 重新加载角色。 记住, LoadCharacter() 在他们的重生点中重新创建玩家,并移除他们所有的工具。

使用匿名函数

匿名函数在特定情况下下常用于高级脚本。在定义它们之前,重要的是要了解您的脚本可能遇到的情况。

考虑这个:要将击败的玩家传送到大厅,重生功能必须连接到玩家的 Died 事件。 但有一个问题。 如果您将过去的事件连接到我们的脚本,就无法从 Died 事件中获取玩家的名称。 脚本需要这个名称才能从跟踪活跃玩家的桌子上移除一名击败的玩家。

要获取 Died 事件触发者的玩家名称,请使用匿名函数。 匿名函数 没有名称,可以直接在 Connect() 中创建,而不是单独。

以下是一个示例的匿名函数,它显示了语法。


myPlayer.Died:Connect(function()
print(player)
end)

编写死亡事件

对于此功能,每当玩家的角色死亡时,他们会触发该角色重生的函数。

  1. 要获得玩家的 Died 事件,在 PlayerManager > preparePlayer() 中,添加一个变量来代表玩家的人形。


    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")
    end
  2. 创建一个匿名函数,连接到死亡事件。首先,输入 humanoid.Died:Connect()。然后,在 Connect() ,输入 1> function()1>,然后按 4> 进入4> 自动完成 7> end7>,然后删除额外的父号。


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    end)
  3. 在匿名函数中,调用 respawnPlayerInLobby()。 通过 player ,变量存储玩家准备进入比匹配。


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    end)
  4. 开始一个 服务器 并播放一场匹配。测试玩家死亡时是否在大厅重生。要击败玩家,请走到他们旁边并使用您的武器直到您确认他们在大厅重生。

    攻击玩家 2
    在重生后的大厅玩家 2

注意,如果需要,还有一些不同的测试方法。

  • 要杀死玩家,在服务器 > 输出窗口 > 命令栏中,复制并粘贴: workspace.Player1.Humanoid.Health = 0 . 按下 输入 来运行命令。要移除其他玩家,请使用 Player2、Player3、等等。
  • 将 GameSettings > matchDuration 设置为更长时间可以让你更有时间找到并淘汰所有玩家。
  • 为了更快地测试,请将 GameSettings > minimumPlayers 改为较小的数字,例如 2。

结束游戏

现在击败的玩家重生,开始工作以结束游戏。记得创建“MatchEnd”事件?它将被触发,当时间器结束或获胜者被找到时。

要告诉其他脚本哪个条件结束了游戏,请创建一个包含 TimerUpFoundWinner 的变量的表。当发生匹配结束事件时,它将以变量的形式传递给其他脚本,以便其他脚本可以回应。

  1. 在GameSettings中,创建一个名为 endStates 的空模块表。


    local GameSettings = {}
    -- 游戏变量
    GameSettings.intermissionDuration = 5
    GameSettings.matchDuration = 10
    GameSettings.minimumPlayers = 2
    GameSettings.transitionTime = 5
    -- 可能的游戏结束方式。
    GameSettings.endStates = {
    }
    return GameSettings
  2. 创建两个变量名为 TimerUpFoundWinner 。将每个变量设置为与其名称匹配的字符串。这些字符串将用于测试代验证码。


GameSettings.endStates = {
TimerUp = "TimerUp",
FoundWinner = "FoundWinner"
}

结束倒计时

当计时器结束时,发射匹配结束事件,并将匹配结束状态变量发送给对应的结束状态变量。这样,其他听到该事件的脚本就可以根据情况发送相应的数据。请注意,当事件发出信号时,也可以发送受到的数据,例如 TimerUpFoundWinner

  1. GameManager 中,在 while 真的循环中,找到线 matchEnd.Event:Wait() . 在线的开始添加 local 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()
    end
  2. 要确认正确的状态已收到,请包含 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()
    print("Game ended with: " .. endState)
    end
  3. 在 MatchManager 中,找到 timeUp()remove 打印声明。然后,要发射匹配结束事件,请输入 matchEnd:Fire() 并通过 1> gameSettings.endStates.TimerUp1> 传递。


    -- 值
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local timeLeft = displayValues:WaitForChild("TimeLeft")
    -- 创建一个新的计时器对象来跟踪匹配时间。
    local myTimer = timer.new()
    -- 本地函数
    local function timeUp()
    matchEnd:Fire(gameSettings.endStates.TimerUp)
    end
  4. 测试一个匹配。一旦计时器结束,请检查打印声明包含存储在 TimerUp 变量中的字符串。

排查提示

在此时,消息未显示,请尝试以下一种。

  • 检查端状态变量的所在位置,它们是否正确写入,例如: gameSettings.endStates.TimerUp
  • 请确保使用 : ( colon operator) 与 Fire() 而不是 dot operator,如在 matchEnd:Fire() 中。

编写胜利的比赛

然后,脚本需要识别赢家玩家,移除失败的玩家,并且运行清理,例如停止计时器。比赛也会结束,如果一个玩家被离开。要确定 FoundWinner 条件是否满足,您需要检查表中跟踪玩家的数量。要查看是否满足 FindWinner 条件,您需要一个函数来检查表中跟踪玩家的数量。

检查玩家数量

如果只剩下一个玩家,匹配将会结束。为了检查这个,脚本需要跟踪玩家在一轮中。当一个玩家被剩下时,赢家可以被分配。

  1. 在 PlayerManager 中,定义以下变量:

    • 模块脚本文件夹
    • 游戏设置模块 - 用于访问端状态变量
    • 事件文件夹和 MatchEnd 事件 - 发射事件

    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")
  2. respawnPlayerInLobby() 上,添加一个名为 checkPlayerCount() 的新本地函数。


    -- 玩家变量
    local activePlayers = {}
    local playerWeapon = ServerStorage.Weapon
    local function checkPlayerCount()
    end
    local function respawnPlayerInLobby(player)
  3. 在该函数中,使用一个 if 然后声明来检查是否有胜利者。在该声明中:

    • 检查 activePlayers 表的大小。
    • 如果是这样,请发射 matchEnd 并通过 gameSettings.endStates.FoundWinner

    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end

移除玩家

精确的帐户必须保持准确,除非玩家被移除。当玩家被击败时,通过将其从玩家表中移除来保持准确的玩家帐户。然后,检查激活玩家桌子的大小来确定是否有胜利。

  1. checkPlayerCount() 下,创建一个名为 removeActivePlayer() 的新本地函数,并在参数上命名为 player


    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end
    local function removeActivePlayer(player)
    end
  2. 要找到 activePlayers 表中的玩家,请使用一个 for 循环。然后,添加一个 if 声明,该运行 if 玩家匹配名称到达到 function 。


    local function removeActivePlayer(player)
    for playerKey, whichPlayer in activePlayers do
    if whichPlayer == player then
    end
    end
    end
  3. 要将玩家移除,在 if 声明中:

    • 调用 table.remove() 。 在父亲的括号内,通过 activePlayers 、表看起来,并通过 playerKey - 玩家从表中移除。
    • playersLeft 对象的值设置为 #activePlayers
    • 使用 checkPlayerCount() 来检查获胜玩家。

    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

连接事件和测试

要使用刚刚创建的函数,请从玩家的 Died 事件中调用它。

  1. 找到 preparePlayer() 。在匿名函数中,调用 removeActivePlayer() 。然后,将其作为参数传递给玩家。


    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    removeActivePlayer(player)
    end)
  2. 要确定有赢家玩家是否存在,请开始一个 测试服务器 。当只剩下一个玩家时,您应该在输出窗口中看到找到赢家。

  3. 继续测试,让比赛结束。 注意,新的比赛开始时,出力窗口中出现错误:

此错误是因为计时器未停止,将在下一节中解决。

停止计时器

当匹配结束时,胜利玩家时,计时器应该停止。 要在匹配结束事件发生时停止计时器,请在匹配结束事件触发时设置计时器。 这是创建事件的一个好处。 它可以在多个情况下重用在多个情况下。

  1. 在 MatchManager 中,创建一个名为 stopTimer() 的新本地函数。里面,输入 myTimer:stop() 来停止计时器。


    -- 创建一个新的计时器对象来跟踪匹配时间。
    local myTimer = timer.new()
    -- 本地函数
    local function stopTimer()
    myTimer:stop()
    end
    local function timeUp()
    matchEnd:Fire(gameSettings.endStates.TimerUp)
    end
  2. 要在比赛结束时停止计时器,请将匹配结束事件连接到 stopTimer()


    -- 模块功能
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    matchStart:Fire()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  3. 测试 那个以前的错误不再会出现,如果您启动一个 服务器 。消除所有但一个玩家,然后等待几秒钟,当匹配结束。

下一步

虽然两个胜利条件已经完成,但还有一些任务需要完成游戏循环。例实例,胜利的玩家不会被传送到大厅。在下一课中,您将显示比赛结束于玩家,并重置游戏,最终完成整个循环。

已完成的脚本

以下是完成脚本来重新检查您的工作。

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)
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

游戏设置脚本


local GameSettings = {}
-- 游戏变量
GameSettings.intermissionDuration = 5
GameSettings.matchDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.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 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()
print("Game ended with: " .. endState)
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 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 = (math.floor(myTimer:getTimeLeft() + 1))
-- 通过将时间设置为“等待”,它提供更准确的循环
task.wait()
end
end
-- 模块功能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager