创建团队 让您可以将玩家分成竞争组,以完成共同目标,例如获得最多积分或在其他敌方团队成员之前越过终点线。对于第一人称射击游戏,创建团队尤其重要,因为它建立了超出任何单个玩家技能范围的复杂协调游戏策略。
以 示例激光标记游戏 为参考,本教程的这一部分教您如何将玩家分成团队,包括脚本指导:
- 使用 Teams 服务的默认功能将玩家分配到绿色或粉色团队。
- 帮助玩家通过屏幕和游戏内团队指示器区分盟友和敌方团队成员。
- 启用宽容的游戏玩法,不会因击中队友而惩罚玩家。
完成本节后,您将了解允许玩家生成或重生到中立大厅或团队生成区的脚本,自定义第一人称力场视觉效果,并处理来自服务器和客户端的客户端状态。

分配团队颜色
示例激光标记游戏使用 Teams 服务作为创建两个团队的基础,因为该服务提供了开箱即用的内置团队排序行为。例如,在没有任何额外脚本工作的情况下,该服务处理以下操作:
- 将玩家均匀排序和平衡到每个团队中。
- 在排行榜上将玩家按团队分组。
- 在3D空间中将玩家名称着色为对应的团队颜色。
- 将玩家生成到只有他们的团队可以访问的不同生成位置。
由于此默认功能,示例启用了 Teams 服务,然后使用两个不同的 Team 对象,具有不同的 Team.Color 属性值来表示每个团队:薄荷代表在地图一侧集合的团队,肉色粉代表在地图另一侧集合的团队。这些特定颜色非常有用,因为它们是互补的,意味着它们彼此对比良好,并使玩家能够轻松扫描周围环境并在建筑物和其他玩家之间进行定位。




重要的是要注意 Team.Color 属性的确切 BrickColor 名称,因为游戏在许多脚本中使用此名称来跟踪玩家在分队时的情况,在回合中当玩家标记敌方玩家时增加积分,并更新自定义 UI 元素。例如,当回合开始时,ReplicatedStorage ⟩ HUDGuiSetup 需要 startSyncingTeamColor 和 startSyncingTeamPoints,这两个都引用 Team.Color 以执行每个团队的独特操作。
startSyncingTeamColor 引用 Team.Color,以便为玩家屏幕左下角的团队指示器分配正确的颜色和图标。


local function setPlayerTeamIcon(gui: ScreenGui)
for _, teamColorIcon in gui.PlayerDisplay.TeamIcons:GetChildren() do
local iconTeamColor = teamColorIcon:GetAttribute(GuiAttribute.teamColor)
teamColorIcon.Visible = localPlayer.TeamColor == iconTeamColor
end
end
local function startSyncingTeamColor(gui: ScreenGui)
setPlayerTeamIcon(gui)
localPlayer:GetPropertyChangedSignal("Team"):Connect(function()
setPlayerTeamIcon(gui)
end)
end显示团队指示器
一旦玩家被分配到一个团队,他们需要能够快速辨别自己属于哪个团队,并区分盟友和敌方团队成员。这种能力很重要,因为第一人称射击游戏的游戏玩法要求玩家在战斗区域内快速做出战略决策,以免被标记出局并输掉回合。
为了让玩家成功,示例激光标记游戏提供了多个屏幕和3D空间中的团队指示器:
- 玩家指示器 – 自定义屏幕 UI,显示玩家的团队颜色和图标。
- 团队指示器 – 自定义游戏内 UI,显示玩家的团队颜色。
- 排行榜指示器 – 默认 Teams 服务的屏幕 UI,将玩家按团队颜色分组。
- 名称着色 – 默认 Teams 服务的游戏内 UI,将玩家头顶的名称着色为其团队颜色。




您无需在排行榜指示器或名称着色上做任何额外工作,只需从本教程的上一部分分配团队颜色,但自定义 UI 团队指示器需要更多编程工作,以显示指示器并在它们被墙壁遮挡时遮挡敌方指示器。有关控制自定义 UI 行为的脚本的完整说明,以及如何实现每个 UI 元素本身,请参阅 UI 课程中的 玩家指示器 和 团队指示器。
禁用友军伤害
虽然一些第一人称射击游戏会惩罚击中自己队友的玩家,但示例激光标记游戏通过禁用友军伤害来允许更宽容的游戏玩法。这个设计决策允许每个人只增加他们的团队得分,而不是因游戏事故而减少得分。
要了解示例如何实现此功能,请检查 ServerScriptService ⟩ LaserBlastHandler ⟩ processTaggedPlayers ⟩ onPlayerTagged 如何处理对被标记玩家造成伤害。当服务器检测到玩家的爆炸与另一名玩家发生碰撞时,它调用 onPlayerTagged 函数以了解哪个玩家发射了爆炸,哪个玩家被击中,以及根据爆炸器类型应从玩家的生命值中移除多少伤害。
local function onPlayerTagged(playerBlasted: Player, playerTagged: Player, damageAmount: number)在减少生命值之前,脚本首先验证被标记的玩家是否与发起爆炸的玩家在同一团队。如果他们在同一团队,脚本将完全忽略爆炸数据。
local character = playerTagged.Character
local isFriendly = playerBlasted.Team == playerTagged.Team
-- 禁止友军伤害
if isFriendly then
return
end但是,如果被标记的玩家 在 敌方团队中,则该玩家将根据爆炸器类型受到适当的伤害。此外,如果玩家受到足够的伤害而被标记出局,脚本将奖励发起爆炸的玩家的团队一个积分。有关示例如何跟踪积分的更多信息,请参阅本教程后面的 添加回合。
local humanoid = character and character:FindFirstChild("Humanoid")
if humanoid and humanoid.Health > 0 then
local damage = math.min(damageAmount, humanoid.Health)
humanoid:TakeDamage(damage)
if humanoid.Health <= 0 then
Scoring.incrementScore(playerBlasted, 1)
end
end
end
return onPlayerTagged如果您现在测试游戏,所有玩家将随机在竞技场两端的任一生成区生成,而不考虑他们属于哪个团队,这意味着每个团队将彼此相邻生成。
为了解决这个问题,本教程的下一部分将教您有关限制团队生成到特定生成位置的自定义逻辑,处理玩家在选择爆炸器后离开生成区域的客户端状态,以及当他们的生命值降至零时将玩家重新生成回他们的生成区或大厅区域。