A HUD (ヘッドアップディスプレイ) in your experience commonly displays non‑interactive UI elements such as the health meter demonstrated in Create HUD meters. Atop this, almost every experience requires interactive UI such as buttons that respond to player activation, animate when activated, tween in/out menus with other interactive controls, etc.

Using UI Fundamentals - HUD Meter as a starting place and UI Fundamentals - Interactivity as a finished reference place, this tutorial demonstrates:
- 画面上部に設定ボタンを配置する方法。
- インタラクティブなドラッグ可能なスライダーを含む設定メニューのデザイン。
- 状態を持つ宣言を持つ UI オブジェクトの拡張制御のための「コントローラ」モジュールを形成するための ModuleScripts の使い方。
- ボタンをプレイヤーのアクティベーションに接続して設定メニューを開いたり閉じたりする方法。
- ドラッグ可能な UI スライダーを接続して、音声効果と背景音の音量をそれぞれ調整する方法。
デバイスエミュレーターの有効化
As noted in Create HUD meters, phones and tablets have the least amount of screen space, so it's important that your UI elements fit on smaller screens and that they're clearly visible to players. If you haven't done so already, enable the Device Emulator in Studio:
Open the UI Fundamentals - HUD Meter template in Studio.
From Studio's Test menu, toggle on Device Emulator.
From the bar directly above the main viewport, select a phone emulation such as iPhone X or Samsung Galaxy A51. Then, set the view size to Fit to Window to utilize the maximum space in Studio.

設定ボタンの作成
GuiButtons are interactive user interface elements with built‑in functionality such as the multi‑platform Activated event which fires when the button is clicked or tapped. The GuiButton class extends to two variations, TextButton and ImageButton, and this tutorial uses a "gear" shaped ImageButton to toggle the settings menu open or closed.

To construct the settings button:
In the Explorer window, locate HUDContainer inside StarterGui.

With the new button selected, set the following in the Properties window:
- 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)
Insert a UIAspectRatioConstraint into the button with default properties (1:1 width to height).

To limit the button's maximum pixel height, insert a UISizeConstraint and set its MaxSize to inf, 44.



設定メニューの作成
The new settings button will be scripted to toggle a settings menu open and closed, giving players on‑demand access to settings or other information. In this tutorial, the menu will contain interactive sliders to adjust the volume levels of background audio and sound effects independently.

親フレームの作成
As noted in Create HUD meters, a Frame serves as a container for other UI objects. The entire settings menu will be constructed with a single parent frame, making it simple to manage as a stateful object that reacts to input differently depending on the current state.
Insert a Frame into HUDContainer and rename it SettingsMenu.

With SettingsMenu selected, set the following properties:
- AnchorPoint = 0.5 (中心アンカー)
- BackgroundColor3 = 30, 30, 60 (ネイビーブルー)
- BackgroundTransparency = 0.25 (75% 不透明)
- Position = 0.5, 0, 0.5, 0 (画面の中心)
- Size = 0.75, 0, 0.75, 0 (画面エリアの 75%の幅/高さ)

Insert a UIAspectRatioConstraint into SettingsMenu and set its AspectRatio property to 2.5. (2.5:1 width to height).


Insert a UICorner modifier into SettingsMenu and set its CornerRadius to 0.1, 0.


To constrain the pixel width and height of SettingsMenu, insert a UISizeConstraint. Set its MaxSize to 800, inf and its MinSize to 350, 0.



スライダーの構築
To allow players to adjust volume levels, the settings menu will contain two draggable slider widgets powered by UIDragDetector, a convenient object that facilitates interaction with 2D user interface elements.
To create a parent container for the first slider:
Insert a new Frame into the SettingsMenu container and rename it EffectsVolumeSlider.

With the EffectsVolumeSlider frame selected, set the following properties:
- AnchorPoint = 0.5 (中心アンカー)
- BackgroundTransparency = 1 (完全に透明)
- Position = 0.5, 0, 0.35, 0 (水平中央およびコンテナの上から 35%)
- Size = 0.8, 0, 0.1, 0 (コンテナの幅の 80%および高さの 10%)

Insert a new UIListLayout into EffectsVolumeSlider. This layout modifier is a powerful way to auto‑arrange sibling GuiObjects into horizontal rows or vertical columns within their parent container, including the ability to apply flex concepts.

Set the following properties for the new UIListLayout:
- Padding = 0.06, 0 (リスト要素の間の 6%のパディング)
- FillDirection = Horizontal (左から右への要素の配置)
- HorizontalFlex = Fill (親コンテナ全体を埋めるために要素の幅を再調整)
- VerticalAlignment = Center (要素を垂直方向で中央に整列)
スライダーアイコン
A simple icon including an audio note and "burst" symbol helps players identify the slider's purpose when they open the settings menu.

Insert an ImageLabel into the EffectsVolumeSlider frame and rename it to Icon. This icon will help players understand what in‑experience aspect the slider controls.

With Icon selected, set the following properties:
- BackgroundTransparency = 1 (完全に透明)
- Size = 2.5, 0, 2.5, 0 (アスペクト比が制約された場合、親フレームの 250%の高さ)
- Image = rbxassetid://90019827067389 (音声ノートと「バースト」シンボルのアセット ID)
Insert a UIAspectRatioConstraint into Icon and leave its properties as the defaults (1:1 width to height).


範囲フレーム
Directly to the right of the icon, the interactive portion of the slider should be contained within another Frame.

Insert a new Frame into the EffectsVolumeSlider frame and rename it SliderFrame. Note that it must be a direct sibling of the UIListLayout layout modifier.

With SliderFrame selected, set the following properties:
- BackgroundColor3 = 0 (黒)
- BackgroundTransparency = 0.75 (25% 不透明)
- LayoutOrder = 1
- Size = 1, 0, 1, 0 (親フレームの幅/高さの 100%)
Insert the following modifiers into SliderFrame:

インタラクティブハンドル
With the slider container constructed, you can now create a draggable handle for players to interact with during gameplay.

Insert a new Frame into the SliderFrame container and rename it to Handle.

With Handle selected, set the following properties:
- AnchorPoint = 0.5 (中心アンカー)
- Position = 0.5, 0, 0.5, 0 (親フレームの中央)
- Size = 1.2, 0, 1.2, 0 (アスペクト比が制約された場合、親フレームの 120%の高さ)
- ZIndex = 3 (視覚的に他のスライダー要素の前に表示)
Insert the following modifiers into Handle:
- UIAspectRatioConstraint with its default properties (1:1 width to height)
Insert a UIDragDetector object into Handle. This convenient object facilitates and encourages interaction with 2D user interface elements.

Set the following properties for the new UIDragDetector:
- ResponseStyle = Scale (デテクターの親の位置のスケール値で移動)
To ensure the handle's linear drag range is limited to its container, link its BoundingUI property to the SliderFrame container:
- Select the UIDragDetector.
- Click its BoundingUI property in the Properties window.
- Back in the Explorer window, click the handle's parent SliderFrame.

The BoundingUI property link now reflects the SliderFrame container:

If you playtest the experience now, you'll be able to drag the handle left and right within its parent container:
インナー填充
To more clearly indicate that the slider controls a 0% to 100% range, you can add an inner fill to the left side of the container which will sync with the handle's variable position.

Insert a new Frame into the SliderFrame container and rename it to InnerFill.

Set the following properties for the InnerFill frame:
- AnchorPoint = 0, 0.5 (左端および垂直中心)
- BackgroundColor3 = [0, 150, 255] (スライダーハンドルに合う青)
- BackgroundTransparency = 0.35 (65% 不透明)
- Position = 0, 0, 0.5, 0
- Size = 0.5, 0, 1, 0 (幅 50%および高さ 100%の親フレーム)
- ZIndex = 2 (親フレームの填充/アウトラインの前に視覚的にレイヤー)
To match the "pill" shape of the parent SliderFrame container, insert a UICorner modifier and set its CornerRadius property to 0.5, 0.



スライダーの複製
With the first slider constructed, you can easily duplicate it and modify some visual aspects to indicate another purpose, in this case the volume level of background audio symbolized by an icon of musical notes.

Select the completed EffectsVolumeSlider object.

Duplicate it (CtrlD or ⌘D) and then rename the duplicate to BackgroundVolumeSlider.

Change the duplicate's Position to 0.5, 0, 0.7, 0 to move it below the first slider.

Expand the top-level branch of BackgroundVolumeSlider, select the Icon image label, and change its Image property to rbxassetid://101125859760167 (アセット ID の音符のシンボル)。



Select the InnerFill frame within SliderFrame and change its BackgroundColor3 property to the same magenta color ([255, 0, 125]).



閉じるボタンの作成
The final element of the settings menu is a close button which provides players an additional input to close the menu (the SettingsButton in the top‑center will serve the same purpose).

With CloseButton selected, set the following properties:
- 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% 不透明)
コントロールモジュールの作成
An extensible control module setup makes interactive UI management more streamlined than individual scripts placed within each object. ModuleScripts facilitate this extensible functionality by letting you reuse code between scripts on different sides of the client‑server boundary or the same side of the boundary.
状態を持つオブジェクトコントローラ
The following stateful object controller module lets you attach behavior to UI objects such as SettingsButton and SettingsMenu, and easily toggle/tween between various states. To create the module:
- Insert a ModuleScript into the ReplicatedStorage container and rename it to StatefulObjectController.

Paste the following code inside the module:
StatefulObjectControllerlocal TweenService = game:GetService("TweenService")local StatefulObjectController = {}StatefulObjectController.__index = StatefulObjectControllerexport type StateName = stringexport 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.initialStateNamelocal self = setmetatable({states = states,currentStateName = initialStateName,tweens = {},}, StatefulObjectController)-- Create tweens for reuse to avoid making new tweens every time state is changedfor stateName, state in states doself.tweens[stateName] = TweenService:Create(object, state.transition, state.properties)endself:setState(self.currentStateName)return selfendfunction StatefulObjectController:setState(stateName: StateName)local stateTween: Tween = self.tweens[stateName]if not stateTween thenwarn(string.format("Attempted to set %s to unknown state '%s'", self.object:GetFullName(), stateName))returnendself.currentStateName = stateName-- Make sure other tweens aren't conflictingfor _, tween in self.tweens dotween:Cancel()endstateTween:Play()endreturn StatefulObjectControllerコードの説明行 目的 6‑10 このモジュールを使用する際のオートコンプリートとリンティングを改善するためにLuau型を定義し、エクスポートします。 12‑33 状態を持つUIオブジェクトに行動を初期化して接続するために使用される関数で、GuiObjectをobjectとして、状態とそれに関連するTweenInfoデータのテーブルと初期状態名を受け取ります。この関数内部で、26‑28行は各状態のTweensを構築し、30行でモジュールのsetState()関数を呼び出してオブジェクトを初期状態に設定します。 35‑50 状態を持つオブジェクトの状態を設定/変更するために使用される関数。42行ではオブジェクトのcurrentStateNameを設定されている状態に設定し、45‑47行で実行中のツイーンをキャンセルして競合を防ぎ、49行で状態のツイーンを実行します。
スライダーコントローラ
An additional module initializes and controls the two volume sliders. It also allows you to connect a callback function to each slider in order to detect player interaction with the slider and apply desired changes in the experience.
Insert a ModuleScript into the ReplicatedStorage container and rename it to SliderController.

Paste the following code inside the module:
SliderControllerlocal SliderController = {}SliderController.__index = SliderControllerexport type Value = numberexport type OnChanged = (Value) -> ()function SliderController.hydrate(props: {object: Instance,onChanged: OnChanged,initialValue: Value?})local object, onChanged, initialValue = props.object, props.onChanged, props.initialValuelocal handle = object:FindFirstChild("Handle", true)if not handle thenwarn(string.format("Attempted to hydrate slider %s but couldn't find Handle", object:GetFullName()))endlocal innerFill = object:FindFirstChild("InnerFill", true)if not innerFill thenwarn(string.format("Attempted to hydrate slider %s but couldn't find InnerFill", object:GetFullName()))endlocal dragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")if not dragDetector thenwarn(string.format("Attempted to hydrate slider %s but couldn't find UIDragDetector", object:GetFullName()))endlocal self = setmetatable({handle = handle,innerFill = innerFill,dragDetector = dragDetector,value = initialValue or 0.5,onChanged = onChanged,}, SliderController)-- set initial valueself:setValue(self.value)-- Connect detector to player manipulationself.dragConnection = dragDetector.DragContinue:Connect(function()self:setValue(handle.Position.X.Scale)end)return selfendfunction SliderController:setValue(value: Value)local clampedValue = math.clamp(value, 0, 1)self.value = clampedValue-- Update the handle position and inner frame size to matchself.handle.Position = UDim2.fromScale(clampedValue, 0.5)self.innerFill.Size = UDim2.fromScale(clampedValue, 1)-- Run the user's callback with the latest valuelocal changeSuccess, changeResult = pcall(self.onChanged, clampedValue)if not changeSuccess thenwarn("Error in slider callback:", changeResult)endendreturn SliderControllerコードの説明行 目的 7‑46 スライダー要素に行動を初期化して接続するために使用される関数で、スライダーの親Frameをobjectとして、スライダーの変更を処理するためのonChangedコールバック関数とスライダーハンドル位置の初期値を受け取ります。内部の14‑27行は、スライダーのハンドル、インナー填充、およびUIDragDetector要素が存在することを確認します。38行はモジュールのsetValue()関数を呼び出し、41‑43行はドラッグデテクタのDragContinueイベントをモジュールのsetValue()関数に接続します(次の行で説明)。 48‑61 スライダーの値を設定するために使用される関数。内部の53‑54行はハンドルの位置とインナー填充サイズを同期し、57行は変更された値をコールバック関数に渡し、必要に応じてその値を利用できるようにします。
設定スクリプトの作成
With the settings button and settings menu finalized, you can hook everything together with a single script that utilizes the control modules.
Insert a new LocalScript into HUDContainer and rename it to SettingsScript to describe its purpose. Note that this script should be at the same level (sibling) as SettingsMenu and SettingsButton, the top‑level UI objects it will manage.

Paste the following code inside the script:
SettingsScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local SoundService = game:GetService("SoundService")local SliderController = require(ReplicatedStorage.SliderController)local StatefulObjectController = require(ReplicatedStorage.StatefulObjectController)local HUDContainer = script.Parent-- 調整ボタンの初期化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"})-- 設定メニューフレームの初期化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"})-- 効果音ボリュームスライダーの初期化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 theneffectsAudio.Volume = valueendend,})-- 背景音ボリュームスライダーの初期化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 thenbackgroundAudio.Volume = valueendend,})-- ボタンをプレイヤーのインタラクションに接続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)Reference the following sections to explore how the script utilizes the control modules.
設定ボタンLines 10-27 initialize and attach behavior to the settings button as follows:
行 目的 10‑11 ローカル参照settingsButtonが宣言され、StatefulObjectController.hydrate()関数で水和され、SettingsButtonボタンがHUDContainer内のオブジェクトとして参照されます。 12‑25 2つのユニークな状態、menuOpenとmenuClosedを含むstatesテーブルが渡されます。この場合、menuOpenはボタンのRotationの45°への状態変更を宣言し、Exponentialツイーンで0.5秒の間に、menuClosedはボタンをデフォルトの回転0に戻すことを宣言します。 26 ボタンの初期状態がmenuClosedに設定されます(この状態の名前はstatesテーブル内の任意の名前で設定可能です)。 Further down in the script (lines 76-86), buttons are connected to player interaction to trigger UI state changes:
設定メニューLines 30-49 initialize and attach behavior to the settings menu as follows:
行 目的 30‑31 ローカル参照settingsMenuが宣言され、StatefulObjectController.hydrate()関数で水和され、SettingsMenuフレームがHUDContainer内のオブジェクトとして参照されます。 32‑46 設定ボタンと同様に、statesテーブルが渡され、menuOpenとmenuClosedという2つのユニークな状態が含まれます。ここで、menuOpenはフレームのPositionがUDim2.fromScale(0.5, 0.5)に状態変更を宣言し、Bounceツイーンで0.5秒の間に、Visible状態がtrueとなります。対照的に、menuClosedでは位置がUDim2.fromScale(0.5, 0.4)に状態変更され、Visibleはfalseに変更されますが、TweenInfoの0の期間が事実上、状態変更を瞬時に発生させます。 48 フレームの初期状態がmenuClosedに設定されます。 Further down in the script (lines 76-86), the settings menu is linked to player interaction:
行 目的 81 SettingsMenuの状態をtargetStateとして設定し、SettingsButtonのアクティブ化によって同期させます。 85 CloseButtonがアクティブ化されると、SettingsMenuの状態をmenuClosedに設定します。 ボリュームスライダーLines 51-73 initialize and attach behavior to EffectsVolumeSlider and BackgroundVolumeSlider as follows:
行 目的 52 ローカル参照をEffectsのSoundGroupに設定します。SoundGroupを使用すると、複数のSoundsを相互に関連付け、グループのVolumeプロパティを通じてグループ内のすべてのサウンドの音量を制御できます。 53‑54 ローカル参照effectsVolumeSliderが宣言され、SliderController.hydrate()関数でHUDContainer ⟩ SettingsMenu内のEffectsVolumeSliderフレームをオブジェクトとしてハイドレートします。trueという2番目のパラメータは、FindFirstChild()メソッドにHUDContainerブランチを再帰的に検索させ、EffectsVolumeSliderを見つけるように指示します。 55 スライダーの初期値は、Effectsサウンドグループの現在のVolumeに設定され、フォールバックとして0.5が使用されます。 56‑60 スライダーの値の変更をEffectsサウンドグループの音量に適用するためのコールバック関数を設定します。 64‑73 基本的には52-61行と同様ですが、HUDContainer ⟩ SettingsMenu内のBackgroundVolumeSliderフレームをハイドレートし、スライダーの値の変更をBackgroundサウンドグループの音量に適用します。
SettingsScriptが整備されることで、体験はプレイヤーの対話に関連する UI オブジェクトのセットをリンクする完全に機能するインタラクティブ UI の例を提供します。








