中级教程

创建互动 UI

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

一个 HUD (Heads-Up Display) 在你的体验中通常会显示非交互式的 UI 元素,例如在 创建 HUD 仪表 中演示的生命值计量器。在此基础上,几乎每个体验都需要 交互式 UI,比如在玩家激活时响应的按钮、激活时动画的按钮、与其他交互控件一起推出和收起的菜单等。

游戏内视图显示设置按钮和带有音量滑块的设置菜单。

使用 UI 基础知识 - HUD 仪表 作为起始点和 UI 基础知识 - 交互性 作为完成的参考, 本教程展示了:

  • 如何在屏幕顶部边缘定位设置按钮。
  • 包含可交互可拖动滑块的设置菜单的设计。
  • 使用 ModuleScripts 来形成“控制器”模块,以便对具有有状态声明的 UI 对象进行可扩展控制。
  • 如何连接按钮与玩家激活,以切换设置菜单的推出和收起。
  • 如何连接可拖动的 UI 滑块,以单独调整音效和背景氛围的音量。

启用设备模拟器

正如在 创建 HUD 仪表 中所指出的,手机和平板电脑的屏幕空间最少,因此确保 UI 元素适应更小的屏幕且对玩家清晰可见非常重要。如果你还没有这样做,请在 Studio 中启用 设备模拟器

  1. 在 Studio 中打开 UI 基础知识 - HUD 仪表 模板。

  2. 在 Studio 的 测试 菜单中,切换打开 设备模拟器

  3. 在主视口上方的工具栏中,选择手机模拟,例如 iPhone XSamsung Galaxy A51。然后,将视图大小设置为 适应窗口 以最大化利用 Studio 的空间。

    设备模拟器设置选项显示在视口窗口顶部。

创建设置按钮

GuiButtons 是具有内置功能的交互用户界面元素,例如当按钮被点击或轻触时触发的多平台 Activated 事件。GuiButton 类扩展为两个变体,TextButtonImageButton,本教程使用一个“齿轮”形状的 ImageButton 来切换设置菜单的打开或关闭。

Roblox 组件用作设置按钮。

要构建设置按钮:

  1. 资源管理器 窗口中,找到 StarterGui 中的 HUDContainer

    资源管理器窗口中显示所选的 HUDContainer。
  2. HUDContainer 中插入一个 ImageButton 并将其重命名为 SettingsButton

    资源管理器窗口中显示新的 ImageButton 被插入并重命名为 SettingsButton。 视口中的新 ImageButton。
  3. 选择新按钮,设置以下属性:

    • AnchorPoint = 0.5, 0.25 (水平居中和垂直上四分之一)
    • BackgroundTransparency = 1 (完全透明)
    • Position = 0.5, 0, 0, 0 (顶端居中定位)
    • Size = 0.1, 0, 0.1, 0 (在纵横比受限时占屏幕高度的 10%)
    • Image = rbxassetid://104919049969988 (“齿轮”符号的资产 ID)
  4. 在按钮中插入一个 UIAspectRatioConstraint,使用默认属性(宽高比 1:1)。

    资源管理器窗口中显示新的 UIAspectRatioConstraint 插入到 SettingsButton 按钮中。
  5. 为了限制按钮的最大像素高度,插入一个 UISizeConstraint 并将其 MaxSize 设置为 inf, 44

    资源管理器窗口中显示新的 UISizeConstraint 插入到 SettingsButton 按钮中。
    属性窗口显示新的 UISizeConstraint 的预期值。
    最终设置按钮位于屏幕顶端中间。

创建设置菜单

新的 设置按钮 将被编程用于切换设置菜单的打开和关闭,给玩家按需访问设置或其他信息的机会。在本教程中,菜单将包含交互式滑块,以独立调整背景音频和音效的音量水平。

用于设置菜单的基本组件。

创建父框架

正如在 创建 HUD 仪表 中所指出的,Frame 作为其他 UI 对象的容器。整个设置菜单将构建在一个父框架中,使其易于管理,作为一个有状态对象,根据当前状态以不同方式响应输入。

  1. HUDContainer 中插入一个 Frame 并将其重命名为 SettingsMenu

    资源管理器窗口中显示新框架被插入并重命名为 SettingsMenu。
  2. 选择 SettingsMenu,设置以下属性:

    框架重新定位、调整大小,并以透明海军蓝背景进行样式设计。
  3. SettingsMenu 中插入一个 UIAspectRatioConstraint,并将其 AspectRatio 属性设置为 2.5 (2.5:1 的宽高比)。

    资源管理器窗口中显示新的 UISizeConstraint 插入到 SettingsMenu 框架中。
    属性窗口显示新的 UISizeConstraint 的预期值。
  4. SettingsMenu 中插入 UICorner 修饰符,并将其 CornerRadius 设置为 0.1, 0

    资源管理器窗口中显示新的 UICorner 插入到 SettingsMenu 框架中。
    属性窗口显示新的 UICorner 修饰符的预期值。
  5. 为了限制 SettingsMenu 的像素宽度和高度,插入一个 UISizeConstraint。将其 MaxSize 设置为 800, inf,并将其 MinSize 设置为 350, 0

    资源管理器窗口中显示新的 UISizeConstraint 插入到 SettingsMenu 框架中。
    属性窗口显示新的 UISizeConstraint 的预期值。
    框架样式为圆角。

构建滑块

为了允许玩家调整音量水平,设置菜单将包含两个可拖动的 滑块小部件,由 UIDragDetector 提供支持,这是一个方便的对象,方便与 2D 用户界面元素进行交互。


要为第一个滑块创建一个父容器:

  1. SettingsMenu 容器中插入一个新的 Frame,并将其重命名为 EffectsVolumeSlider

    资源管理器窗口中显示新框架被插入到 SettingsMenu 框架并重命名为 EffectsVolumeSlider。
  2. 选择 EffectsVolumeSlider 框架,设置以下属性:

    插入空框架以容纳滑块元素。
  3. EffectsVolumeSlider 中插入一个新的 UIListLayout。这个布局修饰符是将兄弟 GuiObjects 自动排列到其父容器中的水平行或垂直列内的强大方法,包括应用 flex 概念的能力。

    资源管理器窗口中显示新的 UIListLayout 插入到 EffectsVolumeSlider 框架中。
  4. 为新的 UIListLayout 设置以下属性:

滑块图标

一个简单的图标,包括音频音符和 “爆炸” 符号,帮助玩家识别滑块的目的,当他们打开设置菜单时。

指示滑块在设置菜单中的目的的图标。
  1. EffectsVolumeSlider 框架中插入一个 ImageLabel 并将其重命名为 Icon。这个图标将帮助玩家理解滑块控制的是体验中的哪个方面。

    资源管理器窗口中显示插入到 EffectsVolumeSlider 框架中的 ImageLabel。
  2. 选择 Icon,设置以下属性:

    • BackgroundTransparency = 1 (完全透明)
    • Size = 2.5, 0, 2.5, 0 (最后宽高比例约束后是父框架高度的 250%)
    • Image = rbxassetid://90019827067389 (音频符号和 “爆炸” 符号的资产 ID)
  3. Icon 中插入一个 UIAspectRatioConstraint 并保留其属性为默认值(1:1 宽高比)。

    资源管理器窗口中显示插入到 ImageLabel 中的 UIAspectRatioConstraint。 设置菜单中的最终图标。

范围框架

图标 的右侧,滑块的交互部分必须包含在另一个 Frame 中。

滑块的交互部分的目标大小和位置。
  1. EffectsVolumeSlider 框架中插入一个新的 Frame,并将其重命名为 SliderFrame。请注意,它必须是 UIListLayout 布局修饰符的直接 兄弟

    资源管理器窗口中显示插入到 EffectsVolumeSlider 框架中的子框架。
  2. 选择 SliderFrame,设置以下属性:

  3. SliderFrame 中插入以下修饰符:

    滑块框架位于图标的右侧。

交互手柄

构建好 滑块容器 后,现在可以为玩家创建一个 可拖动的手柄,以便在游戏中进行交互。

交互式滑块手柄位于范围框架内。
  1. SliderFrame 容器中插入一个新的 Frame,并将其重命名为 Handle

    资源管理器窗口中显示滑块框架中的子框架被插入并重新命名为 Handle。
  2. 选择 Handle,设置以下属性:

    • AnchorPoint = 0.5 (中心锚点)
    • Position = 0.5, 0, 0.5, 0 (父框架的水平和垂直中心)
    • Size = 1.2, 0, 1.2, 0 (最后宽高比约束后为父框架高度的 120%)
    • ZIndex = 3 (在其他滑块元素的视觉层前显示手柄)
  3. Handle 中插入以下修饰符:

  4. Handle 中插入一个 UIDragDetector 对象。这个方便的对象促进并鼓励与 2D 用户界面元素的交互。

    资源管理器窗口中显示插入到 Handle 框架中的 UIDragDetector。
  5. 为新的 UIDragDetector 设置以下属性:

  6. 为了确保手柄的线性拖动范围限制在其容器内,将其 BoundingUI 属性链接到 SliderFrame 容器:

    1. 选择 UIDragDetector
    2. 属性 窗口中单击其 BoundingUI 属性。
    3. 资源管理器 窗口中,单击手柄的父 SliderFrame
    链接检测器的 BoundingUI 属性到 SliderFrame 容器的过程。

    现在 BoundingUI 属性链接会反映 SliderFrame 容器:

    属性窗口显示检测器的 BoundingUI 属性链接到 SliderFrame 容器。

如果你现在进行游戏测试,就会在其父容器中左右拖动手柄:

内部填充

为了更清楚地表明滑块控制的是 0% 到 100% 的范围,可以在容器的左侧添加一个 内部填充,这将与手柄的可变位置同步。

插入到 SliderFrame 中的滑块的内部填充部分。
  1. SliderFrame 容器中插入一个新的 Frame,并将其重命名为 InnerFill

    资源管理器窗口中显示子框架插入到 SliderFrame 框架并重命名为 InnerFill。
  2. InnerFill 框架设置以下属性:

  3. 为了匹配父 SliderFrame 容器的“药丸”形状,插入一个 UICorner 修饰符,并将其 CornerRadius 属性设置为 0.5, 0

    资源管理器窗口中显示插入到 InnerFill 框架中的 UICorner 修饰符。
    属性窗口显示新的 UICorner 的预期值。
    InnerFill 框架样式为蓝色背景和圆角。

复制滑块

构建好 第一个滑块 后,可以轻松复制它并修改一些视觉方面以表示另一个目的,这里是背景音频音量由音乐音符图标表示。

背景音频滑块的目标位置。
  1. 选择完整的 EffectsVolumeSlider 对象。

    资源管理器窗口中显示选中的完整 EffectsVolumeSlider。
  2. 复制它 (CtrlDD) 并将副本重命名为 BackgroundVolumeSlider

    资源管理器窗口中显示被复制并重命名为 BackgroundVolumeSlider 的滑块。
  3. 将副本的 Position 更改为 0.5, 0, 0.7, 0,以便将其移动到第一个滑块下方。

    BackgroundVolumeSlider 位于 EffectsVolumeSlider 下方。
  4. 展开 BackgroundVolumeSlider 的顶层分支,选择 Icon 图像标签,并将其 Image 属性更改为 rbxassetid://101125859760167 (音乐音符符号的资产 ID)。

    资源管理器窗口中显示 BackgroundVolumeSlider 中的 Icon 标签。
    属性窗口显示 Icon 标签的预期值。
    背景音量滑块带有修改过的图标图片。
  5. 展开 SliderFrameHandle 分支,选择 Handle 内部的 UIStroke 修饰符,并将其 Color 属性更改为 [255, 0, 125] (洋红色)。

    资源管理器窗口中显示 BackgroundVolumeSlider 手柄内的 UIStroke 修饰符。
    属性窗口显示 UIStroke 修饰符的预期值。
    背景音量滑块带有修改过的图标图片。
  6. 选择 SliderFrame 内的 InnerFill 框架,并将其 BackgroundColor3 属性更改为相同的洋红色 ([255, 0, 125])

    资源管理器窗口中显示 BackgroundVolumeSlider 的 SliderFrame 容器中的 InnerFill 框架。
    属性窗口显示 InnerFill 框架的预期值。
    背景音量滑块带有修改过的 InnerFill 颜色。

创建关闭按钮

设置菜单的最后一个元素是一个 关闭按钮,为玩家提供一个额外的输入来关闭菜单(顶部中间的 SettingsButton 将执行相同的目的)。

设置菜单上方右角指示关闭按钮。
  1. SettingsMenu 容器中插入一个新的 ImageButton,并将其重命名为 CloseButton

    资源管理器窗口中显示插入到 SettingsMenu 的新 ImageButton,并将其重命名为 CloseButton。 空的 ImageButton 位于设置菜单的左上角。
  2. 选择 CloseButton,设置以下属性:

    • AnchorPoint = 1, 0 (右上角)
    • BackgroundTransparency = 1 (完全透明)
    • Position = 1, -10, 0, 10 (距离右上角 10 像素以内)
    • Size = 0.15, 0, 0.15, 0 (在宽高比受到限制后占框架高度的 15%)
    • Image = rbxassetid://5577404210 (关闭按钮符号的资产 ID)
    • ImageTransparency = 0.25 (75% 不透明)
  3. 在按钮中插入一个 UIAspectRatioConstraint,使用默认属性(1:1 宽高比)。

    资源管理器窗口中显示插入到 CloseButton 中的 UIAspectRatioConstraint。 最终的关闭按钮位于设置菜单的右上角。

创建控制模块

可扩展的 控制模块 设置使互动 UI 管理比放置在每个对象中的单个脚本更加简化。 ModuleScripts 通过让你在客户端-服务器边界的不同侧或同一侧之间重用代码来促进这种可扩展功能。

有状态对象控制器

以下有状态对象控制器模块让你可以将行为附加到 UI 对象(如 SettingsButtonSettingsMenu),并轻松切换/动画到不同的状态。要创建该模块:

  1. ReplicatedStorage 中插入一个 ModuleScript 并将其重命名为 StatefulObjectController

    资源管理器窗口中显示 StatefulObjectController 模块在 ReplicatedStorage 容器中。
  2. 将以下代码粘贴到该模块中:

    StatefulObjectController

    local TweenService = game:GetService("TweenService")
    local StatefulObjectController = {}
    StatefulObjectController.__index = StatefulObjectController
    export type StateName = string
    export type State = {
    transition: TweenInfo,
    properties: { [string]: any },
    }
    function StatefulObjectController.hydrate(props: {
    object: Instance,
    states: { [StateName]: State },
    initialStateName: StateName
    })
    local object, states, initialStateName = props.object, props.states, props.initialStateName
    local self = setmetatable({
    states = states,
    currentStateName = initialStateName,
    tweens = {},
    }, StatefulObjectController)
    -- Create tweens for reuse to avoid making new tweens every time state is changed
    for stateName, state in states do
    self.tweens[stateName] = TweenService:Create(object, state.transition, state.properties)
    end
    self:setState(self.currentStateName)
    return self
    end
    function StatefulObjectController:setState(stateName: StateName)
    local stateTween: Tween = self.tweens[stateName]
    if not stateTween then
    warn(string.format("Attempted to set %s to unknown state '%s'", self.object:GetFullName(), stateName))
    return
    end
    self.currentStateName = stateName
    -- Make sure other tweens aren't conflicting
    for _, tween in self.tweens do
    tween:Cancel()
    end
    stateTween:Play()
    end
    return StatefulObjectController
    行数目的
    610定义并导出 Luau 类型,以提高在使用此模块时的自动完成和代码检查。
    1233用于初始化和附加行为到一个有状态的 UI 对象的函数,接受一个 GuiObject 作为 object,一个状态及其各自 TweenInfo 数据的表,以及一个初始状态名称。在此函数内部,行 2628 为每个状态构建 Tweens,行 30 调用模块的 setState() 函数以将对象设置为初始状态。
    3550用于设置 / 更改有状态对象状态的函数。行 42 将对象的 currentStateName 设置为正在设置的状态,行 4547 取消任何正在运行的动画以防止冲突,行 49 执行状态的动画。

滑块控制器

另一个模块初始化并控制两个音量滑块。它还允许你将回调函数连接到每个滑块,以便检测玩家与滑块的交互并在体验中应用所需的更改。

  1. ReplicatedStorage 容器中插入一个 ModuleScript 并将其重命名为 SliderController

    资源管理器窗口中显示 SliderController 模块在 ReplicatedStorage 容器中。
  2. 将以下代码粘贴到该模块中:

    SliderController

    local SliderController = {}
    SliderController.__index = SliderController
    export type Value = number
    export type OnChanged = (Value) -> ()
    function SliderController.hydrate(props: {
    object: Instance,
    onChanged: OnChanged,
    initialValue: Value?
    })
    local object, onChanged, initialValue = props.object, props.onChanged, props.initialValue
    local handle = object:FindFirstChild("Handle", true)
    if not handle then
    warn(string.format("Attempted to hydrate slider %s but couldn't find Handle", object:GetFullName()))
    end
    local innerFill = object:FindFirstChild("InnerFill", true)
    if not innerFill then
    warn(string.format("Attempted to hydrate slider %s but couldn't find InnerFill", object:GetFullName()))
    end
    local dragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
    if not dragDetector then
    warn(string.format("Attempted to hydrate slider %s but couldn't find UIDragDetector", object:GetFullName()))
    end
    local self = setmetatable({
    handle = handle,
    innerFill = innerFill,
    dragDetector = dragDetector,
    value = initialValue or 0.5,
    onChanged = onChanged,
    }, SliderController)
    -- Set initial value
    self:setValue(self.value)
    -- Connect detector to player manipulation
    self.dragConnection = dragDetector.DragContinue:Connect(function()
    self:setValue(handle.Position.X.Scale)
    end)
    return self
    end
    function SliderController:setValue(value: Value)
    local clampedValue = math.clamp(value, 0, 1)
    self.value = clampedValue
    -- Update the handle position and inner frame size to match
    self.handle.Position = UDim2.fromScale(clampedValue, 0.5)
    self.innerFill.Size = UDim2.fromScale(clampedValue, 1)
    -- Run the user's callback with the latest value
    local changeSuccess, changeResult = pcall(self.onChanged, clampedValue)
    if not changeSuccess then
    warn("Error in slider callback:", changeResult)
    end
    end
    return SliderController
    行数目的
    746用于初始化和附加行为到滑块元素的函数,接受滑块的父 Frame 作为 object,一个 onChanged 回调函数来处理滑块更改,以及滑块手柄位置的初始值。在函数内部,行 1427 确认滑块的 手柄内部填充UIDragDetector 元素的存在。行 38 调用模块的 setValue() 函数,行 4143 将拖动检测器的 DragContinue 事件连接到模块的 setValue() 函数(见下一行的详细信息)。
    4861用于设置滑块值的函数。在函数内部,行 5354 确保手柄的位置和内部填充大小同步,行 57 将更改的值传递给回调函数,以便你可以根据需要使用该值。

创建设置脚本

随着 设置按钮设置菜单 的完成,你可以使用一个脚本将一切连接在一起,该脚本利用 控制模块

  1. HUDContainer 中插入一个新的 LocalScript 并将其重命名为 SettingsScript 以描述其用途。请注意,此脚本应位于与 SettingsMenuSettingsButton 同一级别(兄弟),这两个是将要管理的顶层 UI 对象。

    资源管理器窗口中显示 SettingsScript 脚本在 HUDContainer 中。
  2. 将以下代码粘贴到该脚本中:

    SettingsScript

    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local SoundService = game:GetService("SoundService")
    local SliderController = require(ReplicatedStorage.SliderController)
    local StatefulObjectController = require(ReplicatedStorage.StatefulObjectController)
    local HUDContainer = script.Parent
    -- Initialize settings button
    local settingsButton = StatefulObjectController.hydrate({
    object = HUDContainer:FindFirstChild("SettingsButton"),
    states = {
    menuOpen = {
    transition = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),
    properties = {
    Rotation = 45,
    },
    },
    menuClosed = {
    transition = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),
    properties = {
    Rotation = 0,
    },
    },
    },
    initialStateName = "menuClosed"
    })
    -- Initialize settings menu frame
    local settingsMenu = StatefulObjectController.hydrate({
    object = HUDContainer:FindFirstChild("SettingsMenu"),
    states = {
    menuOpen = {
    transition = TweenInfo.new(0.5, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out),
    properties = {
    Position = UDim2.fromScale(0.5, 0.5),
    Visible = true,
    },
    },
    menuClosed = {
    transition = TweenInfo.new(0),
    properties = {
    Position = UDim2.fromScale(0.5, 0.4),
    Visible = false,
    },
    },
    },
    initialStateName = "menuClosed"
    })
    -- Initialize effects volume slider
    local effectsAudio = SoundService:FindFirstChild("Effects")
    local effectsVolumeSlider = SliderController.hydrate({
    object = HUDContainer:FindFirstChild("EffectsVolumeSlider", true),
    initialValue = effectsAudio and effectsAudio.Volume or 0.5,
    onChanged = function(value: SliderController.Value)
    if effectsAudio then
    effectsAudio.Volume = value
    end
    end,
    })
    -- Initialize background volume slider
    local backgroundAudio = SoundService:FindFirstChild("Background")
    local backgroundVolumeSlider = SliderController.hydrate({
    object = HUDContainer:FindFirstChild("BackgroundVolumeSlider", true),
    initialValue = backgroundAudio and backgroundAudio.Volume or 0.5,
    onChanged = function(value: SliderController.Value)
    if backgroundAudio then
    backgroundAudio.Volume = value
    end
    end,
    })
    -- Connect buttons to player interaction
    HUDContainer:FindFirstChild("SettingsButton").Activated:Connect(function()
    local targetState = if settingsButton.currentStateName == "menuClosed"
    then "menuOpen"
    else "menuClosed"
    settingsButton:setState(targetState)
    settingsMenu:setState(targetState)
    end)
    HUDContainer:FindFirstChild("CloseButton", true).Activated:Connect(function()
    settingsButton:setState("menuClosed")
    settingsMenu:setState("menuClosed")
    end)
  3. 参考以下部分来探索该脚本如何利用 控制模块

    10-27 初始化并附加行为到 设置按钮,如下:

    行数目的
    1011声明一个本地引用 settingsButton,并使用 StatefulObjectController.hydrate() 函数对其进行初始化,引用 HUDContainer 中的 SettingsButton 按钮作为要初始化的对象。
    1225传递一个 states 表,其中包含两个唯一状态,menuOpenmenuClosed。每个状态都包含一个过渡,以声明如何通过 properties 表中定义的属性达到特定状态。在这种情况下,menuOpen 声明状态变化到按钮的 Rotation 为 45°,使用 Exponential 的 0.5 秒的动画,而 menuClosed 有效地将按钮恢复到其默认旋转 0
    26按钮的 初始 状态设置为 menuClosed (可以设置为 states 表中的任何状态名称)。

    在脚本的后面(行 76-86),按钮连接到玩家交互以触发 UI 状态更改:

    行数目的
    7682SettingsButton 连接到 Activated 事件,调用一个匿名函数。在匿名函数内部,行 7779menuOpenmenuClosed 之间切换 targetState 变量。行 80 然后调用 setState() 将按钮的状态设置为 targetState,行 81SettingsMenu 执行相同的操作,确保其在激活 SettingsButton 时切换打开或关闭。
    8386CloseButton 连接到 Activated 事件,以调用匿名函数,该函数将 SettingsButtonSettingsMenu 的状态设置为 menuClosed

    30-49 初始化并附加行为到 设置菜单,如下:

    行数目的
    3031声明一个本地引用 settingsMenu,并使用 StatefulObjectController.hydrate() 函数对其进行初始化,引用 HUDContainer 中的 SettingsMenu 框架作为要初始化的对象。
    3246与设置按钮类似,传递一个 states 表,其中包含两个唯一状态,menuOpenmenuClosed。在这里,menuOpen 声明一个状态变化到 UDim2.fromScale(0.5, 0.5),用于框架的 Position,以及 Bounce 0.5 秒的动画,设置 Visible 状态为 true。相反,menuClosed 声明位置状态变化到 UDim2.fromScale(0.5, 0.4) 并将 Visible 设置为 false,但行 41 中的 TweenInfo 设置为持续时间 0,有效地使状态更改立即发生。
    48框架的初始状态设置为 menuClosed

    在脚本的后面(行 76-86),设置菜单连接到玩家交互:

    行数目的
    81SettingsMenu 设置相同的 targetState,以与 SettingsButton 的激活保持同步。
    85当激活 CloseButton 时,将 SettingsMenu 的状态设置为 menuClosed

    51-73 初始化并附加行为到 EffectsVolumeSliderBackgroundVolumeSlider,如下:

    行数目的
    52设置对 EffectsSoundGroupSoundService 中的本地引用。SoundGroup 使你能够将多个 Sounds 关联在一起,并通过该组的 Volume 属性控制组中每个音效的音量。
    5354声明一个本地引用 effectsVolumeSlider,并使用 SliderController.hydrate() 函数对其进行初始化,引用 HUDContainer 中的 EffectsVolumeSlider 框架。请注意,trueFindFirstChild() 第二个参数告诉该方法递归地向下查找 HUDContainer 分支以查找 EffectsVolumeSlider
    55设置滑块的初始值为当前 Effects 声音组的 Volume,或者作为后备 0.5
    5660建立回调函数,以将滑块值更改应用于 Effects 声音组的音量。
    6473基本上与行 52-61 相同,但用于初始化位于 HUDContainer 中的 BackgroundVolumeSlider 框架,并将滑块值更改应用于 Background 声音组的音量。

随着 SettingsScript 的到位,体验现在提供了一个完整的操作互动 UI 示例,将一组相关的 UI 对象与玩家交互链接在一起。

©2026 Roblox Corporation、Roblox、Roblox 标志及 Powering Imagination 是我们在美国及其他国家或地区的注册与未注册商标。