匹配可以在计时器耗尽或单个玩家被留下等几种情况下结束。
管理被击败的玩家
现在,被击败的玩家在竞技场重生。相反,将他们发送回大厅等待下一场比匹配。
- 在 PlayerManager 中,创建一个名为 respawnPlayerInLobby() 的本地函数。在该函数中,执行以关注中/正在关注操作:
- 将玩家的重生位置属性设置为 lobbySpawn。
- 使用 Player:LoadCharacter() 重新加载角色。请记住,LoadCharacter() 在他们重生点生时创建玩家,移除他们拥有的任何工具。
使用匿名函数
匿名函数在特定情况下常用于高级脚本。在定义它们之前,了解您的脚本可能遇到的情况很重要。
考虑这个:要将被击败的玩家传送到大厅,重生函数必须连接到玩家的死亡事件。不过有一个问题。如果你像过去一样连接事件,那么无法从死亡事件中获取玩家的名称。脚本需要该名称来从跟踪活跃玩家的表中删除被击败的玩家。
要获取导致死亡事件的玩家名称,请使用匿名函数。 匿名函数 没有名称,可以直接在Connect()创建,而不是单独创建。
下面是一个示例匿名函数,显示了语法。
myPlayer.Died:Connect(function()
print(player)
end)
编写死亡事件
对于这个功能,每当玩家的角色死亡时,它们都会触发重生他们的功能。
要获得玩家死亡事件的访问权限,请在 PlayerManager > preparePlayer() 中添加一个变量为玩家的人形。
local function preparePlayer(player, whichSpawn)player.RespawnLocation = whichSpawnplayer:LoadCharacter()local character = player.Character or player.CharacterAdded:Wait()local sword = playerWeapon:Clone()sword.Parent = characterlocal humanoid = character:WaitForChild("Humanoid")end创建一个匿名函数,连接到死亡事件。先输入 humanoid.Died:Connect() 。然后, 内部 Connect(),输入function(),按Enter自动完成end,然后删除额外的括号。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()end)在匿名函数中,调用 respawnPlayerInLobby() . 传递 player ,一个变量,存储玩家准备进入匹配赛的准备。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()respawnPlayerInLobby(player)end)启动一个 服务器 并进行比匹配。测试玩家死亡时,他们在大厅重生。要击败玩家,走到他们身边并使用你的武器,直到你确认他们在大厅重生为止。
攻击玩家2 >重生后的大厅中的玩家2 >
注意,如果需要,也有一些不同的测试方法。
- 要杀死一个玩家,在服务器 > 输出窗口 > 命令栏中,复制并粘贴:workspace.Player1.Humanoid.Health = 0。按Enter执行命令。要删除其他玩家,请使用 Player2、Player3 等
- 将游戏设置 > matchDuration 设置为更长时间可以给你更多时间来找到并取出所有玩家。
- 要进行更快的测试,将游戏设置 > minimumPlayers 更改为更小的数字,例如 2。
结束游戏
现在击败的玩家重生了,开始工作以结束游戏。记得创建匹配结束事件吗?当计时器耗尽或找到胜利者时,将触发该事件。
要告诉其他脚本哪个条件结束了游戏,创建一个包含变量 TimerUp 和 FoundWinner 的表。当匹配结束事件发生时,它会传递一个变量,以便其他脚本可以回应。
在游戏设置中,创建一个名为 endStates 的空模块表。
local GameSettings = {}-- 游戏变量GameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- 游戏可能结束的方式。GameSettings.endStates = {}return GameSettings创建两个变量名为 TimerUp 和 FoundWinner 。将每个设置为与名称匹配的字符串。这些字符串将用于测试代验证码。
GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}
以计时器结束
当计时器结束时,发射匹配结束事件,并发送匹配的结束状态变量。这样,其他正在听该事件的脚本可以根据需要进行回应。请记住,在事件发射信号时,也可以发送由收听脚本接收的数据,例如 TimerUp 或 FoundWinner 。
在 游戏管理器 中,在 while 真实循环中,找到线 matchEnd.Event:Wait() 。在线的开头添加 local 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()end要确认收到正确的状态,请添加包含 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()print("Game ended with: " .. endState)end在匹配管理器中,找到 timeUp() 并 移除 打印声明。然后,要发射匹配结束事件,请输入 matchEnd:Fire() 并传递 gameSettings.endStates.TimerUp 。
-- 值local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")local timeLeft = displayValues:WaitForChild("TimeLeft")-- 创建一个新的计时对象,用于跟踪比赛时间。local myTimer = timer.new()-- 本地函数local function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)end测试匹配。一旦计时器耗尽,检查打印声明包含在 TimerUp 变量中的字符串。
排除问题的提示
在这一点上,消息未显示,请尝试以下其中一个。
- 检查任何地方都调用了终端状态变量,它们是否正确地写入,如这里:gameSettings.endStates.TimerUp。
- 请确保使用:(斑点运营商)与 取代点运营商,如在 中。
编写一个胜利的比匹配
接下来,脚本需要识别获胜玩家、移除失败玩家,并运行清理操作,例如停止计时器。如果一个玩家被留下,匹配也会结束。要查看是否满足 FoundWinner 条件,你需要一个检查表中跟踪玩家的数量的函数。
检查玩家数量
如果只有一个玩家剩下,匹配将结束。要检查这一点,脚本需要跟踪玩家在一轮中。一旦一个玩家被淘汰,就可以分配胜利者。
在 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")在 respawnPlayerInLobby() 之上,添加一个名为 checkPlayerCount() 的新本地函数。
-- 玩家变量local activePlayers = {}local playerWeapon = ServerStorage.Weaponlocal function checkPlayerCount()endlocal function respawnPlayerInLobby(player)在那个函数中,使用 then 句检查是否有胜利者。在那个句子中:
- 检查 activePlayers 表的大小是否为 1。
- 如果是这样,请发射 matchEnd 并传递 gameSettings.endStates.FoundWinner 。
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
移除一个玩家
除非玩家被移除,否则不能保持准确的计数。当玩家被击败时,通过从玩家表中删除他们来保持准确的玩家数量。然后,检查活跃玩家表的大小以确定是否有获胜者。
在 checkPlayerCount() 下,创建一个名为 removeActivePlayer() 的新本地函数,其参数名为 player 。
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endendlocal function removeActivePlayer(player)end要在 activePlayers 表中找到玩家,使用 for 循环进行循环。然后,添加一个 if 声明,如果找到了匹配名称的玩家进入函数,就会运行。
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thenendendend要移除玩家,在 if 声明中:
- 将 playersLeft 对象的值设置为 #activePlayers .
- 通过运行 checkPlayerCount() 检查获胜玩家。
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thentable.remove(activePlayers, playerKey)playersLeft.Value = #activePlayerscheckPlayerCount()endendend
连接事件和测试
要使用刚刚创建的函数,请从连接到玩家 Died 事件的匿名函数中调用它。
找到 preparePlayer() . 在死亡事件连接的匿名函数中,调用 removeActivePlayer() . 然后,将玩家传递为参数。
humanoid.Died:Connect(function()respawnPlayerInLobby(player)removeActivePlayer(player)end)要查看是否找到了赢家,请启动 测试服务器 。当只剩下一个玩家时,你应该在输出窗口中看到 FoundWinner。
继续测试并让匹配结束。注意当新的匹配开始时,输出窗口中出现错误:
这个错误是因为计时器没有停止,这将在下一节中修复。
停止计时器
每当比赛以胜利的玩家结束时,计时器也应停止。为了在时间到之停止计时器,在匹配结束事件触发时让计时器停止。这是创建事件的好处之一。它们可以在多种情况下重复使用,来编写原因和效果关系的脚本。
在匹配管理器中,创建一个名为 stopTimer() 的新本地函数。内部,输入 myTimer:stop() 来停止计时器。
-- 创建一个新的计时对象,用于跟踪比赛时间。local myTimer = timer.new()-- 本地函数local function stopTimer()myTimer:stop()endlocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)end要在比赛结束时停止计时器,将 matchEnd 事件连接到 stopTimer() 。
-- 模块功能function MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endmatchStart.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)
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 = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.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 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()print("Game ended with: " .. endState)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 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 = (myTimer:getTimeLeft() + 1) // 1
-- 通过不设置等待时间,它提供了更准确的循环
task.wait()
end
end
-- 模块功能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager