겨울팥죽 여름빙수

2023.02.24 - [게임을 만들자/Unity] - 1. UniRx 시작, Subject와 ReactiveProperty

2023.03.22 - [게임을 만들자/Unity] - 2. UniRx, Observable 메소드

2023.08.25 - [게임을 만들자/Unity] - 4. UniRx, 메시지 병합(Merge, CombineLastest, Concat)

 

 

  • UniRx에서는, 스트림으로 전달된 메시지를 변형하거나, 필터링 하는 등의 함수를 제공한다. 이 함수들은 C#의 Linq함수와 사용법이 비슷하다. 예를 들어 Select는 메시지를 변경하고, Where는 메시지는 필터링하는데, Linq함수의 Select/Where와 매우 흡사하다.

 

  • Select
    • 메시지를 변경한다.
    heroModel.DiffHp //hp 변화량. ReactiveProperty<int> DiffHp
    	.Select(_diff => _diff > 0) // diff값이 0 이상이면 true, 아니면 false로 메시지 전달
    	.Subscribe(_result =>
    	{
    			//_result는 int가 아닌 boolean값
    	}.AddTo(this)
    
    • 위 코드에서 _diff값은 int타입인데 이것을 boolean타입으로 변환한다.
      • Subscribe에서 전달된 메시지(_result)는 boolean타입이다.

 

  • Where
    • 메시지를 필터링한다.
    heroModel.Level //영웅 레벨.
    	.Where(_level => _level >= 10) //레벨이 10이상인 경우만 처리
    	.Subscribe(_level =>
    	{
    			//10 이상의 값만 전달 된다.
    	}.AddTo(this)
    
    • 위 코드는 영웅 레벨이 변경될 때마다 메시지를 전달하지만, Where문으로 레벨이 10이상일 경우만 처리하는 코드이다. 레벨이 3일 경우, Where까지 실행하고, Subscribe 코드는 동작하지 않는다.

 

  • Skip
    • 구독 후, 전달된 메시지를 N회 무시한다.
    heroModel.Level
    	.Skip(1)
    	.Subscribe(_level =>{})
    	.AddTo(this)
    
    • 위 코드의 Level은 ReactiveProperty만들었을 경우, Subscribe 시 현재 값을 메시지로 받는다. 하지만 어떤 경우엔, 처음 메시지를 넘기고 싶을 때가 있다. 위 코는 맨 처음 구독 시 받는 메시지를 무시하고, 그 다음 레벨 값 부터 Subscribe의 Action이 실행된다.

 

  • Take
    • N개의 메시지만 받는다. N개 메시지 후, 종료된다(OnCompleted).
    public class UiClip
    {
    		//클립 ui가 닫힐 때, HideSubject.OnNext()호출
    		private readonly Subject<Unit> HideSubject = new();
    		public IObservable<Unit> HideObservable => HideSubject;
    }
    
    //HideObservable은 IObservable<Unit> 타입이다.
    //클립 ui가 닫힐 때까지 기다림
    await clip.HideObservable.Take(1).ToTask();
    
    //닫히고 난 후 처리
    ...
    
    • ToTask()함수와 함께 사용
      • ToTask는 IObservable를 Task객체로 반환해준다. 마지막 값이나, 스트림 중의 Exception을 반환한다.
      • 위 코드는 1개의 메시지를 기다리는 코드이다. 비동기 코드로 특정 메시지를 기다릴 때 사용하기 좋다. 위 코드에서는 Clip(게임 상에서 메시지 팝업같은 것) Ui코드에 Subject<Unit> 멤버 변수를 두고, 해당 클립이 닫힐 때, OnNext()함수를 호출해 메시지를 전달한다. 클립이 닫히는 이벤트를 가다리는 곳에서, HideObservable의 Take함수를 호출하고, Take함수의 리턴값(IObservable<T>)을 이용해 Task로 바꿔 await한다.

 

  • Throttle / ThrottleFrame
    • 메시지 중복을 방지하기 위해, 일정 시간 혹은 간격 동안 받은 메시지 중 마지막 메시지를 전달한다.
    • 아래 코드에서 OnClickSubject를 구독하며, 1초에 한 번씩 메시지를 전달한다.
    • 이전 메시지가 전달된 이후 1초가 지나지 않으면, 새로운 메시지를 전달하지 않고 이전 메시지를 유지한다.
    //Observable의 Throttle함수 예제
    public class ThrottleTest : MonoBehaviour
    {
        private readonly Subject<Unit> OnClickSubject = new();
    
        private void Awake()
        {
            //버튼 클릭 시, Subject에 메시지 전달
            GetComponent<Button>()
    					.OnClickAsObservable()
    					.Subscribe(_ => OnClickSubject.OnNext())
    					.AddTo(this);
    
            //Subject를 구독하며, 1초에 한번씩 메시지 전달
            OnClickSubject
    					.Throttle(TimeSpan.FromSeconds(1))
    					.Subscribe(_ => Debug.Log("Click"))
    					.AddTo(this);
        }
    }
    
    
    • 메시지를 병합하는 경우, 한 프레임 내에 같은 메시지가 중복 전달되는 경우가 많다. 이때 ThrottleFrame(1) 설정해, 마지막 메시지만 처리하도록 하여 성능 저하를 막는다.

 

  • Distinct
    • 중복 값을 무시한다. 한번 통과했던 값은 무시한다.

 

  • DistinctUntilChanged
    • 값이 변할 때만 메시지를 전달한다.
    //현재 ui상의 탭 선택한 값
    currentTabState
        .DistinctUntilChanged()
        .Subscribe(_selectedTab =>
        {
            //선택한 탭이 변경 되었을 때만 동작
        }).Add(this);
    
    • 위 코드는 ui상에서 많이 쓰이는 탭 페이지를 구현했을 때의 예이다. 탭이 변경된 경우의 행동을 정의한다.
profile

겨울팥죽 여름빙수

@여름빙수

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!