一个 HUD 或 抬头显示 是一组在游戏过程中始终可见或可访问的 UI 元素,例如得分显示、健康计量器和菜单按钮。包含 HUD 对于大多数游戏至关重要,因为它显示了帮助玩家成功完成游戏目标的信息。
一个常见的 HUD 元素是健康计量器,左侧有一个图标,可以改编为计时条、进度条或类似的东西。

使用 Hazardous Space Station 作为起始地点,并将 UI 基础知识 - HUD 计量器 作为完成的参考地点,本教程演示了:
- 设置和使用 设备模拟器 在多个模拟屏幕上测试您的设计。
- 使用 StarterGui 作为设计和存储容器。
- 如何在内置 Roblox 控件和设备缺口/岛屿周围定位/调整 UI 元素的大小,例如现代手机上的相机缺口。
- 如何用您自己的计量器替换默认的 Roblox 健康计量器,并将其连接到角色的健康水平。
- 如何为健康计量器的中心部分添加动画,并在五个颜色渐变关键点(红色、橙色、黄色、青柠、绿色)之间设置其颜色。
启用设备模拟器
Roblox 本质上是 跨平台 的,因为玩家可以在手机或平板电脑上发现并加入游戏,然后在 PC 或控制台上继续他们的游戏进度。移动设备(手机和平板电脑)具有最少的屏幕空间,因此确保您的 UI 元素适合较小的屏幕并且对玩家清晰可见非常重要。
测试跨平台 UI 设计的最佳方法是 Studio 的 设备模拟器。此工具提供了一组预设设备,并允许您添加自己的自定义预设。
在 Studio 中打开 Hazardous Space Station 模板。
从 Studio 的 测试 菜单中,切换开启 设备模拟器。
从主视口上方的工具栏中,选择一个手机模拟,例如 iPhone X 或 Samsung Galaxy A51。然后,将视图大小设置为 适应窗口 以利用 Studio 中的最大空间。

创建屏幕容器
ScreenGui 容器持有 UI 对象(GuiObjects),以在玩家的屏幕上显示(在本教程中,整个健康计量器)。要将 ScreenGui 及其子对象显示给每个加入游戏的玩家,请将其放置在 StarterGui 容器内。当玩家加入并且他们的角色首次生成时,ScreenGui 及其内容会克隆到该玩家的 PlayerGui 容器中,该容器位于 Players 容器内。

要插入一个空的 ScreenGui:
在 资源管理器 窗口中,找到 StarterGui 容器。

将鼠标悬停在容器上,单击 ⊕ 按钮,并插入一个 ScreenGui。

将新容器重命名为 HUDContainer 以反映其用途。

利用安全区域
现代手机利用整个屏幕,但通常包括缺口、切口和其他占用屏幕空间的元素。每个 Roblox 游戏还包括 顶部栏控件,以便快速访问主菜单、聊天、排行榜 等。

为了确保玩家可以看到并访问所有 UI 而不被遮挡,Roblox 提供了 ScreenInsets 属性,该属性控制 ScreenGui 内容的 安全区域 内边距。您在 ScreenGui 中定位的每个 UI 对象都是相对于内边距边界的。

虽然 CoreUISafeInsets 的默认设置确保所有 UI 对象远离 Roblox UI 和设备切口,但 DeviceSafeInsets 可能是利用有限屏幕空间的更好选择,如下所示。

在 资源管理器 窗口中,选择 HUDContainer。

在 属性 窗口中,将 ScreenInsets 属性设置为 DeviceSafeInsets。

设置边缘填充
将 ScreenInsets 设置为 DeviceSafeInsets 后,内容现在可以直接扩展到屏幕的物理顶部边缘。然而,少量的 填充 可以帮助将健康计量器(以及容器内的其他对象)稍微推离屏幕边缘,以获得更干净的外观,并防止它们被裁剪。

为 UI 容器应用填充的一种方法是插入一个 UIPadding 修饰符:
在 HUDContainer 中插入一个 UIPadding 修饰符。

选择新的 UIPadding 对象,为容器的所有边缘输入值 0, 16(PaddingBottom、PaddingLeft、PaddingRight、PaddingTop)。这会在容器周围应用 16 像素的填充,无论屏幕的分辨率如何。

构建健康计量器
配置好 屏幕容器 后,您可以开始使用 Roblox UI 对象(例如 框架 和 图像标签)构建健康计量器。

创建父框架
类似于 Figma 和 Photoshop 等设计应用程序,Roblox 中的 Frame 作为其他 UI 对象的容器。在本教程中,整个健康计量器将包含在一个父框架中,使其在各种 HUD 布局中重新定位变得简单。
将新框架实例重命名为 MeterBar。

定位框架
在 Roblox 中,UI 对象的位置由包含 UDim2 坐标集表示,该坐标集包含 X 和 Y 轴的 Scale 和 Offset 值:


要将 UI 对象定位在屏幕容器的右上角,Scale 是最佳方法,因为 X 值为 1(100%)表示容器的右边缘,无论屏幕的物理像素大小如何。同样,Y 的比例值为 0(0%)表示容器的顶部边缘。

此外,您还需要为父框架设置右上角的 锚点 以定义其原点。可接受的值在 0 和 1 之间,相对于对象的大小,因此锚点值 1, 0 将框架的锚点放在其右上角。

在 资源管理器 窗口中,选择您之前插入的 MeterBar 框架。

输入 1, 0 作为 AnchorPoint 属性。框架现在应该位于 设备安全区域 的右上角,稍微向内缩进,作为 填充 的结果。

调整框架大小
与位置一样,UI 对象的 Size 由包含 UDim2 坐标集表示,该坐标集包含 X 和 Y 轴的 Scale 和 Offset 值。
默认情况下,新框架的大小为 {0, 100},{0, 100},表示宽度(X)和高度(Y)均为 100 像素。虽然严格的像素值在某些情况下是有用的,但许多 UI 元素在设置为整体屏幕容器大小的 百分比 时,在多个屏幕上响应性更强。
选择 MeterBar 框架,访问 属性 窗口并导航到 Size 属性。
输入值 0.35, 0, 0.05, 0 以设置宽度为 35% 和高度为 5% 的百分比大小,没有添加的像素偏移。

样式化框架
默认情况下,Frames 填充为纯白色。最终的健康计量器应该具有更深且稍微不透明的填充,以及深色轮廓,以便在明亮和黑暗的背景上更好地突出。

选择 MeterBar 框架,输入 0 作为 BackgroundColor3 属性。Studio 会自动将其转换为 RGB 值 [0, 0, 0]。
输入 0.75 作为 BackgroundTransparency 属性。在 Roblox 中,透明度范围从 0(完全不透明)到 1(完全透明),因此 0.75 在其他应用程序(如 Figma 或 Photoshop)中等于 25% 的不透明度。

为了最终确定计量器框架的样式,您可以将角落圆化以形成“药丸”形状,而不是尖锐的矩形。
在 MeterBar 框架中插入一个 UICorner 实例。

选择新的 UICorner,将 CornerRadius 设置为 0.5, 0。使用 比例 值 0.5(50%)而不是像素值对于计量器条尤其方便,因为它确保无论容器变得多高或多宽,都会形成完全圆润的曲线。

创建内部填充
现在健康计量器的容器框架已完成,您可以添加一个 内部填充 部分来表示角色的可变健康。由于它只需要是一个实心填充区域,因此在父框架内的子 Frame 是合适的。

在 MeterBar 框架中插入一个子 Frame。
将新框架实例重命名为 InnerFill。

选择 InnerFill,设置以下属性:
- AnchorPoint = 0, 0.5(左边缘和垂直中心)
- Position = 0, 0, 0.5, 0
- Size = 1, 0, 1, 0
由于框架的子对象相对于其父对象定位和调整大小,因此使用比例使内部框架填充父框架的完整宽度和高度,从父框架的左边缘开始。

为了匹配父框架的“药丸”形状,在 InnerFill 中插入一个额外的 UICorner。

选择新的 UICorner 修饰符,将其 CornerRadius 属性设置为 0.5, 0,以匹配父 MeterBar 框架的“药丸”形状。

为了更好地表示满计量器表示良好健康,选择 InnerFill 并将其 BackgroundColor3 属性设置为 [0, 225, 50](在后面的任务中,您将 脚本 此颜色以根据实际健康变化)。

添加图标
为了更清楚地指示计量器的用途,您可以在左侧添加一个 图像标签,在这种情况下是一个红色心形图标,通常象征健康或生命。

在 MeterBar 框架中插入一个 ImageLabel。此对象允许您应用已作为贴花上传到 Roblox 的 2D 图像资产。
将新标签实例重命名为 Icon。

选择 Icon,将其 ZIndex 属性设置为 2。虽然新插入的 UI 对象总是层叠在之前插入的对象前面,但此更改确保图标始终显示在计量器框架元素的前面。

为了确保图标 ImageLabel 始终保持 1:1 的宽高比,插入一个 UIAspectRatioConstraint。尽管此 约束 具有可自定义的属性来控制宽高比,但您可以保持其默认值不变。

选择 Icon,通过更改以下属性来最终确定外观和位置:
- AnchorPoint = 0.5, 0.5(中心锚点)
- BackgroundTransparency = 1(100% 透明)
- Position = 0, 0, 0.5, 0(计量器的左侧和垂直中心)

限制大小
虽然在现代手机屏幕和 16:9 或更宽的游戏监视器上,0.05(5%)的 比例高度 看起来不错,但在平板电脑屏幕和旧手机上,计量器可能看起来稍微太高。您可以通过在 设备模拟器 中模拟 iPad 第七代 来检查这一点。


为了使计量器条的高度在更宽的屏幕上保持更一致,您可以应用一个 UISizeConstraint 来限制最大像素高度。
在 MeterBar 框架中插入一个 UISizeConstraint。

选择新的约束,将其 MaxSize 属性设置为 inf, 20,以将其高度限制为 20 像素,同时不强制限制宽度。

现在,计量器条在更宽和更高的屏幕之间保持更一致的高度。

替换默认健康计量器
Roblox 游戏包括一个默认的健康计量器,当角色受到伤害时会变得可见。如果您保持默认计量器可见,它将重复并可能与自定义计量器重叠。

禁用默认计量器
要禁用默认健康计量器,您将使用一个 客户端脚本(LocalScript)在 StarterPlayerScripts 中调用 StarterGui:SetCoreGuiEnabled()。
在 资源管理器 窗口中,展开 StarterPlayer 容器并找到其中的 StarterPlayerScripts 容器。

在容器中插入一个新的 LocalScript,并将其重命名为 HideDefaultHealthMeter 以描述其目的。StarterPlayerScripts 中的脚本在本地玩家加入游戏时会自动运行,使其成为运行脚本以永久隐藏默认计量器的理想容器。

当您插入一个新脚本时,它会自动在新的脚本编辑器选项卡中打开(如果没有,请双击 资源管理器 窗口中的脚本)。
将以下代码粘贴到 HideDefaultHealthMeter 脚本中:
HideDefaultHealthMeterlocal StarterGui = game:GetService("StarterGui")-- 隐藏默认健康计量器StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health, false)代码解释行 目的 1 获取对核心 服务 的引用,StarterGui,它代表您创建自定义健康计量器的相同容器,其内容克隆到每个加入游戏的玩家的 PlayerGui 容器中。 4 调用服务的 SetCoreGuiEnabled() 方法,并指示禁用默认健康计量器(false)。
如果您现在进行游戏测试并受到伤害,您会注意到默认计量器被禁用并隐藏(您将在下一部分中编写脚本以 反映健康变化)。

监听健康变化
所有默认的 Roblox 角色模型都包含一个 Humanoid 类,该类为角色提供特殊行为和功能,例如设置其行走/奔跑速度和管理其健康。Health 在服务器上 复制 到每个玩家的客户端,您可以检测这些变化以更新自定义健康计量器的大小和颜色。
在 资源管理器 窗口中,找到 StarterCharacterScripts 容器,该容器位于 StarterPlayer 内。

在容器中插入一个新的 LocalScript,并将其重命名为 UpdateCustomMeter 以描述其目的。StarterCharacterScripts 中的脚本在玩家的角色每次生成时会自动运行,使其成为运行脚本以在每次重生时完全重置健康计量器的理想容器。

在 UpdateCustomMeter 脚本的编辑窗口中,粘贴以下代码:
UpdateCustomMeterlocal Players = game:GetService("Players")-- 本地玩家、角色和人形的引用local player = Players.LocalPlayerlocal character = player.Characterlocal humanoid = character:WaitForChild("Humanoid")-- 计量器条内部框架的引用local playerGui = player:WaitForChild("PlayerGui")local meterBarInner = playerGui.HUDContainer.MeterBar.InnerFill-- 渐变序列颜色(红色、橙色、黄色、青柠、绿色)local gradient = {Color3.fromRGB(225, 50, 0),Color3.fromRGB(255, 100, 0),Color3.fromRGB(255, 200, 0),Color3.fromRGB(150, 225, 0),Color3.fromRGB(0, 225, 50)}-- 从分数点获取渐变序列中的颜色的函数local function getColorFromSequence(fraction: number): Color3-- 渐变中的每种颜色定义了一个部分的开始和/或结束local numSections = #gradient - 1-- 每个部分表示 1 的一部分local sectionSize = 1 / numSections-- 确定请求的分数落入哪个部分local sectionStartIndex = 1 + math.clamp(fraction, 0, 1) // sectionSize-- 获取部分开始和结束的颜色local sectionColorStart = gradient[sectionStartIndex]local sectionColorEnd = gradient[sectionStartIndex + 1] or sectionColorStart-- 将分数标准化为 0 到 1 之间的数字local fractionOfSection = math.clamp(fraction, 0, 1) % sectionSize / sectionSize-- 根据标准化的分数在开始和结束之间插值return sectionColorStart:Lerp(sectionColorEnd, fractionOfSection)endlocal function onHealthChanged()-- 计算新健康作为最大值的百分比local healthFraction = math.max(0, humanoid.Health / humanoid.MaxHealth)-- 将条设置为新的大小/颜色目标meterBarInner.Size = UDim2.new(healthFraction, 0, 1, 0)meterBarInner.BackgroundColor3 = getColorFromSequence(healthFraction)end-- 监听人形健康的变化humanoid.HealthChanged:Connect(onHealthChanged)-- 最初设置(或重置)条的大小/颜色为当前健康onHealthChanged()代码解释行 目的 4‑6 获取对本地 Player、其 Character 模型和其中的 Humanoid 类的引用。 9‑10 获取对计量器的 InnerFill 对象的引用,该对象必须在健康变化时调整大小和重新着色。 13‑19 声明一个包含五种颜色(红色、橙色、黄色、青柠、绿色)的数组,以在不同点重新着色计量器;例如,100% 健康为绿色,50% 为黄色,0% 为红色,或在关键点之间的任何分数进行混合。 22‑41 辅助函数,返回任何渐变颜色关键点之间的颜色混合。 43‑50 处理健康变化的函数。在这里,它计算角色的 MaxHealth 的新健康作为百分比,调整 InnerFill 的大小到该比例,并将其重新着色为从 getColorFromSequence() 函数返回的颜色。 53 主要 事件 连接,检测从服务器复制的 Health 变化并调用 onHealthChanged() 函数。 56 最初(在角色生成或重生时)调用 onHealthChanged() 函数,以将 InnerFill 的大小和颜色设置为正确的百分比。通常这将是完整的宽度和绿色。
如果您现在进行游戏测试,您会注意到自定义计量器在角色受到伤害时正确更新大小和颜色:
动画计量器条
为了为自定义计量器添加额外的光泽,您可以通过 补间动画 来动画健康变化,逐渐改变计量器条的大小和颜色,持续 ½ 秒。
访问您之前编辑的 UpdateCustomMeter 脚本的脚本编辑器选项卡。
选择所有行(CtrlA 或 ⌘A),然后用以下代码粘贴覆盖它们(CtrlV 或 ⌘V):
UpdateCustomMeterlocal Players = game:GetService("Players")local TweenService = game:GetService("TweenService")-- 本地玩家、角色和人形的引用local player = Players.LocalPlayerlocal character = player.Characterlocal humanoid = character:WaitForChild("Humanoid")-- 补间属性local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out)-- 计量器条内部框架的引用local playerGui = player:WaitForChild("PlayerGui")local meterBarInner = playerGui.HUDContainer.MeterBar.InnerFill-- 渐变序列颜色(红色、橙色、黄色、青柠、绿色)local gradient = {Color3.fromRGB(225, 50, 0),Color3.fromRGB(255, 100, 0),Color3.fromRGB(255, 200, 0),Color3.fromRGB(150, 225, 0),Color3.fromRGB(0, 225, 50)}-- 从分数点获取渐变序列中的颜色的函数local function getColorFromSequence(fraction: number): Color3-- 渐变中的每种颜色定义了一个部分的开始和/或结束local numSections = #gradient - 1-- 每个部分表示 1 的一部分local sectionSize = 1 / numSections-- 确定请求的分数落入哪个部分local sectionStartIndex = 1 + math.clamp(fraction, 0, 1) // sectionSize-- 获取部分开始和结束的颜色local sectionColorStart = gradient[sectionStartIndex]local sectionColorEnd = gradient[sectionStartIndex + 1] or sectionColorStart-- 将分数标准化为 0 到 1 之间的数字local fractionOfSection = math.clamp(fraction, 0, 1) % sectionSize / sectionSize-- 根据标准化的分数在开始和结束之间插值return sectionColorStart:Lerp(sectionColorEnd, fractionOfSection)endlocal function onHealthChanged()-- 计算新健康作为最大值的百分比local healthFraction = math.max(0, humanoid.Health / humanoid.MaxHealth)-- 将条补间到新的大小/颜色目标local tweenGoal = {Size = UDim2.new(healthFraction, 0, 1, 0),BackgroundColor3 = getColorFromSequence(healthFraction)}local meterBarTween = TweenService:Create(meterBarInner, tweenInfo, tweenGoal)meterBarTween:Play()end-- 监听人形健康的变化humanoid.HealthChanged:Connect(onHealthChanged)-- 最初设置(或重置)条的大小/颜色为当前健康onHealthChanged()关键添加/更改行 目的 2 获取对 TweenService 的引用,以在脚本中实现补间动画功能。 10 创建一个 TweenInfo 构造函数,定义预期补间的持续时间、缓动样式 和 缓动方向。 52‑57 而不是简单地设置条的大小和颜色,如 之前的版本,声明一个 tweenGoal 表,包含目标大小/颜色,使用 tweenInfo 和 tweenGoal 参数创建一个新的补间,并播放新的补间。
如果您现在进行游戏测试,您会注意到自定义计量器在每次健康变化时都会进行补间动画:
添加伤害效果
默认健康计量器系统在角色受到伤害时会在屏幕边缘显示短暂、微妙的红色阴影。通过 禁用默认计量器,此效果被移除,但您可以用自己的实现替换它。
访问您之前编辑的 UpdateCustomMeter 脚本的脚本编辑器选项卡。
选择所有行并用以下代码粘贴覆盖它们:
UpdateCustomMeterlocal Workspace = game:GetService("Workspace")local Players = game:GetService("Players")local TweenService = game:GetService("TweenService")-- 本地玩家、角色和人形的引用local player = Players.LocalPlayerlocal character = player.Characterlocal humanoid = character:WaitForChild("Humanoid")-- 补间属性local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out)-- 存储/缓存角色健康的变量local cachedHealth = humanoid.Health / humanoid.MaxHealth-- 获取(或创建新的)颜色校正效果在玩家相机内local colorCorrection = Workspace.CurrentCamera:FindFirstChildWhichIsA("ColorCorrectionEffect") or Instance.new("ColorCorrectionEffect", Workspace.CurrentCamera)colorCorrection.Name = "DamageColorEffect"-- 计量器条内部框架的引用local playerGui = player:WaitForChild("PlayerGui")local meterBarInner = playerGui.HUDContainer.MeterBar.InnerFill-- 渐变序列颜色(红色、橙色、黄色、青柠、绿色)local gradient = {Color3.fromRGB(225, 50, 0),Color3.fromRGB(255, 100, 0),Color3.fromRGB(255, 200, 0),Color3.fromRGB(150, 225, 0),Color3.fromRGB(0, 225, 50)}-- 从分数点获取渐变序列中的颜色的函数local function getColorFromSequence(fraction: number): Color3-- 渐变中的每种颜色定义了一个部分的开始和/或结束local numSections = #gradient - 1-- 每个部分表示 1 的一部分local sectionSize = 1 / numSections-- 确定请求的分数落入哪个部分local sectionStartIndex = 1 + math.clamp(fraction, 0, 1) // sectionSize-- 获取部分开始和结束的颜色local sectionColorStart = gradient[sectionStartIndex]local sectionColorEnd = gradient[sectionStartIndex + 1] or sectionColorStart-- 将分数标准化为 0 到 1 之间的数字local fractionOfSection = math.clamp(fraction, 0, 1) % sectionSize / sectionSize-- 根据标准化的分数在开始和结束之间插值return sectionColorStart:Lerp(sectionColorEnd, fractionOfSection)endlocal function onHealthChanged()-- 计算新健康作为最大值的百分比local healthFraction = math.max(0, humanoid.Health / humanoid.MaxHealth)-- 将条补间到新的大小/颜色目标local tweenGoal = {Size = UDim2.new(healthFraction, 0, 1, 0),BackgroundColor3 = getColorFromSequence(healthFraction)}local meterBarTween = TweenService:Create(meterBarInner, tweenInfo, tweenGoal)meterBarTween:Play()-- 如果新健康低于缓存健康,则显示伤害效果if healthFraction < cachedHealth then-- 缓存新健康值cachedHealth = healthFraction-- 将颜色校正设置为红色作为补间前的初始阴影colorCorrection.TintColor = Color3.fromRGB(255, 25, 25)colorCorrection.Saturation = 2.5-- 将阴影补间回白色(中性且没有正常的阴影变化)local colorCorrectionTweenGoal = {TintColor = Color3.fromRGB(255, 255, 255),Saturation = 0}local colorCorrectionTween = TweenService:Create(colorCorrection, tweenInfo, colorCorrectionTweenGoal)colorCorrectionTween:Play()endend-- 监听人形健康的变化humanoid.HealthChanged:Connect(onHealthChanged)-- 最初设置(或重置)条的大小/颜色为当前健康onHealthChanged()关键添加/更改行 目的 14 设置一个占位符引用(cachedHealth)以跟踪角色的健康量,以便您可以比较变化是否较低(伤害)。 17‑18 在初始角色生成时,在玩家当前的 Camera 内创建一个新的 ColorCorrectionEffect,或在后续重生时获取对同一实例的引用。通过将此 后处理效果 作为玩家相机的子对象,它仅适用于他们的本地屏幕,而不是服务器上每个玩家的屏幕。 68‑83 首先执行条件检查以确认健康变化低于 cachedHealth 值,表示受到伤害;如果是,则将 cachedHealth 设置为新值。接下来,将 ColorCorrectionEffect 的阴影设置为 [255, 25, 25](红色)并提高饱和度,然后将阴影补间回默认的中性白色([255, 255, 255])并将饱和度设置为 0。
如果您现在进行游戏测试,您会注意到每当角色受到伤害时,屏幕会短暂闪烁红色:



