添加回合

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

添加回合 让你将游戏分为阶段,有明确的开始和结束点,以便玩家可以测量进度并获得定期的平等游戏场地机会。这对于团队基于的游戏尤为重要,因为它为玩家提供了在那一轮中转换他们的游戏风格的机会,根据谁在他们的团队中。

使用 样本激光标签体验 作为参考,本教程的这一部分教你如何使用和自定义 Roblox 内置功能来结构每一轮,包括关于脚本指南的指导:

  • 通过重置个人和团队积分开始回合,然后生成玩家到他们的团队生成区。
  • 自定义设置每个玩家屏幕顶部的目标变量。
  • 跟踪玩家点的贡献为他们的团队得分。
  • 根据玩家的团队是否赢得或失去了回合来触发独特的用户界面屏幕。
  • 通过断开玩家并将他们生成到中立大厅来结束一轮。

完成本节后,您将学习如何实现既准确又令玩家满意的爆破行为。

开始循环

服务器脚本服务 > 游戏 > 回合 处理了大部分的逻辑来实现回合,并且由调用 startRoundLoopAsync() 函数来标记回合循环的开始。当玩家加入大厅并等待分配到团队时, startRoundLoopAsync() 调用 resetScores() 函数在 ServerScriptService > 游戏玩法 > 评分 来重置排行榜和团队积分。

评分

function Scoring.resetScores()
for _, player in Players:GetPlayers() do
player.leaderstats.Points.Value = 0
end
for _, team in Teams:GetTeams() do
team:SetAttribute(GuiAttribute.teamPoints, 0)
end
end

现在每个人都从零点开始, 然后将中立生成地点置的属性设置为假,以便只有具有与生成地点置相同属性的玩家才能在那里生成。因为生成地点置的 TeamColor 属性已设置为 白色 而不是样本的薰衣草或玫瑰粉色队伍,这种配置防止所有玩家在回合激活时在那里生成或重生。

对于当前在大厅的玩家,startRoundLoopAsync() 将所有当前在体验中的玩家传递到 spawnPlayersInMap 功能中的 服务器脚本服务 > 游戏 > 回合 > 在地图上生成玩家 以排序并平衡每个团队的玩家数量大约相同,以排序并平衡每个团队的玩家数量大约相同。

对于在大厅组被排序为团队后加入体验的任何新玩家,startRoundLoopAsync() 听到 Players.PlayerAdded:Connect 事件,然后再次调用 spawnPlayersInMap 函数将他们添加到最少数玩家的团队。有关此过程的更多信息,请参阅配置生成位置从教程的以前的 生成和重生 部分。

回合

-- 在地图上生成所有玩家
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- 当他们加入时,在地图上生成新玩家
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)

设置目标

现在每个玩家都在竞技场与队友一起,体验需要提供在回合内成功的指示。示例激光标签体验通过在每个玩家的屏幕顶部提供一个客观的提示来满足这一要求,并提供清晰的指导,告诉团队需要做什么才能获胜。

虽然您可以在 UI 教程中了解更多关于如何配置和显示 目标用户界面 组件的方法,本节专注于如何在回合开始时实现目标目标,从设置每个团队需要完成回合的点数开始。

即使在运行时目标提示告诉玩家他们需要得分三分才能获胜,如果你在 StarterGui > HUDGui 中检查提示,你可以看到它实际上包含可配置的“%d”点值。

“ ”是一个可以随时增加或减少的占位符字符串,您可以通过在 ReplicatedStorage > 中更新变量 TEAM_SCORE_LIMIT 来满足自己的游戏需求。例如,如果你将此数字设置为过高的 200,那么提示和团队点数计数器将相应更新。

团队_分数_限制

local TEAM_SCORE_LIMIT = 200 -- 更新行,请确保返回
return TEAM_SCORE_LIMIT

这个简单的变量更新在运行时工作,因为当回合开始时, ReplicatedStorage > HUDGuiSetup > 设置目标 需要 TEAM_SCORE_LIMIT 模块脚本,以便它可以在 UI 目标的 TextLabel 对象中切换占位符字符串。

团队_分数_限制

local TEAM_SCORE_LIMIT = require(ReplicatedStorage.TEAM_SCORE_LIMIT)
local function setObjective(gui: ScreenGui)
local bodyTextLabel = gui.Objective.ObjectiveDisplay.Body.BodyTextLabel
bodyTextLabel.Text = bodyTextLabel.Text:format(TEAM_SCORE_LIMIT)
end

跟踪点

现在玩家有了回合的目标,体验需要跟踪每支队伍的积分,直到他们达到目标。虽然 Teams 服务的默认行为自动将每个玩家分组在他们的团队下,并将每个玩家的贡献添加到他们的团队得分中,但是为了回合游戏,重要的是要在单独位置存储和监控积分,因为如果玩家在回合结束前离开,他们的贡献将被从排行榜中扣除,因为他们与体验断开后。

为了确保这不会发生,每个向团队目标做出的贡献都得到保留, 复制存储 > HUDGui设置 > 开始同步团队积分 将所有积分独立地存储在 teamPoints 下的 Teams 。作为 teamPoints 增量,该模块脚本调用函数 startSyncingTeamPoints 找到目标 UI 组件内的团队计数器 Class.GuiObjects

当它找到 TeamACounterTeamBCounter 时,它获得了他们的 teamColor 属性,这与团队生成区相关:TeamACounter 显示绿色团队的分数,TeamBCounter 跟踪粉色团队的分数。

开始同步团队积分

local function startSyncingTeamPoints(gui: ScreenGui)
for _, teamPointCounter in gui.Objective.TeamPointCounter:GetChildren() do
if not teamPointCounter:IsA("GuiObject") then
continue
end
local iconTeamColor = teamPointCounter:GetAttribute(GuiAttribute.teamColor)

模块脚本然后调用其 函数来验证 TeamACounter's mint 属性和 TeamBCounter's carnation pink 属性都匹配相应的 属性,位于服务下方。如果是这样,它返回两个团队。

开始同步团队积分

local function getTeamFromTeamColor(teamColor: Color3): Team?
for _, team in Teams:GetTeams() do
if team.TeamColor == teamColor then
return team
end
end
return nil
end

当这发生时, startSyncingTeamPoints 将两个团队计数器的 TextLabel 对象设置为相应的 teamPoints 值,并继续更新它们,当玩家通过标记另一支队伍上的另一名玩家获得一分时。

开始同步团队积分

teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)

目前这一节的所有内容都专注于如何在玩家屏幕上跟踪点,但重要的是审查服务器上处理跟踪点的逻辑,以便知道团队何时达到目标目标并赢得回合。如果您重新访问 ServerScriptService > 游戏玩法 > 评分 ,您可以看到模块脚本通过创建可绑定的事件开始,每次玩家得分时都会触发。

评分

local teamScoreChangedBindable = Instance.new("BindableEvent")
local Scoring = {
teamScoreChanged = teamScoreChangedBindable.Event,
}

然后调用 incrementScore 函数,该函数执行以下操作:

  • 抓住玩家的团队和当前团队点数值在 服务中的对象,然后添加一个。
  • 抓取玩家在排行榜上的个人得分,并添加一个。
  • 发射以前提到的可绑定事件,包括玩家的队伍和他们的得分。

该过程有效地将客户端和服务器对两名玩家的个人得分和团队得分保持一致。

评分

function Scoring.incrementScore(player: Player, amount: number)
local team = player.Team
assert(team, `Player {player.Name} must be on a team to score a point, but has no team`)
local teamPoints = team:GetAttribute(GuiAttribute.teamPoints)
teamPoints += amount
team:SetAttribute(GuiAttribute.teamPoints, teamPoints)
local leaderstat = player.leaderstats.Points
leaderstat.Value += amount
teamScoreChangedBindable:Fire(team, teamPoints)
end

显示结果

当玩家标记对方并为他们的团队得分时, 服务器脚本服务 > 游戏 > 回合 检查是否满足了团队得分的回合目标。如果他们的团队得分低于 TEAM_SCORE_LIMIT 变量在 ReplicatedStorage > TEAM_SCORE_LIMIT 中,服务器继续等待直到其中一支团队再次得分。

然而,一旦团队的分数达到 TEAM_SCORE_LIMIT 变量,脚本会发射一个具有玩家名称和他们团队的 roundWinnerRemote 事件实例。

回合

-- 检查每次得分后回合是否结束
local team: Team
local score: number = 0
while score < TEAM_SCORE_LIMIT do
team, score = Scoring.teamScoreChanged:Wait()
end
-- 显示赢家团队
for _, player in Players:GetPlayers() do
-- 在回合结束时向球队发送玩家所在的团队
-- 因为玩家的团队即将被移除,所以客户
-- 无法检查自己的团队
roundWinnerRemote:FireClient(player, team, player.Team)
end

每个客户端上的 复制存储 > 回合结果设置 脚本倾听这个 roundWinnerRemote 事件实例,以便它可以:

  • 显示一个独特的 新手指南GUI > 回合结果GUI UI屏幕,宣布回合结果和玩家是否属于获胜团队伍。
  • 播放胜利或击败的音频片段。

例如,如果玩家属于得分的团队,他们会收到多种形式的回馈,即以胜利文本显示的 UI 屏幕和播放欢乐声音的音频片段。相反,如果玩家不在得分的团队中,他们会收到显示挫败文本的 UI 屏幕和发出阴森声音的音频片段。

胜利反馈
打败反馈
回合结果图形用户界面设置

local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Round ended!"
if localTeam then
-- 如果我们的团队赢了,我们会显示胜利!否则显示失败...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end

重置团队

在同一时间, 服务器脚本服务 > 游戏 > 回合 检查出一支团队满足了回合目标,并触发了每位玩家的适当界面显示,同时也将所有玩家从竞技场转移到大厅,通过关闭回合连接来实现。这启动了正式结束回合和重置两个团队的过程。

在 配置生成位置 、 回合 中使用相同的逻辑,然后将 中立 生成地点置的 属性设置为 true ,以便玩家无论他们的团队状态如何都可以在那里生成。这意味着大厅成为玩家在他们与回合断开后可以重生的唯一地点。

回合

-- 将所有人发送到大厅
playerAddedConnection:Disconnect()
neutralSpawn.Neutral = true
spawnPlayersInLobby(Players:GetPlayers())

等待十秒钟的中场休息后, 回合 服务器脚本然后重新启动循环,通过重置每个人的分数并将它们排序为新团队来重新启动循环。样本继续重复这个循环轮回过程,直到服务器内没有任何玩家。

现在玩家可以使用自己的团队进入地图并进行全轮游戏,下一节教你了解每个爆破器行为背后的脚本。