中级教程

创建交互式用户界面

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

在您的游戏中,HUD抬头显示)通常显示非交互式的用户界面元素,例如在 创建 HUD 计量器 中演示的健康计量器。除此之外,几乎每个游戏都需要交互式用户界面,例如响应玩家激活的按钮、在激活时动画、与其他交互控件一起淡入/淡出的菜单等。

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

使用 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)。

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

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

创建设置菜单

新的 设置按钮 将被编写脚本以切换设置菜单的打开和关闭,给玩家提供按需访问设置或其他信息的功能。在本教程中,菜单将包含可交互的滑块,以独立调整背景音频和音效的音量级别。

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

创建父框架

创建 HUD 计量器 中所述,Frame 作为其他 UI 对象的容器。整个设置菜单将通过一个父框架构建,使其作为一个有状态对象简单易于管理,根据当前状态对输入做出不同反应。

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

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

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

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

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

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

构建滑块

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


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

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

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

  3. EffectsVolumeSlider 中插入一个新的 UIListLayout。这个布局修饰符是将兄弟 GuiObjects 自动排列成水平行或垂直列的强大方法,包括应用 flex 概念的能力。

    资源管理器窗口显示插入到 EffectsVolumeSlider 框架中的新 UIListLayout。
  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

    资源管理器窗口显示插入到 SliderFrame 框架中的子框架并重命名为 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 标签的预期值。
    BackgroundVolumeSlider 的图标图像已修改。
  5. 展开 SliderFrameHandle 分支,选择其中的 UIStroke 修饰符,并将其 Color 属性设置为 [255, 0, 125](品红色)。

    资源管理器窗口显示 BackgroundVolumeSlider 的手柄中的 UIStroke 修饰符。
    属性窗口显示 UIStroke 修饰符的预期值。
    BackgroundVolumeSlider 的手柄已修改。
  6. 选择 SliderFrame 中的 InnerFill 框架,并将其 BackgroundColor3 属性更改为相同的品红色 ([255, 0, 125])

    资源管理器窗口显示 BackgroundVolumeSlider 的 SliderFrame 中的 InnerFill 框架。
    属性窗口显示 InnerFill 框架的预期值。
    BackgroundVolumeSlider 的 InnerFill 颜色已修改。

创建关闭按钮

设置菜单的最后一个元素是 关闭按钮,为玩家提供额外的输入以关闭菜单(顶部中心的 SettingsButton 将起到相同的作用)。

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

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

  3. 在按钮中插入一个 UIAspectRatioConstraint,并保持默认属性(宽高比为 1:1)。

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

创建控制模块

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

有状态对象控制器

以下有状态对象控制器模块允许您将行为附加到 UI 对象,例如 SettingsButtonSettingsMenu,并轻松在各种状态之间切换/过渡。要创建模块:

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

    资源管理器窗口显示 ReplicatedStorage 容器中的 StatefulObjectController 模块。
  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

    资源管理器窗口显示 ReplicatedStorage 容器中的 SliderController 模块。
  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 对象。

    资源管理器窗口显示 HUDContainer 容器中的 SettingsScript 脚本。
  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。每个状态都包含一个过渡,以声明(通过 TweenInfo)特定状态将如何达到在 properties 表中定义的目标属性。在这种情况下,menuOpen 声明状态更改为按钮的 Rotation 为 45°,并使用 Exponential 的半秒过渡,而 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 的半秒过渡,以及 Visible 状态为 true。相反,menuClosed 声明位置状态更改为 UDim2.fromScale(0.5, 0.4),并将 Visible 设置为 false,但第 41 行的 TweenInfo 的持续时间为 0,有效地使状态更改立即发生。
    48框架的初始状态设置为 menuClosed

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

    目的
    81SettingsMenu 设置相同的 targetState,以便与 SettingsButton 的激活同步。
    85CloseButton 被激活时,将 SettingsMenu 的状态设置为 menuClosed

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

    目的
    52将本地引用设置为 SoundGroup 中的 Effects,该组位于 SoundService 中。SoundGroup 允许您相互关联多个 Sounds,并通过组的 Volume 属性控制组中每个声音的音量。
    5354声明一个本地引用 effectsVolumeSlider,并使用 SliderController.hydrate() 函数进行初始化,HUDContainer 中的 EffectsVolumeSlider 框架被引用为要初始化的对象。请注意,FindFirstChild() 的第二个参数为 true,告诉该方法递归查找 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 是我们在美国及其他国家或地区的注册与未注册商标。