์ด ์์ ๋ ๋คํฌ์์ธ์ ์คํ๋ฏธ๋ ์์คํ ๊ณผ ์ ์ฌํ ์์คํ ๊ตฌํ์ ์ํด ํ์ํ RX์ ์ฐ์ฐ๋ค์ ์กฐํฉ ๋ฐฉ๋ฒ๊ณผ ์ฌ์ฉ์ ์ ์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ ๋ํด์ ์๊ฐํ๋ ๊ธ๋ก์จ ์๋์ ๋ด์ฉ๋ค์ ํฌํจํ๋ค.
- uGUI ์ด๋ฒคํธ ์ฒ๋ฆฌ
- Subject๋ฅผ ์ด์ฉํ ๋ฉ์์ง ํต์ง
- ํ๋ ์ด์์ Rx ์ฐ์ฐ๋ค์ ์กฐํฉ(SkipUntil + TakeUntil + Repeat)
๊ตฌํํ ์์คํ ์ ๋ค์๊ณผ ๊ฐ์ด ์๋ํ๋ค.
- Action ๋ฒํผ(๋คํฌ์์ธ์์์ ๊ณต๊ฒฉ, ๊ตฌ๋ฅด๊ธฐ ๋ฑ)์ ํด๋ฆญํ๋ฉด ๋ฏธ๋ฆฌ ์ ํ ์(
amount)๋งํผ์ ์คํ๋ฏธ๋๊ฐ ๊ฐ์ํ๋ค. - ์ผ์ ์๊ฐ(
delay)์ด ์ง๋ ํ ์คํ๋ฏธ๋๋ ์๋์ผ๋ก ํ๋ณต๋๋ค. - ์คํ๋ฏธ๋๊ฐ ํ๋ณต์ค์ ๋ค์ ์ก์
์ ์คํํ๋ ๊ฒฝ์ฐ
2.๋ฅผ ๋ฐ๋ณตํ๋ค.
์ด๋ฅผ RX์์์ ์ด๋ฒคํธ ์คํธ๋ฆผ์ ๊ด์ ์ผ๋ก ๋ณด๋ฉด ์๋์ ๊ฐ์ด ์ ๋ฆฌํ ์ ์๋ค.
- ์ก์ ์ด๋ฒคํธ(์์ ์์๋ Action ๋ฒํผ์ ํด๋ฆญํ ๊ฒฝ์ฐ)๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ ์คํ๋ฏธ๋๋ฅผ ๊ฐ์ํ ํ
delay๋งํผ ๋๊ธฐ ํ์ ๊ฐ์ ์ด๋ฒคํธ(= ์คํ๋ฏธ๋ ํ๋ณต ์์)๋ฅผ ํต์งํ๋ค.- ๊ฐ์ ์ด๋ฒคํธ๋ฅผ ํต์งํ๋ฉด ์คํ๋ฏธ๋๋ฅผ ์ฑ์ฐ๋ ์คํธ๋ฆผ(ํ๋ณต)์ ๋ฐ๋ณตํ๋ค.
- ์คํ๋ฏธ๋๋ฅผ ํ๋ณตํ๋ ๋์ค์ ๋ค์ ์ก์ ์ด๋ฒคํธ๊ฐ ํต์ง๋๋ฉด ๊ธฐ์กด์ ๋ฐ๋ณต์ ์ค์ง(์ค์!)ํ ํ 2. 3.์ ๋ฐ๋ณตํ๋ค.
- ์คํ๋ฏธ๋๋ฅผ ๋ชจ๋ ํ๋ณตํ๋ฉด (slider.value == 1) ์คํ๋ฏธ๋ ๊ฐ์ ์ด๋ฒคํธ๊ฐ ํต์ง๋ ๋๊น์ง ๋๊ธฐํ๋ค.
๋จผ์ ์คํ๋ฏธ๋์ ๊ฐ์์ ํ๋ณต ์๋ฃ์ ๋ํ ๋ ๊ฐ์ง ์ด๋ฒคํธ ํต์ง๋ฅผ ์ํ ๋ฉ์์ง๊ฐ ํ์ํ๋ค. RX์์ ์ด์ ๊ฐ์ ์ฌ์ฉ์ ์ ์ํ ์ด๋ฒคํธ๋ Subject๋ฅผ ์ฌ์ฉํด์ ์์ฑํ ์ ์๋ค.
Subject<Slider> spStartSubject = new Subject<Slider>();
Subject<Slider> spEndSubject = new Subject<Slider>();๋ค์์ผ๋ก๋ ๋ Subject ๊ฐ์ฒด์ ๋ํ Observable ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
var spStartStream = spStartSubject.AsObservable();
var spEndStream = spEndSubject.AsObservable();์คํ๋ฏธ๋์ ํ๋ณต์ spStartStream์ด ๋์ฐฉํ๋ฉด ํ๋ณต์ ์์ํ๋ค. ํ๋ณต ์ค์ spEndStream์ด ๋์ฐฉํ๋ฉด ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ์๋ฃํ๋ค. ์ด๋ฒคํธ A๊ฐ ์ฌ ๋๋ถํฐ ์ด๋ฒคํธ B๊ฐ ์ฌ ๋๊น์ง์ ๋ํ ์ฒ๋ฆฌ๋ ์๋ RX ์ฐ์ฐ ์กฐํฉ์ ์ด์ฉํ๋ฉด ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
SkipUntil + TakeUntil + Repeat
๊ฐ๊ฐ์ ์ฐ์ฐ์ ๋ํด์๋ ์๋ ๋งํฌ๋ฅผ ์ฐธ์กฐํ์.
์คํ๋ฏธ๋์ ํ๋ณต์ ์ํ recorveryStream ์คํธ๋ฆผ์ ์์ฑํ๋ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
var recoveryStream = Observable.EveryUpdate()
.SkipUntil(spStartStream) // spStartStream ์ด๋ฒคํธ ํต์ง์๊น์ง ๋๊ธฐ
.Select( _ => slider.value )
.TakeUntil(spEndStream) // spEndStream ์ด๋ฒคํธ๊ฐ ํต์ง๋ ๋๊น์ง,
.RepeatUntilDisable(this) // ๋ฐ๋ณต
.Subscribe(v =>
{
// ์คํ๋ฏธ๋๋ฅผ delta๋งํผ ํ๋ณต
slider.value += this.delta;
// ์คํ๋ฏธ๋ ํ๋ณต์ด ์๋ฃ๋๋ฉด spEndSubject ์ด๋ฒคํธ ํต์ง๋ก ์คํธ๋ฆผ ์๋ฃ.
// -> ๋ค์ spStartStream ํต์ง๋ฅผ ๋๊ธฐํ๋ ์ํ๋ก ์ ์ด.
if (slider.value >= 1f)
spEndSubject.OnNext(slider);
});MonoBehaviour์ Update ์๋ง๋ค ์ด๋ฒคํธ ํต์ง๋ฅผ ๊ฒ์ฌํ๊ธฐ ์ํด์ Observable.EveryUpdate()๋ก ์คํธ๋ฆผ์ ์์ฑํ๋ค.
๋ฐ๋ณต์ Repeat ์ฐ์ฐ์ผ๋ก ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฐ, ๋ฌดํ๋ฃจํ์ ๋น ์ง์ง ์๋๋ก ์ฃผ์ํด์ผ ํ๋ค. UniRx์์๋ ์ด๋ฅผ ์ํด์ RepeatSafe์ RepeatUntilDestroy(gameObject/component), RepeatUntilDisable(gameObject/component)์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.(UniRx ReadMe ๋ฌธ์ ์ฐธ๊ณ ) ์ฌ๊ธฐ์์๋ ์ปดํฌ๋ํธ๊ฐ disable ์ํ์ผ ๋์๋ ๋ฐ๋ณตํ์ง ์๋๋ก RepeatUntilDisable ์ฐ์ฐ์ ์ฌ์ฉํ๋ค.
๋ค์์ผ๋ก๋ uGUI์ UI ๊ฐ์ฒด๋ค์ ์ด๋ฒคํธ๋ฅผ UniRx๋ฅผ ์ฌ์ฉํด์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์ดํด ๋ณด์.
UniRx์์๋ UnityEvent.AsObservable๋ฅผ ํตํด์ uGUI์ UnityEvent๋ค์ ๋ํ ์ฒ๋ฆฌ์ ํ ์ ์๋ค.
Button์ ๊ฒฝ์ฐ Button ๊ฐ์ฒด์ OnClickAsObservable() ์ ์ฌ์ฉํด์ ํด๋น ๋ฒํผ์ ํด๋ฆญํ ๊ฒฝ์ฐ์ ๋ํ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ค.
public Button actionButton;
...
IDisposable cancel = null;
var buttonStream = actionButton.OnClickAsObservable()
.Subscribe(_ =>
{
Debug.Log("button click.");
// ํ๋ณต ๊ด๋ จํด์ ์ด๋ฏธ ์คํ์ค์ธ ์ฝ๋ฃจํด์ด ์๋ ๊ฒฝ์ฐ ์คํ์ ์ข
๋ฃ.
if (cancel != null)
cancel.Dispose();
cancel = Observable.FromCoroutine(StartStaminaRecovery)
.Subscribe();
});์คํ๋ฏธ๋ ์๋ชจ์ ์์์ Observable.FromCoroutine์ ์ฌ์ฉํด์ ์ฝ๋ฃจํด ํจ์ StartStaminaRecovery๋ฅผ ํตํด์ ํต์งํ ๊ฒ์ ์คํ๋ฏธ๋ ์๋ชจ๊ฐ ์ผ์ด๋ ์งํ ๋ฐ๋ก recorveryStream์์ ์คํ๋ฏธ๋ ํ๋ณต์ ์์ํ๋ ๊ฒ์ด ์๋๋ผ delay๋งํผ ๋๊ธฐํ ํ spStartSubject๋ก ์คํ๋ฏธ๋ ํ๋ณต ์์ ์ด๋ฒคํธ์ ๋ํ ํต์ง ์ฒ๋ฆฌ๋ฅผ ์์ฝ๊ฒ ํ๊ธฐ ์ํด์์ด๋ค.
IEnumerator StartStaminaRecovery()
{
// ์คํ๋ฏธ๋๋ฅผ amount ๋งํผ ๊ฐ์.
slider.value -= this.amount;
// ํ์ฌ ์คํ๋ฏธ๋๊ฐ ํ๋ณต์ค์ธ ๊ฒฝ์ฐ spEndSubject์ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด์ ํ์ฌ ํ๋ณต์ค(repeat)์ธ ์ํ๋ฅผ ์ค์งํ๋๋ก ํ๋ค.
spEndSubject.OnNext(slider);
// delay ์๊ฐ๋งํผ ๋๊ธฐ.
yield return new WaitForSeconds(this.delay);
// ์คํ๋ฏธ๋ ํ๋ณต ์ด๋ฒคํธ ํต์ง
spStartSubject.OnNext(slider);
} ๋ฒํผ์ ๋๋ฌ์ StartStaminaRecovery ์ฝ๋ฃจํด ํจ์๊ฐ ์ด๋ฏธ ํ๋ ์คํ ์ค์ธ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด ๋ณด์. ์ฝ๋ฃจํด ํจ์๋ ์ฃผ์ด์ง delay๋งํผ ๋๊ธฐ ์ค์ธ ์ํ๋ก ์์ง spStartSubject.OnNext(slider)๋ก ํ๋ณต ์ด๋ฒคํธ๋ ํต์งํ๊ธฐ ์ ์ด๋ค. ์ด ๋ ๋ค์ ๋ฒํผ์ ๋๋ฌ์ StartStaminaRecovery ์ฝ๋ฃจํด ํจ์๋ฅผ ์คํํ ๊ฒฝ์ฐ๋ฅผ ๊ฐ์ ํด ๋ณด์. ์ฒซ ๋ฒ์งธ ์คํํ ์ฝ๋ฃจํด ํจ์์์ delay๋งํผ ๋๊ธฐ ํ์ ํ๋ณต ์ด๋ฒคํธ๋ฅผ ํต์งํ๊ณ ๊ทธ ๋ค์ ์คํํ ์ฝ๋ฃจํด ํจ์์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก delay๋งํผ ๋๊ธฐ ํ ํ๋ณต ์ด๋ฒคํธ๋ฅผ ํต์งํ ๊ฒ์ด๋ค. ๋ ๋ฒ์งธ ํ๋ณต ์ด๋ฒคํธ๋ฅผ ํต์งํ ๋์๋ ์ด๋ฏธ ์คํ๋ฏธ๋๋ฅผ ํ๋ณต ์ค์ธ ์ํ์ด๊ณ ๋ ๋ฒ์งธ ์ด๋ฒคํธ๋ recoveryStream์ ํต์งํ๋ฉด ํ๋ณต์ ์์ํ๊ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ฒํผ์ ์ฐํํด์ ์ฐ์ํ ํ๋ณต ์ด๋ฒคํธ๋ฅผ ํต์งํ๋ ๊ฒฝ์ฐ recoveryStream ์คํธ๋ฆผ์ ํ๋ณต ์ด๋ฒคํธ๊ฐ ์์ฌ์ ์๋ํ๋๋ก ํ๋ณต ์์คํ
์ด ์๋ํ์ง ์๊ฒ ๋๋ค. ์๋ ์๋ํ ํ๋ณต ์์คํ
์ ์๋์ ์ก์
์ด ๋ฐ์ํ๋ฉด ์ ํด์ง ์คํ๋ฏธ๋๋งํผ ๊ฐ์ํ๊ณ delay๋งํผ ๊ธฐ๋ค๋ฆฐํ ์๋์ผ๋ก ํ๋ณต์ ์์ํ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฐ๋ฐ recoveryStream์ ์ด๋ฒคํธ๊ฐ ์์ด๋ฉด delay๋งํผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฐ๋ก ํ๋ณต๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ฒ ๋๋ค. ์ด๋ฐ ์ค๋์์ ๋ฐฉ์งํ๊ธฐ ์ํด์ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ฝ๋ฃจํด ํจ์์ Observable์ด ์ด๋ฏธ ์๋์ง๋ฅผ ๊ฒ์ฌํด์ ์คํ์ค์ธ ์ฝ๋ฃจํด ํจ์๊ฐ ์์ผ๋ฉด Dispose๋ก ํด์ ํ๋๋ก ํ๋ค.
IDisposable cancel = null;
...
// ๋ฐ๋ก ์ฝ๋ฃจํด ํจ์๋ฅผ ์คํํ์ง ์๊ณ ์ธ์คํด์ค๋ฅผ ๊ฒ์ฌํด์ Dispose๋ฅผ ํธ์ถํ๋ ์ด์
if (cancel != null)
cancel.Dispose();
cancel = Observable.FromCoroutine(StartStaminaRecovery)
.Subscribe();์ด๋ ๊ฒ ๋ฒํผ์ด ๋๋ฌ์ง ๋๋ง๋ค ์คํ ์ค์ธ ์ฝ๋ฃจํดํจ์๊ฐ ์์ผ๋ฉด ๊ฐ์ ๋ก ์ข ๋ฃํ ํ ์๋ก์ด ์ฝ๋ฃจํด ํจ์๋ฅผ ์คํํ๋ฉด ์๋ํ ๋๋ก ํ๋ณต ์์คํ ์ด ์๋ํ๋ค.
์ค์ ๊ฒ์์ ์ ์ฉํ ๋์๋ ์ฌ๋ผ์ด๋์ ๊ฐ์ ๋ฐ๋ก ๋ณ๊ฒฝํ์ง ๋ง๊ณ ํ๋ ์ด์ด ์บ๋ฆญํฐ์ ์คํ๋ฏธ๋ ๊ฐ์ ๋ณ๊ฒฝํ๋๋ก ํ๊ณ ์ฌ๋ผ์ด๋๋ ํ๋ ์ด์ด ์บ๋ฆญํฐ์ ์คํ๋ฏธ๋ ๊ฐ๊ณผ Bindingํด ๋์ด์ ํ๋ ์ด์ด ์บ๋ฆญํฐ์ ์คํ๋ฏธ๋ ๊ฐ์ ๋ณ๊ฒฝํ ๋๋ง๋ค ์ฌ๋ผ์ด๋์ ๊ฐ์๋ ๋ณ๊ฒฝ๋ ๊ฐ์ด ์๋์ผ๋ก ๋ฐ์๋๋๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ข๋ค. UniRx์์๋ ์ด๋ฌํ ์ฒ๋ฆฌ๋ฅผ ์ํด ReactiveProperty๋ฅผ ์ ๊ณตํ๊ณ ์์ผ๋ ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.
๋ํ ์์ ์์๋ Observable.EveryUpdate()์ ์ฌ์ฉํด์ ๋งคํ๋ ์๋ง๋ค ์ ํด์ง ์๋งํผ ์คํ๋ฏธ๋๋ฅผ ํ๋ณตํ๋๋ก ์ฒ๋ฆฌํ๊ณ ์์ง๋ง ๋คํฌ์์ธ๊ณผ ์ ์ฌํ๊ฒ ์ฒ๋ฆฌํ๊ณ ์ ํ๋ค๋ฉด ๋ ๋ฒจ์ด๋ ๊ด๋ จ ์์ดํ
์ ์ฐฉ์ฉ ์ ๋ฌด์ ๋ฐ๋ผ ์ ํด์ง ์ด๋น ์คํ
๋ฏธ๋ ์ฆ๊ฐ๋์ ์ด์ฉํด์ ํ๋ณตํ๋๋ก ์ฒ๋ฆฌํด์ผ ํ๋ค. ๊ทธ๋ฌ๋ฏ๋ก ํ๋ ์๊ณผ ๋ฌด๊ดํ๊ฒ ์ฃผ์ด์ง ์๊ฐ์ ์คํ๋ฏธ๋๊ฐ ํ๋ณตํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ณ๊ฒฝํด์ผ ํ ๊ฒ์ด๋ค. ๋ฐ๊พธ์ด ๋งํ๋ฉด ํ๋ ์์ ๋
๋ฆฝ์ ์ธ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํด์ผ ํ๋ค๋ ์ด์ผ๊ธฐ์ด๋ค.
