Notice
Recent Posts
Recent Comments
Link
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Tags more
Archives
Today
Total
관리 메뉴

쓰고싶은거 써요

Unity Custom Attribute 본문

Unity

Unity Custom Attribute

우히힝 2025. 9. 22. 21:55

Unity 플랫포머 게임을 만들다 보니 참 내 생각대로 되는게 없는 것 같다.

 

이렇게 생긴 UI 컴포넌트가 존재한다고 치자.

 

 

하나의 Scene 에서 해당 값을 바꾸고 적용하는 것에는 전혀 문제가 없다.

 

다만 다른 Scene 으로 이동했을 경우에는 달랐다.

 

 

안에 들어가는 On Value Changed 값이 항상 바뀌고 하나하나 설정하기에는 너무나 큰 리소스를 차지한다.

 

직접 손으로 했을 경우의 문제.

1. KeyManage 의 인스턴스가 사라질지 안사라질지 알 수 없기 때문에 바인드를 미리 시킬 수 없다.

2. 그렇다고 하나씩 불러서 하기에는 너무 너무너무 귀찮다. 이걸 언제 손으로 하나하나 씬이 바뀔때마다 하냐?

 

귀찮은건 싫어.~

메서드에서만 적용 가능한 커스텀 어트리뷰트 를 만들었다.

 

일단 Option UI 에 담을 Script 를 하나 생성한다.

 

만든 스크립트는 단축키 설정에 필요한 옵션 버튼에 넣을 것이다.

public class Option_ShortCut_Atom : MonoBehaviour
{
    private TextMeshProUGUI[] keyText;
    private Toggle toggle;
    private KeyManager keyManager;
    [SerializeField] private KeyAction keyAction;

    private void Awake()
    {
        keyText = GetComponentsInChildren<TextMeshProUGUI>();
        toggle = GetComponentInChildren<Toggle>();
        keyManager = KeyManager.Instance;
    }

    private void Start()
    {
        keyText[1].text = KeyManager.GetKeyCodeDisplayName(keyAction);
        // 코드를 추가해야할 곳.
        toggle.onValueChanged.AddListener((bool isOn) => { if (isOn) .... });
        KeyManager.OnKeyBinded += OnChanged;
        KeyManager.OnKeysLoaded += OnChanged;
    }

    private void OnChanged()
    {
        keyText[1].text = KeyManager.GetKeyCodeDisplayName(keyAction);
    }

    private void OnDestroy()
    {
        KeyManager.OnKeyBinded -= OnChanged;
        KeyManager.OnKeysLoaded -= OnChanged;
    }
    
}

 

주석달린 저 곳에 함수들을 알잘딱깔센으로 넣어줘여한다..

 

진~~짜 간단하고 귀찮은 방법이 있다.

 

switch case 문을 사용해서 넣는것이다.

 

다만... 키가 몇개인데 그걸 하나하나하나 하겠는가..

 

나는 귀찮아서 싫다.

 

그래서? 검색을 이리저리 돌려봤는디

 

[AttributeUsage(AttributeTargets.Method)]

 

이런 좋은게 있었다. 

  • AttributeUsage: 커스텀 어트리뷰트의 사용 범위를 제한하는 어트리뷰트
  • AttributeTargets.Method: 어트리뷰트가 메서드에만 적용될 있음을 지정

이걸 넣음으로써 어떤 장점이 있을까?

  1. 타입 안전성: 잘못된 위치에 어트리뷰트 사용 방지
  2. 명확한 의도: 어트리뷰트가 메서드용임을 명시
  3. IDE 지원: 잘못된 사용 컴파일 에러로 알려줌

일단 만들어보자~

using System;

[AttributeUsage(AttributeTargets.Method)]
public class KeyBindingActionAttribute : Attribute
{
    public KeyAction keyAction { get; }
    public KeyBindingActionAttribute(KeyAction _keyAction)
    {
        keyAction = _keyAction;
    }
}

 

이 함수를 생성하고 KeyManager 에 해당 코드를 사용할 수 있도록 세팅해주었다.

    // 자동 매핑 시스템
    private static Dictionary<KeyAction, System.Action> keyBindingMethods;

    private void InitializeKeyBindingMethods()
    {
        keyBindingMethods = new Dictionary<KeyAction, System.Action>();

        // KeyManager의 모든 public 메서드를 검사
        var methods = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);

        foreach (var method in methods)
        {
            var attribute = method.GetCustomAttribute<KeyBindingActionAttribute>();
            if (attribute != null)
            {
                keyBindingMethods[attribute.keyAction] = () => method.Invoke(this, null);
            }
        }
    }

    public void SetKeyBinding(KeyAction action)
    {
        if (keyBindingMethods == null)
            InitializeKeyBindingMethods();

        if (keyBindingMethods.TryGetValue(action, out var method))
        {
            method();
        }
        else
        {
            Debug.LogWarning($"No binding method found for {action}");
        }
    }

 

이제 이 코드를 OnValueChange 에 넣을 함수들 위에 Attribute 를 추가해주면 완성!!

 

    [KeyBindingAction(KeyAction.SHIFT)]
    public void SetKeyBindingShift()
    {
		...
    }

    [KeyBindingAction(KeyAction.UP)]
    public void SetKeyBindingUp()
    {
		...
    }

    [KeyBindingAction(KeyAction.DOWN)]
    public void SetKeyBindingDown()
    {
		...
    }

	.......

 

물론 모든 문제가 다 해결된 것은 아니다.

 

switch case 마냥 노가다를 안할 수는 없지만. 두 번 할바에 한번 하는게 낫지 않은가?

 

이제 처음에 만든 Option_Shortcut_Atom Script 에 이벤트를 추가해주면?

 

 toggle.onValueChanged.AddListener((bool isOn) => { if (isOn) keyManager.SetKeyBinding(keyAction); });

 

UI 로서의 기능은 완벽히 분리되어 case 로 지럴염병을 떨지 않아도 좋아졌다.

 

Comments