UI작업을 하면서 어떤 값이 바뀌면 UI에 바로 적용되도록 구현하고 싶어서 알아보던 중 "반응형 프로퍼티"의 개념을 알게되어서 정리해보려고 한다.
반응형 프로퍼티는 간단하게 설명하면 값이 바뀌면 자동으로 등록된 이벤트가 실행되는 구조이다. 데이터가 UI같은 다른 로직에 연결되어 있을 때, 변화를 감지하고 자동으로 동작하도록 구성할 수 있다.
이런 개념을 통해 몬스터를 소환할 때 사용하는 게이지를 만들고, 게이지를 소모할 시 바로 Fill Type Image의 Fill Amount값을 변경해보려고 한다.
<반응형 프로퍼티 스크립트>
using System; [Serializable] public class ReactiveProperty<T> where T : struct { private T value; private Action<T> actions; public T Value { get { return value; } set { if(Equals(this.value,value)) { return; } this.value = value; actions?.Invoke(this.value); } } public void AddAction(Action<T> action) { this.actions += action; } public void RemoveAction(Action<T> action) { this.actions -= action; } private void OnDestroy() { actions = null; } }
해당 코드가 반응형 프로퍼티이다. 프로퍼티의 설정자 부분을 보면 값이 동일할 때는 리턴하고, 값이 변경되었을 때 등록된 이벤트를 호출하는 방식이다. 그래서 반응형 프로퍼티를 초기화할 때 AddAction을 통해 함수를 등록해두면 자동으로 프로퍼티의 값이 변경될 때 이벤트 함수를 호출하는 것이다.
아래 코드는 반응형 프로퍼티로 만든 게이지 값을 Image에 바로 적용하는 코드이다.
using UnityEngine; using UnityEngine.UI; public class GaugeUI : MonoBehaviour { private Image fillImage; private ReactiveProperty<float> cur; private ReactiveProperty<float> max; private void Awake() { fillImage = GetComponent<Image>(); } // 반응형 프로퍼티로 현재 게이지와 최대 게이지를 바인딩 public void Bind(ReactiveProperty<float> curGauge, ReactiveProperty<float> maxGauge) { cur = curGauge; max = maxGauge; cur.AddAction(UpdateFill); max.AddAction(UpdateFill); UpdateFill(cur.Value); } // 반응형 프로퍼티의 값이 변경되면 실행할 함수. 값에 따라 이미지의 fillAmount가 바뀜 private void UpdateFill(float useless) { if (max == null || max.Value <= 0f) { return; } fillImage.fillAmount = Mathf.Clamp01(cur.Value / max.Value); } // 메모리 누수 방지용 자산해제 private void OnDestroy() { if (cur != null) { cur.RemoveAction(UpdateFill); } if (max != null) { max.RemoveAction(UpdateFill); } } }
이런식으로 반응형 프로퍼티를 사용해서 프로퍼티를 UI에 바인딩해두면 프로퍼티의 값이 변경될 때 UI에 자동으로 적용된다.
아래 영상은 몬스터를 소환하면 반응형 프로퍼티로 설정된 게이지 value가 감소하고, 감소될 때 자동으로 게이지UI에 적용되는 모습이다.
- 위 영상에서 잘 보이진 않지만 12시 방향의 타이머도 반응형 프로퍼티를 이용해서 제작했다.