20. Reactive Extension
최근 들어 유행의 조짐이 오고 있다
- 다양한 언어로 이식 되고 있음
RxJS, RxJava, ReactiveCocoa, RxPy, RxLua, UniRx…
- 어떤 언어라도 Rx의 개념은 같다
21. UniRx
.NET용 Rx은 유니티의 Mono에서는 사용 불가
- Mono의 .NET 버전 문제
- 그리고 .NET용 Rx는 무겁고 크다
UniRx
- Unity(C#)에서 사용할 수 있게 만든 가볍고 빠른 유니티 전용 Rx
- Unity 전용으로 사용할 수 있는 Rx 스트림들을 제공
- 일본에서 개발
24. 시간이 결정하는 처리의 예
이벤트의 기다림
- 마우스 클릭이나 버튼의 입력 타이밍에 무언가를 처리 한다
비동기 처리
- 다른 스레드에서 통신을 하거나, 데이터를 로드할 때
시간 측정이 판정에 필요한 처리
- 홀드, 더블클릭의 판정
시간 변화하는 값의 감시
- False->True가 되는 순간에 1회만 처리하고 싶을 때
32. 스트림
[이벤트가 흐르는 파이프] 같은 이미지
- 어렵게 말하자면, [타임라인에 배열되어 있는 이벤트의 시퀀스]
- 분기 되거나 합쳐지는게 가능하다
코드 안에서는 IObservable<T> 로 취급된다
- LINQ에서 IEnumerable<T>에 해당
이벤트 메시지
이벤트의 흐름 그 자체가 <스트림>
33. 스트림에 흐르는 이벤트 <메시지>
메시지는 3종류가 있다
• OnNext
- 일반적으로 사용되는 메시지
- 보통은 이것을 사용한다
• OnError
- 에러 발생시에 예외를 통지하는 메시지
• OnCompleted
- 스트림이 완료되었음을 통지하는 메시지
34. 스트림과 버튼 클릭
버튼은
[클릭 때에 이벤트를 스트림에 보낸다]
라고 생각하는 것이 가능하다
Button
버튼이 클릭된 타이밍에
스트림에 메시지를 보내 넣는다 (OnNext)
35. Subscribe (스트림의 구독)
스트림의 말단에서 메시지가 올때 무엇을 할 것인지를 정의 한다
스트림은 Subscribe 된 순간에 생성 된다
- 기본적으로 Subscribe하지 않는 한 스트림은 동작하지 않는다
- Subscribe 타이밍에 의해서 결과가 바뀔 가능성이 있다
OnError, OnComplete가 오면 Subscribe는 종료 된다
Subscribe
스트림을 구독해서
메시지가 올 때에 처리를 한다
스트림
36. Subscribe와 메시지
Subscribe는 오버로드로 여러 개 정의되어 있어서, 용도에 따라 사용하는게 좋다
• OnNext 만
• OnNext & OnCompleted
• OnNext & OnError & OnCompleted
43. Button이 3회 눌리면 Text에 표시한다
버튼이 클릭된 횟수를 카운트 한다?
- 카운트용의 변수를 필드에 정의 한다?
44. Button이 3회 눌리면 Text에 표시한다
Buffer(3)을 추가만 하면 됨
- 굳이 필드 변수 추가 필요 없음
- 혹은 Skip(2)로도 똑같은 동작을 한다
- 여기에서는 이해를 돕기위해 Buffer를 사용했지만,
n회후에 동작하는 경우에는 Skip 쪽이 적절하다
45. Buffer
메시지를 모아서 특정 타이밍에 보낸다
- 방출 조건은 여러가지 지정이 가능하다
*n개 모아서 보내기
*다른 스트림에 메시지가 흐르면, 보내기
92. 도착 판정의 이미지 도식
F F F T T T T F F
F T F
T
UpdateAsObservable()
Updateの타이밍을 통지
Select()
IsGrounded 값으로 교체
DistinctUntilChanged()
값에 변화가 있는 순간만 통과
Where()
값이 True인 경우에만 통과
Subscribe()
isGrounded가 False->True가 된 순간에 통지 된다
98. isGrounded 다듬기 이미지 도식
T F T T T T T T T
T
T
UpdateAsObservable()
Updateの타이밍을 통지
Select()
IsGroundedの값으로 교체
DistinctUntilChanged()
값에 변화가 있는 순간만 통과
ThrottleFrame(5)
값이 5프레임간
오지 않는다면 최후의 값을 보냄
Subscribe()
isGrounded가 6프레임 이상
안정된 때에 최후의 값을 통지 한다
F T
1 2 3 4 5
111. UniRx와 조합하게 되면?
PhotonCloud의 콜백이 스트림으로 변환된다
- 복잡한 콜백은 숨기자
콜백으로
복잡복잡한 세계
UniRX로 콜백을 숨긴다
최신 방정보의 통지 스트림 로비 참가에 성공 통지
스트림
방에 참가 성공했다 통지
스트림
112. 콜백으로부터 스트림을 변경하는 메리트
코드가 명시적이 된다
- Photon의 콜백은 SendMessage로 호출된다
- Observable의 제대로 정의해서 사용하면 명시적이 된다
다양한 오퍼레이터에 의한 유연한 제어가 가능해 지게 된다
- 로그인이 실패하면 3초후에 다시 리트라이 시도한다던가
- 유저들로부터 요청이 있을때 처리를 한다던가
- 방정보 리스트가 갱신될때 통지 한다던가
113. 콜백으로부터 스트림을 변경하는 메리트
코드가 명시적이 된다
- Photon의 콜백은 SendMessage로 호출된다
- Observable의 제대로 정의해서 사용하면 명시적이 된다
다양한 오퍼레이터에 의한 유연한 제어가 가능해 지게 된다
- 로그인이 실패하면 3초후에 다시 리트라이 시도한다던가
- 유저들로부터 요청이 있을때 처리를 한다던가
- 방정보 리스트가 갱신될때 통지 한다던가
114. 예) 최신 방정보를 통시하는 스트림을 만들자
OnReceivedRoomListUpdate
- PhotoNetwork.GetRoomList()가 변경될때에 실행 된다
- 이것을 스트림으로 만들어 보자
115. 즉 이런 형태가 되고 싶다
갱신된 RoomInfo[]가 흐르는 스트림
이것을 Subscribe하게 되면,
방리스트의 갱신이 있을때마다 즉시 알게됨
116. 스트림의 소스를 만드는 법
Observable의 팩토리 메소드를 사용
기존의 이벤트등으로부터 변경한다
Subject<T>계를 사용
ReactiveProerty<T>를 사용
117. ReactiveProperty
Subscribe가 가능한 변수
Observale로서 Subscribe가 가능하다
값이 쓸때에 OnNext 메시지가 날라간다
//초기화
//Observable로서 Subscribe 가능
//Get으로 현재 값을 읽어오기 가능
//Set으로 값의 변경이 가능
// 동시에 그때의 값이 OnNext에 보낸다
124. 정리
UniRx는 편리하니까 사용해 보자!!!
- [시간]을 상당히 간단히 취급할 수 있게 된다
- GUI 관련 구현도 간단히 쓸 수 있다
- 게임 로직에 적용하는 것도 가능하다
UniRx는 편리하지만, 어려운 면도 있다
- 학습 코스트가 높고 개념적으로도 어렵다
- 도입하는 경우에는 프로그램의 설계부터 다시 생각할 필요가 생긴다
* 진가를 발휘하기 위해서는 설계 근본에서 UniRx를 포함시켜야 함
* [편리한 라이브러리]가 아닌 [언어 확장]이라고 생각할 필요가 있다
126. 보충) Subject<T>
스트림의 소스를 만드는것
- Subject, ReplySubject, BehaviorSubject, AsyncSubject로 여러 종류 있다
- 외부에 공개할 때에는 반드시 AsObservable을 거쳐서 공개한다
* 외부에서 직접 OnNext가 호출되는 상태로 하지 않음
127. 보충) Subject를 멈추는 법
Dispose를 호출하면 Subcribe가 중지 된다
- 스트림의 소스가 해제되면 자동적으로 Dispose 된다
- 스트림이 완료상태가 되어도 Dispose 된다
- static한 스트림을 만들 경우에는 수동 Dispose가 필요
128. 보충)UpdateAsObservable과Observable.EveryUpdate
둘다 Update()의 타이밍에 통지되는 Observable
- UpdateAsObaservable
* ObservableMonoBehavior를 상속받아 사용
* Obversevable을 계승하는 방식은 없어졌음
대신에 UniRx.Trigger 네임 스페이스에 준비된 확장 메소드를 사용
* Iobservable<Unit>
* 컴포넌트가 Destroy 될때 자동 Dispose
- Observable.EveryUpdate
* 어느 스크립트에서 사용할 수 있다
* Iobservable<long> (Subscribe된 때부터의 프레임 수)
* 사용이 끝나면 명시적으로 Dispose 할 필요가 있다
혹은 OnCompleted가 제대로 불리는 스트림으로 한다