关于 roblox-ui
面向 Roblox 开发者的 UI 设计与实现指南,涵盖自适应布局、样式、跨平台输入、文本、动画和性能。适用于从单个界面到多页面项目。
主要功能
- 01使用 Scale 与约束适配屏幕
- 02通过布局组件组织界面
- 03用 StyleSheets 管理样式和主题
- 04适配触摸、键鼠与手柄输入
- 05处理文本、本地化及动画
- 06优化动态界面的性能
适用场景
- 01构建适配手机和大屏的 HUD
- 02制作支持手柄导航的菜单
- 03为多页面项目统一样式
- 04实现动画面板与世界空间 UI
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ el4cteo/ roblox-skills --skill roblox-ui安装后在 Claude Code 中输入/roblox-ui确认已加载。
附带文件references/styling-and-frameworks.md
详细介绍
Roblox UI
基础
- 将 UI 放在
StarterGui中作为ScreenGui(会复制到每位玩家的PlayerGui),或通过客户端控制器创建。UI 代码仅在客户端运行;在常规设计中,服务器不会接触PlayerGui。 ScreenGui的默认设置:ResetOnSpawn = false(死亡后保留 UI)、ZIndexBehavior = Sibling、按设计设置IgnoreGuiInset,交互式 UI 使用ScreenInsets = CoreUISafeInsets(避开刘海屏区域和 Roblox 顶栏);只有全屏背景才使用DeviceSafeInsets/None。- 使用 Scale 设置尺寸和位置(
UDim2.fromScale),并搭配约束;Offset 仅用于固定细节(内边距、描边、图标)。纯 Offset UI 在手机和 4K 屏幕上会显示异常。 AnchorPoint = Vector2.new(0.5, 0.5)+Position = UDim2.fromScale(0.5, 0.5)可将元素居中。UIAspectRatioConstraint可保持形状为正方形或比例一致;UISizeConstraint可限制尺寸;使用TextScaled时,UITextSizeConstraint可限制文本大小(尽可能优先使用固定的TextSize+AutomaticSize——TextScaled会导致大小不一致)。AutomaticSize可让框架随内容增长(列表、工具提示、聊天气泡)。- 在 Device Simulator 中测试每种屏幕(手机竖屏/横屏、平板、10 英尺距离的主机屏幕、4K)。
布局
| 需求 | 使用 |
|---|---|
| 自适应行/列 | UIListLayout(FillDirection、Padding、HorizontalFlex/VerticalFlex、Wraps) |
| 一个项目扩展以填满空间 | 使用 FlexMode = Fill(或 Grow/Shrink/Custom)的 UIFlexItem 子项 |
| 网格(物品栏) | 在带有 AutomaticCanvasSize 的 ScrollingFrame 中使用 UIGridLayout |
| 轮播/页面 | UIPageLayout |
| 圆角、边框、内边距 | UICorner、UIStroke、UIPadding |
| 渐变、阴影 | UIGradient、UIShadow |
| 缩放整个组 | UIScale |
--!strict
local Players = game:GetService("Players")
local playerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "Hud"
screenGui.ResetOnSpawn = false
screenGui.ScreenInsets = Enum.ScreenInsets.CoreUISafeInsets
local bar = Instance.new("Frame")
bar.Name = "Toolbar"
bar.AnchorPoint = Vector2.new(0.5, 1)
bar.Position = UDim2.new(0.5, 0, 1, -16)
bar.Size = UDim2.fromScale(0.6, 0.1)
bar.BackgroundTransparency = 0.3
bar.Parent = screenGui
local list = Instance.new("UIListLayout")
list.FillDirection = Enum.FillDirection.Horizontal
list.HorizontalFlex = Enum.UIFlexAlignment.Fill -- slots share the width equally
list.Padding = UDim.new(0, 8)
list.Parent = bar
Instance.new("UICorner").Parent = bar
local padding = Instance.new("UIPadding")
padding.PaddingLeft, padding.PaddingRight = UDim.new(0, 8), UDim.new(0, 8)
padding.Parent = bar
for slot = 1, 5 do
local button = Instance.new("TextButton")
button.Name = `Slot{slot}`
button.Text = tostring(slot)
button.Size = UDim2.fromScale(0, 1)
button.Parent = bar
Instance.new("UIAspectRatioConstraint").Parent = button
end
screenGui.Parent = playerGui -- parent last: one layout pass, no flicker
样式:StyleSheets(类似 CSS)
Roblox 引擎级样式可替代复制粘贴的属性值:
- 使用包含
StyleRule的StyleSheet(Selector可设为"TextButton"、".Primary"(标签)、"#Close"(名称)、"TextButton:Hover"(状态)、"::UICorner"(修饰符伪实例)),并调用rule:SetProperties({...})。 - Token 是 Token Sheet 上的属性(
$Primary、$Radius);主题 是通过StyleDerive派生 Token 的 Sheet;通过重新指定StyleDerive来切换主题。 ScreenGui下的StyleLink会将一个 Sheet 应用于该树。样式查询(@Name)可根据屏幕尺寸、输入类型或无障碍设置切换样式。- 在 Studio 的 Style Editor 中进行可视化编辑。详情和代码示例:references/styling-and-frameworks.md。
UI 中的跨平台输入
- 读取
UserInputService.PreferredInput(KeyboardAndMouse、Touch、Gamepad),并监听UserInputService:GetPropertyChangedSignal("PreferredInput"),以切换按钮提示和布局。不要仅凭TouchEnabled/KeyboardEnabled推断平台。 - 使用
GuiButton.Activated(支持鼠标、触摸和游戏手柄),而非MouseButton1Click。 - 游戏手柄/主机:将每个交互元素设为
Selectable;打开菜单时设置GuiService.SelectedObject;使用SelectionGroup/NextSelection*分组,以实现可预测的方向键导航;支持使用ButtonB关闭。触摸目标最小尺寸约为 44×44 px;手机上的文本应不小于 14 px。 - 通过 Input Action System 绑定操作(
InputBinding.UIButton可让屏幕按钮触发操作)——参见roblox-input。
文本
RichText = true可启用<b>、<i>、<font color="#FF0">、<stroke>等标签。转义用户文本。- 向其他玩家显示的任何玩家文本都必须经过过滤:在服务器上使用
TextService:FilterStringAsync(roblox-text-chat)。这包括宠物名称、标牌、公会名称和交易备注。 - 使用
FontFace = Font.new("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Bold)设置字重。 - 使用
LocalizationTable和自动翻译实现本地化;避免将文本直接嵌入图片中。
动画与手感
- 在客户端使用补间动画:
TweenService:Create(frame, TweenInfo.new(0.2, Enum.EasingStyle.Quad), { Position = ... }):Play()。 - 使用
UIScale.Scale制作弹出效果,而不是调整Size(这样可以保持布局稳定)。 CanvasGroup可淡入淡出整个子树(GroupTransparency),但会渲染到纹理:适合用于淡入淡出面板,不适合用于大型常驻 UI(会带来内存和画质开销)。- 现在
ClipsDescendants也会裁剪旋转后的子对象和Path2D(自 2026 年 9 月 24 日起为默认行为;StarterGui.ClipsDescendantsSupportsRotation退出选项将于 2026 年 11 月移除)。若要避免旋转后的子对象被裁剪,可将其设为层级更高的同级对象。旋转后的父对象仍只会在CanvasGroup内部进行裁剪。 - 拖放:使用
UIDragDetector(已弃用的GuiObject.Draggable不再适用于新项目)。
世界空间 UI
BillboardGui(面向摄像机:名称、生命值条)——谨慎设置MaxDistance和AlwaysOnTop,使用Size的 Scale 值按距离缩放;零件上的屏幕或标牌使用SurfaceGui。优先使用Adornee,并将其保留在PlayerGui中以显示玩家专属内容。当其零件流出时,它们会停止渲染。ProximityPrompt可免费提供跨平台交互 UI(请在服务端进行验证!)。
框架
屏幕数量超过几个时,声明式框架有助于保持状态与 UI 同步:
- React(
jsdotlua/react+react-roblox)——组件 + hooks,Web 开发者熟悉,适用于大型应用。 - Fusion——响应式状态对象和声明式实例创建。
- Vide——小巧、快速的响应式库。 与项目现有的框架保持一致。将游戏状态保存在控制器中;UI 只负责渲染状态并发出用户意图。
性能
- 如果值没有变化,避免每帧更新文本或属性。
- 菜单关闭时使用
Visible = false(或对ScreenGui使用Enabled = false),而不是反复销毁并重新创建;大型列表应按需构建或进行虚拟化。 - 动态 UI 中过多使用
UIGradient/CanvasGroup/UIStroke会增加帧耗时;请检查 MicroProfiler。
相关技能
roblox-input(操作、游戏手柄)、roblox-text-chat(过滤)、roblox-monetization(商店)、roblox-luau、roblox-performance。
评论
支持 Markdown