대화형 UI 만들기

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

게임의 HUD (Heads-Up Display)는 일반적으로 HUD 미터 만들기에서 보여준 건강 미터와 같은 비대화형 UI 요소를 표시합니다. 이와 함께 거의 모든 게임은 플레이어의 활성화에 반응하고, 활성화될 때 애니메이션을 실행하며, 다른 대화형 컨트롤과 함께 메뉴를 트윈 인/아웃하는 버튼과 같은 대화형 UI를 필요로 합니다.

설정 버튼과 볼륨 슬라이더가 있는 설정 메뉴를 보여주는 게임 내 보기.

UI 기초 - HUD 미터를 시작점으로 하고 UI 기초 - 대화형을 완성된 참조로 사용하여, 이 튜토리얼에서는 다음을 보여줍니다:

  • 화면 상단 가장자리에 설정 버튼을 배치하는 방법.
  • 대화형 드래그 가능한 슬라이더가 포함된 설정 메뉴 디자인.
  • 상태가 있는 선언으로 UI 객체를 확장 가능하게 제어하기 위한 "컨트롤러" 모듈을 형성하기 위해 ModuleScripts를 사용하는 방법.
  • 버튼을 플레이어 활성화에 연결하여 설정 메뉴를 트글 인/아웃하는 방법.
  • 드래그 가능한 UI 슬라이더를 연결하여 효과음과 배경 음향의 볼륨을 별도로 조정하는 방법.

장치 에뮬레이터 활성화

HUD 미터 만들기에서 언급했듯이, 전화기와 태블릿은 화면 공간이 가장 적기 때문에 UI 요소가 더 작은 화면에 맞고 플레이어에게 명확하게 보이도록 하는 것이 중요합니다. 아직 하지 않았다면, Studio에서 장치 에뮬레이터를 활성화하세요:

  1. Studio에서 UI 기초 - HUD 미터 템플릿을 엽니다.

  2. Studio의 테스트 메뉴에서 장치 에뮬레이터를 켭니다.

  3. 메인 뷰포트 바로 위의 바에서 iPhone X 또는 Samsung Galaxy A51과 같은 전화 에뮬레이션을 선택합니다. 그런 다음, 창에 맞추기로 보기 크기를 설정하여 Studio에서 최대 공간을 활용합니다.

    뷰포트 창 상단에 표시된 장치 에뮬레이터 설정 옵션.

설정 버튼 만들기

GuiButtons는 클릭되거나 탭될 때 발생하는 멀티 플랫폼 Activated 이벤트와 같은 내장 기능을 가진 대화형 사용자 인터페이스 요소입니다. GuiButton 클래스는 TextButtonImageButton의 두 가지 변형으로 확장되며, 이 튜토리얼에서는 설정 메뉴를 열거나 닫기 위해 "기어" 모양의 ImageButton을 사용합니다.

설정 버튼에 사용된 Roblox 구성 요소.

설정 버튼을 구성하려면:

  1. Explorer 창에서 StarterGui 내의 HUDContainer를 찾습니다.

    선택된 HUDContainer를 보여주는 Explorer 창.
  2. HUDContainerImageButton을 삽입하고 이름을 SettingsButton으로 변경합니다.

    새로운 ImageButton이 삽입되고 SettingsButton으로 이름이 변경된 Explorer 창. 뷰포트에 있는 새로운 ImageButton.
  3. 새 버튼을 선택한 상태에서 속성 창에서 다음을 설정합니다:

    • AnchorPoint = 0.5, 0.25 (수평 중앙 및 수직 상단 1/4)
    • 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를 보여주는 Explorer 창.
  5. 버튼의 최대 픽셀 높이를 제한하기 위해 UISizeConstraint를 삽입하고 MaxSizeinf, 44로 설정합니다.

    SettingsButton 버튼에 삽입된 새로운 UISizeConstraint를 보여주는 Explorer 창.
    새로운 UISizeConstraint에 대한 예상 값을 보여주는 속성 창.
    화면 상단 중앙에 위치한 최종 설정 버튼.

설정 메뉴 만들기

새로운 설정 버튼은 설정 메뉴를 열고 닫는 스크립트가 작성될 것이며, 플레이어에게 설정이나 기타 정보에 대한 즉각적인 접근을 제공합니다. 이 튜토리얼에서는 메뉴에 배경 오디오와 효과음의 볼륨 레벨을 독립적으로 조정할 수 있는 대화형 슬라이더가 포함됩니다.

설정 메뉴에 사용된 기본 구성 요소.

부모 프레임 만들기

HUD 미터 만들기에서 언급했듯이, Frame는 다른 UI 객체의 컨테이너 역할을 합니다. 전체 설정 메뉴는 단일 부모 프레임으로 구성되어, 현재 상태에 따라 입력에 다르게 반응하는 상태가 있는 객체로 관리하기 쉽게 만듭니다.

  1. HUDContainerFrame을 삽입하고 이름을 SettingsMenu로 변경합니다.

    SettingsMenu로 이름이 변경된 새로운 프레임이 삽입된 Explorer 창.
  2. SettingsMenu가 선택된 상태에서 다음 속성을 설정합니다:

    투명한 네이비 블루 배경으로 재배치되고 크기가 조정된 프레임.
  3. SettingsMenuUIAspectRatioConstraint를 삽입하고 AspectRatio 속성을 2.5로 설정합니다. (너비 대 높이 비율 2.5:1).

    SettingsMenu 프레임에 삽입된 새로운 UISizeConstraint를 보여주는 Explorer 창.
    새로운 UISizeConstraint에 대한 예상 값을 보여주는 속성 창.
  4. SettingsMenu의 픽셀 너비와 높이를 제한하기 위해 UISizeConstraint를 삽입합니다. MaxSize800, inf로 설정하고 MinSize350, 0로 설정합니다.

    SettingsMenu 프레임에 삽입된 새로운 UISizeConstraint를 보여주는 Explorer 창.
    새로운 UISizeConstraint에 대한 예상 값을 보여주는 속성 창.
    모서리가 둥근 스타일의 프레임.

슬라이더 구성

플레이어가 볼륨 레벨을 조정할 수 있도록 설정 메뉴에는 UIDragDetector로 구동되는 두 개의 드래그 가능한 슬라이더 위젯이 포함됩니다. 이는 2D 사용자 인터페이스 요소와의 상호작용을 용이하게 하는 편리한 객체입니다.


첫 번째 슬라이더의 부모 컨테이너를 만들려면:

  1. SettingsMenu 컨테이너에 새로운 Frame을 삽입하고 이름을 EffectsVolumeSlider로 변경합니다.

    SettingsMenu 프레임에 삽입된 새로운 프레임, 이름이 EffectsVolumeSlider로 변경됨.
  2. EffectsVolumeSlider 프레임이 선택된 상태에서 다음 속성을 설정합니다:

    • AnchorPoint = 0.5 (중앙 앵커)

    • BackgroundTransparency = 1 (완전히 투명)

    • Position = 0.5, 0, 0.35, 0 (수평 중앙 및 컨테이너의 상단에서 35%)

    • Size = 0.8, 0, 0.1, 0 (컨테이너 너비의 80% 및 높이의 10%)

      슬라이더 요소를 포함할 빈 프레임이 삽입됨.
  3. EffectsVolumeSlider에 새로운 UIListLayout을 삽입합니다. 이 레이아웃 수정자는 형제 GuiObjects를 부모 컨테이너 내에서 수평 행 또는 수직 열로 자동 정렬하는 강력한 방법으로, 플렉스 개념을 적용할 수 있습니다.

    EffectsVolumeSlider 프레임에 삽입된 새로운 UIListLayout을 보여주는 Explorer 창.
  4. 새로운 UIListLayout에 대해 다음 속성을 설정합니다:

슬라이더 아이콘

간단한 아이콘에는 오디오 노트와 "버스트" 기호가 포함되어 있어 플레이어가 설정 메뉴를 열 때 슬라이더의 목적을 식별하는 데 도움이 됩니다.

설정 메뉴에서 슬라이더의 목적을 나타내는 아이콘.
  1. EffectsVolumeSlider 프레임에 ImageLabel을 삽입하고 이름을 Icon으로 변경합니다. 이 아이콘은 플레이어가 슬라이더가 제어하는 게임 측면을 이해하는 데 도움이 됩니다.

    EffectsVolumeSlider 프레임에 삽입된 ImageLabel을 보여주는 Explorer 창.
  2. Icon이 선택된 상태에서 다음 속성을 설정합니다:

    • BackgroundTransparency = 1 (완전히 투명)
    • Size = 2.5, 0, 2.5, 0 (비율이 제한된 후 부모 프레임의 250% 높이)
    • Image = rbxassetid://90019827067389 (오디오 노트와 "버스트" 기호의 자산 ID)
  3. IconUIAspectRatioConstraint를 삽입하고 속성을 기본값으로 유지합니다 (1:1 너비 대 높이).

    ImageLabel에 삽입된 UIAspectRatioConstraint를 보여주는 Explorer 창. 설정 메뉴에서 최종 아이콘.

범위 프레임

아이콘 바로 오른쪽에, 슬라이더의 대화형 부분은 또 다른 Frame 내에 포함되어야 합니다.

슬라이더의 대화형 부분의 목표 크기와 위치.
  1. EffectsVolumeSlider 프레임에 새로운 Frame을 삽입하고 이름을 SliderFrame으로 변경합니다. 이는 UIListLayout의 직접 형제여야 합니다.

    EffectsVolumeSlider 프레임에 삽입된 자식 프레임을 보여주는 Explorer 창.
  2. SliderFrame이 선택된 상태에서 다음 속성을 설정합니다:

  3. SliderFrame에 다음 수정자를 삽입합니다:

    아이콘 오른쪽에 위치한 슬라이더 프레임.

대화형 핸들

슬라이더 컨테이너가 구성되었으므로, 이제 플레이어가 게임 중에 상호작용할 수 있는 드래그 가능한 핸들을 만들 수 있습니다.

범위 프레임 내에 위치한 대화형 슬라이더 핸들.
  1. SliderFrame 컨테이너에 새로운 Frame을 삽입하고 이름을 Handle로 변경합니다.

    SliderFrame 프레임에 삽입된 자식 프레임을 보여주는 Explorer 창, 이름이 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. HandleUIDragDetector 객체를 삽입합니다. 이 편리한 객체는 2D 사용자 인터페이스 요소와의 상호작용을 용이하게 하고 장려합니다.

    Handle 프레임에 삽입된 UIDragDetector를 보여주는 Explorer 창.
  5. 새로운 UIDragDetector에 대해 다음 속성을 설정합니다:

  6. 핸들의 선형 드래그 범위가 컨테이너로 제한되도록 BoundingUI 속성을 SliderFrame 컨테이너에 연결합니다:

    1. UIDragDetector를 선택합니다.
    2. 속성 창에서 BoundingUI 속성을 클릭합니다.
    3. Explorer 창에서 핸들의 부모 SliderFrame을 클릭합니다.
    탐지기의 BoundingUI 속성을 SliderFrame 컨테이너에 연결하는 과정을 보여주는 다이어그램.

    이제 BoundingUI 속성 링크가 SliderFrame 컨테이너를 반영합니다:

    탐지기의 BoundingUI 속성이 SliderFrame 컨테이너에 연결된 속성 창.

이제 게임을 플레이 테스트하면 핸들을 부모 컨테이너 내에서 왼쪽과 오른쪽으로 드래그할 수 있습니다:

내부 채우기

슬라이더가 0%에서 100% 범위를 제어한다는 것을 더 명확하게 나타내기 위해, 핸들의 가변 위치와 동기화되는 내부 채우기를 컨테이너의 왼쪽에 추가할 수 있습니다.

SliderFrame에 삽입된 슬라이더의 내부 채우기 부분.
  1. SliderFrame 컨테이너에 새로운 Frame을 삽입하고 이름을 InnerFill로 변경합니다.

    SliderFrame 프레임에 삽입된 자식 프레임을 보여주는 Explorer 창, 이름이 InnerFill로 변경됨.
  2. InnerFill 프레임에 대해 다음 속성을 설정합니다:

    • 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 (부모 프레임의 채우기/윤곽선 앞에 시각적으로 레이어링)
  3. 부모 SliderFrame 컨테이너의 "알약" 모양과 일치하도록 UICorner 수정자를 삽입하고 CornerRadius 속성을 0.5, 0로 설정합니다.

    InnerFill 프레임에 삽입된 UICorner 수정자를 보여주는 Explorer 창.
    새로운 UICorner에 대한 예상 값을 보여주는 속성 창.
    파란색 배경과 둥근 모서리로 스타일링된 InnerFill 프레임.

슬라이더 복제

첫 번째 슬라이더가 구성되었으므로, 이를 쉽게 복제하고 다른 목적을 나타내기 위해 일부 시각적 측면을 수정할 수 있습니다. 이 경우, 음악 노트 아이콘으로 상징되는 배경 오디오의 볼륨 레벨입니다.

배경 오디오 슬라이더의 목표 위치.
  1. 완료된 EffectsVolumeSlider 객체를 선택합니다.

    완료된 EffectsVolumeSlider가 선택된 Explorer 창.
  2. 이를 복제합니다 (CtrlD 또는 D) 그리고 복제된 이름을 BackgroundVolumeSlider로 변경합니다.

    복제된 슬라이더가 BackgroundVolumeSlider로 이름이 변경된 Explorer 창.
  3. 복제된 Position0.5, 0, 0.7, 0로 변경하여 첫 번째 슬라이더 아래로 이동합니다.

    EffectsVolumeSlider 아래에 위치한 BackgroundVolumeSlider.
  4. BackgroundVolumeSlider의 최상위 브랜치를 확장하고 Icon 이미지 레이블을 선택한 후, Image 속성을 rbxassetid://101125859760167 (음악 노트가 있는 기호의 자산 ID)로 변경합니다.

    BackgroundVolumeSlider 내의 Icon 레이블을 보여주는 Explorer 창.
    Icon 레이블에 대한 예상 값을 보여주는 속성 창.
    수정된 아이콘 이미지를 가진 BackgroundVolumeSlider.
  5. SliderFrameHandle 브랜치를 확장하고 그 안의 UIStroke 수정자를 선택한 후, Color 속성을 [255, 0, 125] (마젠타)로 설정합니다.

    BackgroundVolumeSlider의 핸들 내 UIStroke 수정자를 보여주는 Explorer 창.
    UIStroke 수정자에 대한 예상 값을 보여주는 속성 창.
    수정된 아이콘 이미지를 가진 BackgroundVolumeSlider.
  6. SliderFrame 내의 InnerFill 프레임을 선택하고 BackgroundColor3 속성을 동일한 마젠타 색상 ([255, 0, 125])으로 변경합니다.

    BackgroundVolumeSlider의 SliderFrame 컨테이너 내 InnerFill 프레임을 보여주는 Explorer 창.
    InnerFill 프레임에 대한 예상 값을 보여주는 속성 창.
    수정된 InnerFill 색상을 가진 BackgroundVolumeSlider.

닫기 버튼 만들기

설정 메뉴의 마지막 요소는 메뉴를 닫기 위한 추가 입력을 제공하는 닫기 버튼입니다 (상단 중앙의 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를 보여주는 Explorer 창. 설정 메뉴의 오른쪽 상단 모서리에 위치한 최종 닫기 버튼.

제어 모듈 만들기

확장 가능한 제어 모듈 설정은 각 객체에 개별 스크립트를 배치하는 것보다 대화형 UI 관리를 더 간소화합니다. ModuleScripts는 클라이언트-서버 경계의 서로 다른 측면 또는 경계의 동일한 측면에서 스크립트 간에 코드를 재사용할 수 있도록 하여 이 확장 가능한 기능을 촉진합니다.

상태가 있는 객체 컨트롤러

다음 상태가 있는 객체 컨트롤러 모듈은 SettingsButtonSettingsMenu와 같은 UI 객체에 동작을 부착하고 다양한 상태 간에 쉽게 전환/트윈할 수 있게 해줍니다. 모듈을 만들려면:

  1. ReplicatedStorage 컨테이너에 ModuleScript를 삽입하고 이름을 StatefulObjectController로 변경합니다.

    ReplicatedStorage 컨테이너 내 StatefulObjectController 모듈을 보여주는 Explorer 창.
  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 객체에 동작을 초기화하고 부착하는 데 사용되는 함수로, GuiObjectobject로, 상태와 해당 TweenInfo 데이터를 포함하는 테이블을 수용하며, 초기 상태 이름을 수용합니다. 이 함수 내에서 2628 라인은 각 상태에 대한 Tweens를 구성하고, 30 라인은 모듈의 setState() 함수를 호출하여 객체를 초기 상태로 설정합니다.
    3550상태가 있는 객체의 상태를 설정/변경하는 데 사용되는 함수입니다. 42 라인은 객체의 currentStateName을 설정하려는 상태로 설정하고, 4547 라인은 충돌을 방지하기 위해 실행 중인 모든 트윈을 취소하며, 49 라인은 상태의 트윈을 실행합니다.

슬라이더 컨트롤러

추가 모듈은 두 개의 볼륨 슬라이더를 초기화하고 제어합니다. 또한 각 슬라이더에 콜백 함수를 연결하여 플레이어가 슬라이더와 상호작용하는 것을 감지하고 게임에서 원하는 변경을 적용할 수 있습니다.

  1. ReplicatedStorage 컨테이너에 ModuleScript를 삽입하고 이름을 SliderController로 변경합니다.

    ReplicatedStorage 컨테이너 내 SliderController 모듈을 보여주는 Explorer 창.
  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슬라이더 요소에 동작을 초기화하고 부착하는 데 사용되는 함수로, 슬라이더의 부모 Frameobject로, 슬라이더 변경을 처리할 onChanged 콜백 함수를 수용하며, 슬라이더 핸들 위치의 초기 값을 수용합니다. 함수 내에서 1427 라인은 슬라이더의 핸들, 내부 채우기, 및 UIDragDetector 요소가 존재하는지 확인합니다. 38 라인은 모듈의 setValue() 함수를 호출하고, 4143 라인은 드래그 탐지기의 DragContinue 이벤트를 모듈의 setValue() 함수에 연결합니다 (다음 행의 세부 사항 참조).
    4861슬라이더의 값을 설정하는 데 사용되는 함수입니다. 함수 내에서 5354 라인은 핸들 위치와 내부 채우기 크기가 동기화되도록 보장하며, 57 라인은 변경된 값을 콜백 함수에 전달하여 필요에 따라 값을 활용할 수 있도록 합니다.

설정 스크립트 만들기

설정 버튼설정 메뉴가 완료되었으므로, 제어 모듈을 활용하여 모든 것을 연결하는 단일 스크립트를 작성할 수 있습니다.

  1. HUDContainer에 새로운 LocalScript를 삽입하고 이름을 SettingsScript로 변경하여 그 목적을 설명합니다. 이 스크립트는 SettingsMenuSettingsButton과 같은 최상위 UI 객체와 동일한 수준(형제)에 있어야 합니다.

    HUDContainer 컨테이너 내 SettingsScript 스크립트를 보여주는 Explorer 창.
  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 버튼이 수화할 객체로 참조됩니다.
    1225menuOpenmenuClosed라는 두 개의 고유 상태가 있는 states 테이블이 전달됩니다. 각 상태는 특정 상태가 properties 테이블에 정의된 목표 속성에 도달하는 방법을 선언하기 위해 TweenInfo를 통해 전환을 포함합니다. 이 경우, menuOpen은 버튼의 Rotation을 45°로 변경하고, Exponential 트윈을 0.5초 동안 적용하며, menuClosed는 버튼을 기본 회전인 0으로 복원합니다.
    26버튼의 초기 상태가 menuClosed로 설정됩니다 (이는 states 테이블 내의 어떤 상태 이름으로도 설정할 수 있습니다).

    스크립트의 아래쪽 (라인 76-86)에서 버튼은 플레이어 상호작용에 연결되어 UI 상태 변경을 트리거합니다:

    라인목적
    7682SettingsButtonActivated 이벤트에 연결되어 익명 함수를 호출합니다. 익명 함수 내에서 7779 라인은 targetState 변수를 menuOpenmenuClosed 사이에서 전환합니다. 80 라인은 setState()를 호출하여 버튼의 상태를 targetState로 설정하고, 81 라인은 SettingsMenu에 대해서도 동일하게 수행하여 SettingsButton의 활성화와 함께 열리거나 닫히도록 합니다.
    8386CloseButtonActivated 이벤트에 연결되어 익명 함수를 호출하며, 이 함수는 SettingsButtonSettingsMenu의 상태를 menuClosed로 설정합니다.

    30-49 라인은 설정 메뉴에 동작을 초기화하고 부착합니다:

    라인목적
    3031로컬 참조 settingsMenu가 선언되고 StatefulObjectController.hydrate() 함수로 수화되며, HUDContainer 내의 SettingsMenu 프레임이 수화할 객체로 참조됩니다.
    3246설정 버튼과 유사하게, menuOpenmenuClosed라는 두 개의 고유 상태가 있는 states 테이블이 전달됩니다. 여기서 menuOpen은 프레임의 PositionUDim2.fromScale(0.5, 0.5)로 변경하고, Bounce 트윈을 0.5초 동안 적용하며, Visible 상태를 true로 설정합니다. 반면, menuClosed는 위치 상태를 UDim2.fromScale(0.5, 0.4)로 변경하고 Visiblefalse로 설정하지만, TweenInfo0 지속 시간을 가지므로 상태 변경이 즉시 발생합니다.
    48프레임의 초기 상태가 menuClosed로 설정됩니다.

    스크립트의 아래쪽 (라인 76-86)에서 설정 메뉴는 플레이어 상호작용에 연결됩니다:

    라인목적
    81SettingsMenu의 동일한 targetState를 설정하여 SettingsButton의 활성화와 동기화합니다.
    85CloseButton이 활성화될 때 SettingsMenu의 상태를 menuClosed로 설정합니다.

    51-73 라인은 EffectsVolumeSliderBackgroundVolumeSlider에 동작을 초기화하고 부착합니다:

    라인목적
    52로컬 참조를 Effects SoundGroup에 설정합니다. SoundGroup은 여러 Sounds를 상호 연관시키고 그룹의 Volume 속성을 통해 모든 소리의 볼륨을 제어할 수 있게 해줍니다.
    5354로컬 참조 effectsVolumeSlider가 선언되고 SliderController.hydrate() 함수로 수화되며, HUDContainer ⟩ SettingsMenu 내의 EffectsVolumeSlider 프레임이 수화할 객체로 참조됩니다. true라는 두 번째 매개변수는 FindFirstChild()HUDContainer 브랜치 아래로 재귀적으로 EffectsVolumeSlider를 찾도록 지시합니다.
    55슬라이더의 초기 값이 Effects 사운드 그룹의 현재 Volume으로 설정되거나, 기본값으로 0.5가 설정됩니다.
    5660슬라이더 값 변경을 Effects 사운드 그룹의 볼륨에 적용하는 콜백 함수를 설정합니다.
    6473기본적으로 52-61과 동일하지만, HUDContainer ⟩ SettingsMenu 내의 BackgroundVolumeSlider 프레임을 수화하고 슬라이더 값 변경을 Background 사운드 그룹의 볼륨에 적용합니다.

SettingsScript가 설정되면, 게임은 관련 UI 객체 세트를 플레이어 상호작용에 연결하는 완전한 대화형 UI 예제를 제공합니다.

©2026 Roblox Corporation. Roblox 및 Roblox 로고, 'Powering Imagination'은 미국 및 기타 국가 내 당사의 등록 및 미등록 상표입니다.