개발일지 - Keymates!/개발

버튼 UI 효과음 설정 추가

khh7052 2026. 5. 20. 15:44
반응형

UI Toolkit에서 버튼을 클릭하면 효과음을 발생시키는 기능을 추가시키려고한다.

물론 스크립트를 통해 버튼 이벤트에서 클릭을 하면 사운드를 재생시키는 방법이 가장 간단하고 쉽겠지만, 한번 새로운 방식도 해보려고 한다.

 

바로 [UxmlElement] 와 [UxmlAttribute] 를 사용해서, 인스펙터에서 사운드를 할당하고 자동으로 이벤트를 등록해주는 버튼을 만들도록 할 것이다.

 

[UxmlElement] 와 [UxmlAttribute] 는 UIToolkit에서 커스텀 VisualElement를 UXML에서 사용할 수 있게 해주는 최신 Attribute 방식이다.

예전에는 UxmlFactory, UxmlTraits를 직접 구현했는데, 요즘 Unity에서는 이 Attribute 방식이 추가돼서 훨씬 간단해졌다.

예전 방식

using UnityEngine;
using UnityEngine.UIElements;

public class IconLabel : VisualElement
{
    public new class UxmlFactory : UxmlFactory<IconLabel, UxmlTraits> { }

    public new class UxmlTraits : VisualElement.UxmlTraits
    {
        private readonly UxmlStringAttributeDescription _text =
            new() { name = "text", defaultValue = "" };

        private readonly UxmlAssetAttributeDescription<Texture2D> _icon =
            new() { name = "icon" };

        public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
        {
            base.Init(ve, bag, cc);

            IconLabel element = (IconLabel)ve;

            element.text = _text.GetValueFromBag(bag, cc);
            element.icon = _icon.GetValueFromBag(bag, cc);

            element.Refresh();
        }
    }

    public string text;
    public Texture2D icon;

    private Label _label;
    private Image _image;

    public IconLabel()
    {
        _image = new Image();
        _label = new Label();

        Add(_image);
        Add(_label);
    }

    public void Refresh()
    {
        _label.text = text;
        _image.image = icon;
    }
}

 

최신 방식

using UnityEngine.UIElements;

[UxmlElement]
public partial class IconLabel : VisualElement
{
    [UxmlAttribute]
    public string text;

    [UxmlAttribute]
    public Texture2D icon;

    private Label _label;
    private Image _image;

    public IconLabel()
    {
        _image = new Image();
        _label = new Label();

        Add(_image);
        Add(_label);

        RegisterCallback<AttachToPanelEvent>(_ =>
        {
            _label.text = text;
            _image.image = icon;
        });
    }
}

 

 

우선 최신 방식을 통해 간단하게 사운드 버튼을 만들었다.

그리고 이제 UXML에서 ui:Button을 SoundButton으로 변경하면 잘 작동하지만, 좀 더 세부적인 설정을 적용할 수 있도록 코드를 추가하였다.

using UnityEngine;
using UnityEngine.UIElements;

[UxmlElement]
public partial class SoundButton : Button
{
    [UxmlAttribute]
    public AudioClip clickSound { get; set; }

    public SoundButton()
    {
        RegisterCallback<ClickEvent>(OnClick);
    }

    private void OnClick(ClickEvent evt)
    {
        if (clickSound != null)
            AudioManager.Instance.PlaySFX(clickSound);
    }
}

 

이번에는 [UxmlObject] 도 활용하였는데, [UxmlObject] 는 VisualElement 가 아닌 일반 객체를 UXML 안에서 사용할 수 있게 해주는 기능이다.

  • [UxmlElement]
    → 화면에 존재하는 UI 요소
  • [UxmlObject]
    → UI 요소가 사용하는 설정 데이터/구조체 느낌의 객체
using System.Collections.Generic;
using UnityEngine.Audio;
using UnityEngine.UIElements;

// 1. UxmlObject — 인스펙터의 Sound Effects 항목 하나
[UxmlObject]
public partial class SoundEffect
{
    public enum TriggerEvent { OnPointerClick, OnPointerEnter, OnPointerDown }

    [UxmlAttribute] public TriggerEvent EventType { get; set; }
    [UxmlAttribute] public AudioResource AudioResource { get; set; }
}

// 2. 커스텀 버튼에 리스트로 연결
[UxmlElement]
public partial class SoundButton : Button
{
    [UxmlObjectReference("sound-effects")]
    public List<SoundEffect> SoundEffects { get; set; } = new();

    public SoundButton()
    {
        RegisterCallback<ClickEvent>(_ => Play(SoundEffect.TriggerEvent.OnPointerClick));
        RegisterCallback<PointerEnterEvent>(_ => Play(SoundEffect.TriggerEvent.OnPointerEnter));
        RegisterCallback<PointerDownEvent>(_ => Play(SoundEffect.TriggerEvent.OnPointerDown));
    }

    private void Play(SoundEffect.TriggerEvent trigger)
    {
        var sfx = SoundEffects?.Find(s => s.EventType == trigger);
        if (sfx?.AudioResource != null)
            AudioManager.Instance.PlaySFX(sfx.AudioResource);
    }
}

 

변경 전 UXML

<ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Style src="project://database/Assets/_UI/USS/LobbyStyle.uss?fileID=7433441132597879392&amp;guid=9867ba563b7bd1f4792ff122d79cb6ae&amp;type=3#LobbyStyle"/>
    <ui:VisualElement name="container" style="flex-grow: 1; background-color: rgb(182, 223, 255); -unity-background-image-tint-color: rgb(255, 255, 255);">
        <ui:Label text="Keymates!" name="title" style="-unity-text-generator: advanced; -unity-text-auto-size: none; -unity-font-definition: url(&quot;project://database/Assets/_Fonts/Super%20Mindset.ttf?fileID=12800000&amp;guid=25d36e1c9a0e3e04a96c6f2dd3a11a74&amp;type=3#Super Mindset&quot;); background-color: rgba(0, 0, 0, 0); color: rgb(255, 192, 136); text-shadow: 10px 10px 0 rgb(27, 94, 176); -unity-text-align: middle-center; font-size: 200px; height: 400px;"/>
        <ui:Button text="Start" name="start-btn" class="lobby-button"/>
        <ui:Button text="Tutorial" name="tutorial-btn" class="lobby-button"/>
        <ui:Button text="Exit" name="exit-btn" class="lobby-button"/>
    </ui:VisualElement>
</ui:UXML>

 

변경 후 UXML

<ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:custom="UnityEngine.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Style src="project://database/Assets/_UI/USS/LobbyStyle.uss?fileID=7433441132597879392&amp;guid=9867ba563b7bd1f4792ff122d79cb6ae&amp;type=3#LobbyStyle"/>
    <ui:VisualElement name="container" style="flex-grow: 1; background-color: rgb(182, 223, 255); -unity-background-image-tint-color: rgb(255, 255, 255);">
        <ui:Label text="Keymates!" name="title" style="-unity-text-generator: advanced; -unity-text-auto-size: none; -unity-font-definition: url(&quot;project://database/Assets/_Fonts/Super%20Mindset.ttf?fileID=12800000&amp;guid=25d36e1c9a0e3e04a96c6f2dd3a11a74&amp;type=3#Super Mindset&quot;); background-color: rgba(0, 0, 0, 0); color: rgb(255, 192, 136); text-shadow: 10px 10px 0 rgb(27, 94, 176); -unity-text-align: middle-center; font-size: 200px; height: 400px;"/>
        <SoundButton text="Start" name="start-btn" class="lobby-button"/>
        <SoundButton text="Tutorial" name="tutorial-btn" class="lobby-button"/>
        <SoundButton text="Exit" name="exit-btn" class="lobby-button"/>
    </ui:VisualElement>
</ui:UXML>

 

변경한 부분은 두 곳뿐이다.

  • ui:Button → SoundButton
  • xmlns:custom="UnityEngine.UIElements" 추가

이제 버튼 인스펙터의 Attributes 항목에서 Sound Effects 가 잘 표시되는 것이 보인다.

여기에 사운드를 할당하면 게임에서 클릭했을 때 정상적으로 사운드가 실행된다. 

 

 

 

반응형

'개발일지 - Keymates! > 개발' 카테고리의 다른 글

캐릭터 변경  (0) 2026.05.26
AI 활용 3D 캐릭터 제작  (0) 2026.05.21
실루엣 렌더링 기능 추가  (0) 2026.05.21