roblox-ui
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRoblox UI
Roblox UI
Foundations
基础
- Put UI in as
StarterGuis (copied to each player'sScreenGui), or create it from a client controller. UI code is client-only; the server never touchesPlayerGuiin normal designs.PlayerGui - defaults to set:
ScreenGui(keep UI across deaths),ResetOnSpawn = false,ZIndexBehavior = Siblingper design,IgnoreGuiInsetfor interactive UI (clears notches and the Roblox top bar);ScreenInsets = CoreUISafeInsets/DeviceSafeInsetsonly for full-bleed backgrounds.None - Size and position with Scale () plus constraints; use Offset only for fixed details (padding, strokes, icons). Pure-Offset UI breaks on phones and 4K screens.
UDim2.fromScale - +
AnchorPoint = Vector2.new(0.5, 0.5)centers an element.Position = UDim2.fromScale(0.5, 0.5) - keeps shapes square/consistent;
UIAspectRatioConstraintcaps sizes;UISizeConstraintwithUITextSizeConstraintbounds text size (prefer fixedTextScaled+TextSizewhere possible —AutomaticSizeproduces inconsistent sizes).TextScaled - lets frames grow with content (lists, tooltips, chat bubbles).
AutomaticSize - Test every screen in the Device Emulator (phone portrait/landscape, tablet, console 10-foot, 4K).
- 将 UI 作为 放入
ScreenGui(会复制到每位玩家的StarterGui),或者由 客户端 controller 创建。UI 代码仅在客户端运行;正常设计中,服务端绝不操作PlayerGui。PlayerGui - 默认应设置为:
ScreenGui(在死亡后保留 UI)、ResetOnSpawn = false、 根据设计配置ZIndexBehavior = Sibling;对于交互式 UI,使用IgnoreGuiInset(避开刘海和 Roblox 顶部栏);仅全屏铺满的背景才使用ScreenInsets = CoreUISafeInsets/DeviceSafeInsets。None - 使用 Scale()配合 constraints 控制尺寸和位置;仅将 Offset 用于固定 细节(padding、stroke、icon)。纯 Offset UI 会在手机和 4K 屏幕上失效。
UDim2.fromScale - 与
AnchorPoint = Vector2.new(0.5, 0.5)配合使用, 可将元素居中。Position = UDim2.fromScale(0.5, 0.5) - 可保持形状方正或比例一致;
UIAspectRatioConstraint可限制尺寸上限;UISizeConstraint与UITextSizeConstraint可限制文字大小(尽可能优先使用固定TextScaled+TextSize——AutomaticSize会产生不一致的尺寸)。TextScaled - 可让 Frame 随内容扩展(列表、tooltip、聊天气泡)。
AutomaticSize - 在 Device Emulator 中测试每一种屏幕(手机竖屏/横屏、平板、主机 10-foot 视角、4K)。
Layout
布局
| Need | Use |
|---|---|
| Rows/columns that adapt | |
| One item grows to fill space | |
| Grids (inventory) | |
| Carousels/pages | |
| Rounded corners, borders, padding | |
| Gradients, shadows | |
| Scale a whole group | |
luau
--!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| 需求 | 使用 |
|---|---|
| 自适应行/列 | |
| 让一个项扩展以填满空间 | 使用 |
| 网格(库存) | 在 |
| 轮播/分页 | |
| 圆角、边框、内边距 | |
| 渐变、阴影 | |
| 缩放整个组 | |
luau
--!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 flickerStyling: StyleSheets (CSS-like)
样式:StyleSheets(类似 CSS)
Roblox's engine-level styling replaces copy-pasted property values:
- with
StyleSheets (StyleRulelikeSelector,"TextButton"(tag),".Primary"(name),"#Close"(state),"TextButton:Hover"(modifier pseudo-instance)) and"::UICorner".rule:SetProperties({...}) - Tokens are attributes on a token sheet (,
$Primary); themes are sheets deriving tokens ($Radius); swap themes by retargeting theStyleDerive.StyleDerive - A under a
StyleLinkapplies one sheet to that tree. Style queries (ScreenGui) switch styles by screen size, input type, or accessibility settings.@Name - Edit visually in Studio's Style Editor. Details and a code example: references/styling-and-frameworks.md.
Roblox 的引擎级样式功能可取代重复复制粘贴的属性值:
- 使用带 s 的
StyleRule(StyleSheet可写成Selector、"TextButton"(tag)、".Primary"(name)、"#Close"(state)、"TextButton:Hover"(modifier pseudo-instance)),并通过"::UICorner"设置属性。rule:SetProperties({...}) - Tokens 是 token sheet 上的属性(、
$Primary);themes 是派生自 tokens 的 sheet ($Radius);重新指定StyleDerive的目标即可切换 themes。StyleDerive - 放在 下的
ScreenGui会将一个 sheet 应用于该 UI 树。Style queries(StyleLink) 可按屏幕尺寸、输入类型或无障碍设置切换样式。@Name - 可在 Studio 的 Style Editor 中进行可视化编辑。更多细节和代码示例: references/styling-and-frameworks.md。
Cross-platform input in UI
UI 中的跨平台输入
- Read (
UserInputService.PreferredInput,KeyboardAndMouse,Touch) and listen toGamepadto swap button prompts and layouts. Don't infer platform fromUserInputService:GetPropertyChangedSignal("PreferredInput")/TouchEnabledalone.KeyboardEnabled - Use (works for mouse, touch, and gamepad) instead of
GuiButton.Activated.MouseButton1Click - Gamepad/console: every interactive element , set
Selectablewhen a menu opens, group withGuiService.SelectedObject/SelectionGroupfor predictable D-pad navigation, supportNextSelection*to close. Minimum touch target ≈ 44×44 px; readable text ≥ 14 px on phones.ButtonB - Bind actions through the Input Action System (makes an on-screen button trigger an action) — see
InputBinding.UIButton.roblox-input
- 读取 (
UserInputService.PreferredInput、KeyboardAndMouse、Touch),并监听Gamepad,以切换按钮提示和布局。 不要仅凭UserInputService:GetPropertyChangedSignal("PreferredInput")/TouchEnabled推断平台。KeyboardEnabled - 使用 (适用于 mouse、touch 和 gamepad),而不是
GuiButton.Activated。MouseButton1Click - 对于 gamepad/console:所有可交互元素都应设为 ;菜单打开时设置
Selectable;使用GuiService.SelectedObject/SelectionGroup组织分组,以实现可预测的 D-pad 导航; 支持使用NextSelection*关闭。触摸目标尺寸至少约为 44×44 px;手机上的可读文字应 ≥ 14 px。ButtonB - 通过 Input Action System 绑定操作(可让屏幕按钮触发操作)——参见
InputBinding.UIButton。roblox-input
Text
文本
- enables
RichText = true,<b>,<i>,<font color="#FF0">, etc. Escape user text.<stroke> - Any text from one player shown to another must be filtered with on the server (
TextService:FilterStringAsync). That includes pet names, signs, guild names, trade notes.roblox-text-chat - Use for weights.
FontFace = Font.new("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Bold) - Localize with s and auto-translation; avoid baking text into images.
LocalizationTable
- 可启用
RichText = true、<b>、<i>、<font color="#FF0">等标签。请转义用户文本。<stroke> - 任何由一名玩家显示给另一名玩家的文本,都必须在服务端使用
进行过滤(
TextService:FilterStringAsync)。这包括宠物名称、标牌、 公会名称和交易备注。roblox-text-chat - 使用 设置字重。
FontFace = Font.new("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Bold) - 使用 s 和自动翻译进行本地化;避免将文字固化在图片中。
LocalizationTable
Animation and feel
动画与手感
- Tween on the client: .
TweenService:Create(frame, TweenInfo.new(0.2, Enum.EasingStyle.Quad), { Position = ... }):Play() - Animate for pop effects rather than
UIScale.Scale(keeps layout stable).Size - fades a whole subtree (
CanvasGroup) but renders to a texture: use it for fading panels, not for large always-visible UI (memory/quality cost).GroupTransparency - Drag-and-drop: (the deprecated
UIDragDetectorno longer works for new work).GuiObject.Draggable
- 在客户端执行 Tween:
。
TweenService:Create(frame, TweenInfo.new(0.2, Enum.EasingStyle.Quad), { Position = ... }):Play() - 为弹出效果设置 动画,而不是设置
UIScale.Scale(这样可保持布局稳定)。Size - 可以淡入淡出整个子树(
CanvasGroup),但会先渲染为 texture:仅将其 用于需要淡入淡出的面板,不要用于大型且始终可见的 UI(会带来内存和画质成本)。GroupTransparency - 拖放:使用 (已弃用的
UIDragDetector不再用于新项目)。GuiObject.Draggable
World-space UI
世界空间 UI
- (faces camera: names, health bars) — set
BillboardGui,MaxDistancesparingly, useAlwaysOnTopin Scale for distance scaling;Sizefor screens/signs on parts. PreferSurfaceGui+ keep them inAdorneefor per-player content. They stop rendering when their part streams out.PlayerGui - gives cross-platform interaction UI for free (validate on the server!).
ProximityPrompt
- (朝向摄像机:名称、血条)——设置
BillboardGui,谨慎使用MaxDistance,使用 Scale 设置AlwaysOnTop以实现距离缩放;Size用于部件上的屏幕或标牌。优先使用SurfaceGui,并将其保留在Adornee中,以支持每位玩家独立的内容。当关联 Part stream out 后, 它们会停止渲染。PlayerGui - 可直接提供跨平台交互 UI(务必在服务端验证!)。
ProximityPrompt
Frameworks
框架
For more than a few screens, a declarative framework keeps state and UI in sync:
- React (+
jsdotlua/react) — components + hooks, familiar to web devs, scales to big apps.react-roblox - Fusion — reactive state objects and declarative instance creation.
- Vide — small, fast reactive library. Match whatever the project already uses. Keep game state in controllers; UI only renders it and emits user intents.
当界面不止几个屏幕时,声明式 framework 可让状态与 UI 保持同步:
- React(+
jsdotlua/react)——components + hooks,web 开发者熟悉, 可扩展到大型应用。react-roblox - Fusion——响应式状态对象和声明式实例创建。
- Vide——轻量、快速的响应式库。
与项目当前使用的方案保持一致。将游戏状态保留在 controllers 中;UI 只负责渲染状态并发出用户意图。
Performance
性能
- Avoid updating text/properties every frame when values haven't changed.
- Hide closed menus with (or
Visible = falseon the ScreenGui) instead of destroying/recreating them repeatedly; build large lists lazily or virtualize them.Enabled = false - Too many /
UIGradient/CanvasGroupon dynamic UI costs frame time; check the MicroProfiler.UIStroke
- 当值未发生变化时,避免每帧更新文本或属性。
- 使用 (或在
Visible = false上使用ScreenGui)隐藏已关闭的菜单,而不是反复销毁和重新创建; 对大型列表进行延迟构建或虚拟化。Enabled = false - 动态 UI 上过多使用 /
UIGradient/CanvasGroup会消耗帧时间;使用 MicroProfiler 检查。UIStroke
Related skills
相关 skills
roblox-inputroblox-text-chatroblox-monetizationroblox-luauroblox-performanceroblox-inputroblox-text-chatroblox-monetizationroblox-luauroblox-performance