3 minute read

개요


UniRx는 반응형 프로그래밍(Reactive Programming)을 유니티에 도입하기 위한 라이브러리입니다. 반응형 프로그래밍은 데이터 스트림과 변화의 전파에 초점을 맞춘 프로그래밍 패러다임입니다.
쉽게 말해, 발생하는 이벤트들을 데이터의 흐름(스트림)으로 보고, 이 흐름을 다양한 연산자들을 통해 가공하고 처리하는 방식입니다.
마치 정수기에서 여러 단계의 필터를 거쳐 깨끗한 물을 얻는 것과 같습니다.

특징


  • 이벤트 스트림 기반: 모든 이벤트를 데이터의 흐름(Observable)으로 표현합니다. 마치 수도꼭지에서 나오는 물줄기와 같습니다.
  • LINQ 스타일 API: C#의 LINQ와 유사한 API를 제공하여 스트림을 쉽게 조작할 수 있습니다. 마치 파이프를 연결하고 밸브를 조절하는 것과 같습니다.
  • 다양한 연산자(Operator) 제공: Where, Select, Merge, Zip, Throttle 등 다양한 연산자를 사용하여 스트림을 필터링, 변환, 결합할 수 있습니다. 마치 여러 종류의 필터를 사용하여 물을 정화하는 것과 같습니다.
  • 스케줄러(Scheduler) 제공: 스레드 관리 및 실행 컨텍스트를 제어할 수 있습니다. 예를 들어, UI 업데이트는 메인 스레드에서 실행해야 합니다. 마치 정수기의 전원 공급 및 물 공급을 제어하는 것과 같습니다.
  • 유니티 통합: 유니티의 MonoBehaviour, 이벤트 시스템 등과 잘 통합되어 있습니다. 마치 유니티 환경에 최적화된 정수기 시스템과 같습니다.

장단점


장점

  • 비동기 코드 및 이벤트 처리 코드를 간결하고 가독성 높게 작성할 수 있습니다. 마치 깔끔하게 정리된 배관 시스템과 같습니다.
  • 복잡한 이벤트 흐름을 쉽게 관리할 수 있습니다. 마치 정수기의 필터 관리 시스템과 같습니다.
  • 코드의 유지 보수성을 향상시킵니다. 마치 정수기의 부품 교체가 쉬운 것과 같습니다.

단점

  • 반응형 프로그래밍 패러다임에 대한 이해가 필요합니다. 마치 정수기 시스템의 작동 원리를 이해해야 하는 것과 같습니다.
  • 처음에는 연산자들을 익히는 데 시간이 걸릴 수 있습니다. 마치 여러 종류의 필터 사용법을 익히는 것과 같습니다.
  • 과도하게 사용하면 코드의 흐름을 파악하기 어려울 수 있습니다. 마치 너무 복잡한 배관 시스템과 같습니다.

주의점


  • 네임스페이스 추가: UniRx 함수를 사용하기 전에 using UniRx; 및 필요한 추가 네임스페이스 (예: using UniRx.Triggers;)를 추가해야 합니다.
  • Subscribe 관리: Subscribe를 통해 생성된 구독은 적절히 해제해야 메모리 누수를 방지할 수 있습니다. 마치 사용하지 않는 수도꼭지를 잠그는 것과 같습니다. Dispose() 메서드를 사용하거나 CompositeDisposable을 활용할 수 있습니다.
  • 스케줄러 사용: UI 업데이트 등 메인 스레드에서 실행해야 하는 작업은 ObserveOnMainThread()를 사용하여 스케줄러를 지정해야 합니다. 마치 정수기의 전원을 올바르게 연결하는 것과 같습니다.
  • 오퍼레이터 남용 방지: 너무 많은 오퍼레이터를 연결하면 코드의 가독성이 떨어질 수 있으므로 적절히 분리하여 사용하는 것이 좋습니다. 마치 너무 많은 필터를 연결하여 수압이 약해지는 것과 같습니다.

사용법


  1. UniRx 설치: 유니티 에셋 스토어 또는 Package Manager를 통해 UniRx를 설치합니다.
  2. 네임스페이스 추가: 스크립트 상단에 using UniRx; 및 필요한 추가 네임스페이스를 추가합니다.
  3. Observable 생성 (물 공급): 이벤트를 Observable로 변환합니다. 마치 수도꼭지를 트는 것과 같습니다.
  4. 오퍼레이터 사용 (필터링 및 가공): 다양한 오퍼레이터를 사용하여 Observable을 조작합니다. 마치 필터를 사용하여 물을 정화하는 것과 같습니다.
  5. Subscribe (물 마시기): 최종 Observable을 구독하여 이벤트를 처리합니다. 마치 정수기에서 깨끗한 물을 마시는 것과 같습니다.


[유니티 이벤트 Observable로 변환]

// 버튼 클릭 이벤트 Observable로 변환 (수도꼭지에 파이프 연결)
button.OnClickAsObservable().Subscribe(_ => Debug.Log("Button Clicked!"));

// Update() 함수 Observable로 변환 (끊임없이 흐르는 물)
Observable.EveryUpdate().Subscribe(_ => Debug.Log("Every Frame!"));

// 충돌 이벤트 Observable로 변환 (UniRx.Triggers 필요) (물통에 물이 차는 이벤트)
GetComponent<Collider>().OnCollisionEnterAsObservable().Subscribe(collision => Debug.Log("Collision!"));


[오퍼레이터 활용]

// 마우스 클릭 후 1초 뒤에 메시지 출력 (1초 필터 사용)
Observable.EveryUpdate()
    .Where(_ => Input.GetMouseButtonDown(0)) // 마우스 클릭 필터링 (특정 조건의 물만 통과)
    .Delay(TimeSpan.FromSeconds(1)) // 1초 지연 (1초 동안 물을 저장)
    .Subscribe(_ => Debug.Log("1 second after mouse click!"));

// 두 개의 Observable 병합 (두 개의 물줄기를 하나의 파이프로 합치기)
var observable1 = Observable.Interval(TimeSpan.FromSeconds(1)); // 1초 간격 물줄기
var observable2 = Observable.Interval(TimeSpan.FromSeconds(2)); // 2초 간격 물줄기
observable1.Merge(observable2).Subscribe(x => Debug.Log(x)); // 합쳐진 물줄기 마시기


[스케줄러 사용]

// 백그라운드 스레드에서 계산 후 메인 스레드에서 UI 업데이트 (백그라운드에서 정수 후 메인 밸브에서 물 내보내기)
Observable.Start(() => LongRunningOperation()) // 백그라운드 스레드에서 작업 (정수 작업)
    .ObserveOnMainThread() // 메인 스레드로 전환 (메인 밸브 열기)
    .Subscribe(result => uiText.text = result); // UI 업데이트 (물 마시기)


[Dispose 관리]

private CompositeDisposable disposables = new CompositeDisposable(); // 파이프 보관소

void Start() {
    button.OnClickAsObservable().Subscribe(_ => Debug.Log("Button Clicked!")).AddTo(disposables); // 파이프 연결 후 보관
}

void OnDestroy() {
    disposables.Clear(); // 모든 파이프 분리 (메모리 누수 방지)
}



Top