[UniRx 입문 강좌 2] UniRx 의 핵심, Subject 와 Observable 사용 방법
[UniRx 입문 강좌 3] IObserver 메세지 종류와 스트림의 수명 관리
[UniRx 입문 강좌 4] Operator 활용(1) - Where & Select & SelectMany 사용법
[UniRx 입문 강좌 5] Operator 활용(2) - 다양한 오퍼레이터 소개
[UniRx 입문 강좌 6] 코루틴(Coroutine) 과 UniRx 연동
1. UniRx 란?
제작자 : @neuecc (Yoshifumi Kawai, CTO at Grani, Microsoft C# MVP)
License : MIT 로 공개
다운로드 : AssetStore, GitHub
UniRx란 무엇인가
UniRx - Reactive Extensions for Unity 의 약자.
Functional Reactive Programming(FRP) 를 C# 에 사용할 수 있게 만든 .Net Reactive Extensions 를 일본인인 @neuecc가 Unity 전용으로 최적화 하여 공개한 라이브러리 이다.
그런 만큼 더 가벼우며 UGUI, GameObject, Coroutine 등 유니티의 시스템과 매우 강력하고 직관적으로 연동이 되어 있어 쉽게 Reactive Programming 의 사용이 가능하다.
Reactive Programming 은 .Net 뿐만 아니라 RxJava, RxJS, Rx++, ReactiveCocoa, RxScala, RxClojure, RxSwift 등등 수많은 언어에서 사용 가능하도록 이미 많은 라이브러리가 제공 되고 있으며 사용자층 또한 매우 빠르게 늘어나고 있다.
2. Reactive Programming 이란?
Reactive Programming 을 한마디로 정의 한다면 아래와 같다.
Reactive programming is programming with asynchronous data streams.
(출처 : https://gist.github.com/staltz/868e7e9bc2a7b8c1f754)
'비동기적 데이터 흐름' 을 처리하는 프로그래밍 기법이라는 뜻으로 모든 처리를 비동기적 데이터 스트림으로 간주, Observer 디자인패턴을 활용해서 이러한 비동기 이벤트를 처리하는 것이 핵심이다.
좀 더 쉽게 풀어 쓰자면 일련의 흐름을 관찰할 수 있는 (Observable) 형태로 만들어서 값의 변화, 혹은 이벤트의 발생을 감지하는 것으로 이 값들은 마치 물이 흐르듯 스트림 (Stream) 을 통해 흐르는 것에 비유 할 수 있다.
경우에 따라 이 스트림의 값들을 필터링 하거나 버퍼링, 또는 다른 스트림의 값으로 바꾸는 등의 다양한 연산을 할 수 있다.
이렇게 스트림을 조작해서 원하는 결과가 통지 (Subscribe) 되므로 이 때 최종적으로 필요한 처리를 해줄 수 있게 된다.
이 방식은 지금까지 일반적으로 개발해 왔던 '명령형 프로그래밍' 과 큰 차이점을 가지고 있다.
명령형 프로그래밍이 일련의 작업 과정을 처리하는 각 단계마다 어떤 일이 일어나고 있는지 무엇을 해야 하는지 직접 관찰하고 컨트롤 하는 반면 Rx 프로그래밍은 Async Event(비동기 이벤트) 와 Observer 디자인패턴의 통지 처리를 이용해 미리 이런 조건이 발생하면 이런 처리를 하라고 지시를 내려놓고 그 지시가 통과된 시점에서만 통지를 받는 형태가 된다.
개념적으로는 기존의 프로그래밍 패러다임과 워낙 다르다보니 바로 와닿지 않는 점이 있지만 연습을 거쳐 개념을 이해하게 되면 매우 편리하다는 점을 알게 될것이다.
- 단, 사용 방법이 LINQ 쿼리 방식 중심이기에 람다 구문과 LINQ 를 어느 정도 익숙하게 사용할 수 있어야 한다.
3. UniRx 를 사용하는 이유
UniRx 를 사용하면 시간 (및 타이밍) 의 관리가 매우 편리해 지며 코드의 가독성과 코드 라인 수를 획기적으로 개선할 수 있다.
UniRx를 사용하기 좋은 예를 들자면
1. 더블 클릭 판정이나 유저의 입력 시간 제한 등의 일정 시간동안 대기 및 체크 해야 하는 이벤트
2. 파일을 다운로드 하거나 특정 통신 요청 후 응답 처리하는 경우
3. UI 반응이나 로직 상에 특정 변수 값이 변경되는 순간의 처리
등의 경우 예전에는 멤버 변수를 둔다거나 매프레임 Update 함수 내에서 변화를 체크하는 식의 작업을 해야 했지만 UniRx 를 사용하면 매우 간단하게 제어할 수 있게 된다.
이해를 돕기 위해 마우스 더블 클릭을 판정하는 경우를 예로 들어보겠다.
0.3초 내에 마우스 더블 클릭이 일어나면 GUI 의 MyText 컴포넌트에 클릭 횟수를 출력하는 로직이다.
기본적인 방법으로 구현한 더블클릭 판정 코드는 위와 같을 것이다.
더블 클릭이라는 점을 판단하기 위해 두개의 멤버 변수가 필요하며 마우스 클릭 순간을 판단하기 위해 어쩔 수 없이 Update 함수를 오버로딩 해서 매 프레임 체크를 해주고 있다.
많은 처리를 구현해 놓은 실제 프로젝트에서 이 코드가 추가되면 소스를 분석할 때 우선 멤버 변수 두개가 무슨 기능인지를 이해해야 하고 Update 함수 내에서 이루어 지는 여러개의 if 구문을 파악해야 한다.
만약 이 코드를 UniRx 기반으로 바꾸면 어떻게 될까
단지 이것으로 끝이다.
통지 받기 원하는 상황을 여러군데 로직을 나누지 않고 쿼리 형식으로 입력하는데다 조건을 체크하는게 아니라 지시하는 형태이므로 Update 함수안에서 매프레임 체크할 필요 없이 Start 나 Awake 에서 한번만 등록해 두면 되기에 코드 분석과 가독성이 비약적으로 향상된다.
주석에 대부분의 내용이 들어있지만 좀더 이해하기 쉽게 도형을 통해서 흐름을 살펴보자
소스의 첫번째 줄은 위 그림을 통해 보듯이 마우스 클릭 된 프레임들만을 흘려 보낼 clickStream 을 정의 한다.
이 스트림은 정의를 했을 뿐 아직 생성된 것은 아니라는 점이 포인트이다.
스트림의 생성은 실제 이벤트가 발생하는 시점에서 이루어진다.
이 부분은 실제 이벤트 발생 시 통지를 받을 조건들을 정의 한다.
1. 위에서 UpdateAsObservable 의 Where 오퍼레이터를 통해 마우스 클릭이 발생한 프레임 들을 골라서 스트림으로 만들어 준다.
2. 1번에서 생성되어 흘러온 스트림은 Buffer 에서 흐름이 멈춘 채 차곡차곡 누적된다.
3. 2번의 Buffer 는 개방 조건이 만족될 때까지 스트림을 흘려보내지 않고 누적시키는데 이 코드의 개방 조건은 Throttle(0.3초) 이다.
4. 즉, 밸브의 역할을 하는 Throttle 오퍼레이터가 클릭 이벤트 발생 후 0.3초 동안 새로운 클릭 이벤트가 없으면 통지를 해주는데 그때 Buffer가 모은 이벤트의 갯수를 체크해서 2개가 넘었다면 더블클릭으로 판정하게 된다.
5. 샘플에 의하면 Throttle 은 3번 발생했고 그중 첫번째와 세번째는 각각 3번, 2번의 클릭이 기록되어 더블클릭으로 판정 되며 두번째 Throttle 이벤트는 1번의 클릭이므로 Subscribe 를 통지하지 않는다.
이 경우 일반적으로는 .Subscribe() 을 통해 결과를 통지하지만 UniRx 의 경우 다양한 유니티 전용 오퍼레이터를 추가로 지원하는 데 그중 예제의 SubscribeToText() 는 인자로 넘겨주는 Text 컴포넌트에 람다식으로 지정한 문자열을 자동으로 셋팅해 주는 기능을 제공한다.
이 외에도 굉장히 다양한 유니티 기능을 제공하는데 이후 강좌에서 하나씩 다루어 보겠다.
어쨌든, 이 샘플을 이해했다면 Rx의 핵심 작동원리를 알 수 있을 것이다.
1. 스트림(Stream) 을 정의한다
2. 오퍼레이터(Operator) 로 스트림의 데이터를 가공한다
3. 가공된 데이터를 통지 (Subscribe) 받아서 우리의 로직에 태운다.
즉, 이벤트를 받으면 이걸 어떻게 가공하고 사용할지를 작성하는게 아니라 이벤트를 받기 전에 어떤 이벤트만 받고 싶은지를 작성하는 것이다.
내 로직에 필요한 이벤트만 가공하고 걸러내면 코딩이 훨씬 쾌적해 지니까!
[UniRx 입문 강좌 2] UniRx 의 핵심, Subject 와 Observable 사용 방법
댓글