내일배움캠프 Unity 11일차 TIL - Unity delegate로 옵저버 패턴 구현해보기

Wooooo·2023년 11월 13일
0

내일배움캠프Unity

목록 보기
13/94

오늘의 키워드

어제 하던 옵저버 패턴 실습 중에, System.Action 말고도 Unity에서 지원해주는 UnityEngine.Events.UnityAction도 있다는 걸 알았다.
실습 진행상황과 함께 저 둘의 차이점도 한 번 정리해보려 한다.


실습 진행

기능 추가

    public event Action<int, int> OnLevelChanged;
    public event Action<int> OnKill;
    public event Action OnDead;
    public event Action<float, float> OnHPChanged;
    public event Action<float, float> OnMpChanged;
    public event Action<float, float> OnExpChanged;

    void Start()
    {
        OnHPChanged += IsDead;
        OnHPChanged += GameObject.Find("Player Info UI").transform.GetChild(0).GetComponent<InfoUI>().SetUIBar;
        OnMpChanged += GameObject.Find("Player Info UI").transform.GetChild(1).GetComponent<InfoUI>().SetUIBar;
        OnExpChanged += GameObject.Find("Player Info UI").transform.GetChild(2).GetComponent<InfoUI>().SetUIBar;
        OnExpChanged += LevelUp;
        OnLevelChanged += GameObject.Find("Player Info UI").transform.GetChild(3).GetChild(1).GetComponent<InfoUI>().SetUILvText;
        OnLevelChanged += LevelUpVFX;
        OnDead += achievement.AchieveFirstDeath;
        OnLevelChanged += achievement.AchieveMaxLv;
        OnKill += achievement.AchieveKills;

        HP = MaxHP;
        MP = MaxMP;
        EXP = 0;
        LV = 1;
    }

OnLevelChanged, OnDead, OnKill 등을 추가로 작성해서 업적과 관련된 메서드들을 등록시켜줬다.
또, 기존에 void delegate StatusChangeHandler(float, float)로 작성했었던 delegate를 System.Action으로 바꾸고 통일해줬다.
이 과정에서 delegate를 inspector 창에 노출시킬 순 없을까? 하고 찾아봤는데, 그러기 위해선 UnityEngine.Events.UnityEvent를 사용해야한다고 한다.

업적 구현

업적은 Player의 여러가지 상태를 구독하고 있어야 한다. 그런데 interface를 이용한 옵저버 패턴 구현은 Player 클래스 자체를 구독하고 Player 클래스는 자신의 상태가 바뀌면 어떤 것이 바뀌었든간에 업적관리 클래스에게 Notify()로 공지한다. 이러면 업적관리 클래스는 Player의 어떤 것이 바뀌었는지 모르기 때문에 하나하나 검사를 해봐야한다. 예를 들면,

  • 플레이어가 처음으로 죽었을 때 달성되는 업적 : 플레이어가 죽었을 때만 검사하면 됨
  • 플레이어가 만렙을 찍으면 달성되는 업적 : 플레이어가 레벨업을 할 때만 검사하면 됨
  • 플레이어가 n킬을 하면 달성되는 업적 : 플레이어가 킬을 할 때만 검사하면 됨

따라서, delegate를 이용하면, 업적관리 클래스는 Player의 변수 하나하나를 구독할 수 있게 되고 이렇게 구현하는 게 interface를 사용하는 것보다 더 의존성도 적고 구현하기도 쉬울 것 같았다.

(interface로 구현 시, 클래스 단위의 구독)

(delegate로 구현 시, property/method 단위의 구독)

구현된 모습

달성되지 않은 업적은 회색 글씨로 보여주고, 달성한 업적은 검은색 글씨로 보여준다.


C#Event vs UnityEvent

C# Event

  • Unity Editor의 Inspector창에 노출할 수 없음.
  • 오버헤드가 적어 빠르다.
  • C# 구문으로 작성할 수 있어 UnityEvent로 작성하는 것 보다 코드가 유연하다.

UnityEvent

  • Unity Engine에서 사용하기 위해 Unity에서 미리 만들어둔 Event.
  • Unity Editor의 Inspector창에 노출됨. 따라서 디자이너 친화적
  • 직렬화, 리플렉션 등을 지원하기 때문에 C# Event보다 느린 속도
  • Unity UI의 OnClick()이나 OnValueChanged()와 같은 Event가 이 녀석으로 구현됨.
  • MonoBehaviour를 상속받는 클래스에 사용 가능
  • AddListener()를 이용해 대리자를 연결함.

둘의 장단점이 명확하다. 빠른 속도와 간결한 코드가 필요하다면 C# Event를 사용하면 되고, Inspector창과의 호환으로 Unity Editor에서 추가 작업을 필요로하면 UnityEvent를 사용하면 되겠다.


출처

https://highfence.tistory.com/19
https://www.jacksondunstan.com/articles/3335
https://coding-shop.tistory.com/91?category=1165832

profile
game developer

0개의 댓글