๋ญ๊ฐ ๊ฐค ๋ณด๊ณ ์์ผ๋ฉด 'UniRx๋ฅผ ๊ณต๋ถํด์ผํ๋?' ์๊ฐํ๋ ์ฌ๋๋ค๊ณผ
๋ฌด์ง์ฑ UniRX ์ ๋ด์๋ค์ด ๊ฝค ์๋๊ฑฐ ๊ฐ์์ ์ ๋๋ก ์ ๋ณด๋ฅผ ์ฃผ๊ธฐ ์ํด ๊ธ์.
๊ฒฐ๋ก ๋ง ๋ณผ ์ฌ๋์ ๋งจ ์๋ ๊ฒฐ๋ก ๋ง ๋ณด์
.
https://neuecc.medium.com/r3-a-new-modern-reimplementation-of-reactive-extensions-for-c-cf29abcc5826
UniRX, UniTask, R3 ๊ฐ๋ฐ์์ธ ์นด์์ด ์์ํ๋ฏธ์ ๋ธ๋ก๊ทธ ๊ธฐ์ฌ ์ธ์ฉ
์ฐธ๊ณ ๋ก ์์ํ๋ฏธ๋ Cysharp.Inc์ ๋ํ๋ก ์ฌ์ด๊ฒ์์ฆ ์ํ์ฌ๊ณ ,
์ด ํ์ฌ๋ ๊ฒ์ ๊ฐ๋ฐ์ฉ ์คํ ์์ค C# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋ฌธ ๊ฐ๋ฐ์ฌ๋ก C#์ ๊ฐ๋ฐ ์ธ์ด์ ํ์ค์ผ๋ก ๋ง๋๋๊ฒ ๋ชฉํ์.
C#์ ๋ฏธ์น ์ฌ๋์ด๋ผ๊ณ ๋ณด๋ฉด ๋จ.
โโโ
"Rx๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๊น? .NET์ด๋ Unity๋ฟ๋ง ์๋๋ผ Java, Swift, Kotlin์์๋ โ์๋์โ๋ผ๊ณ ๋๋ตํ๋ ์ฌ๋๋ค์ ์๊ฐ ๋์ด๋๊ณ ์์ต๋๋ค. ๊ทธ ์กด์ฌ๊ฐ์ด ํ์ฐํ ์ค์ด๋ค๊ณ ์์ต๋๋ค. ์? ๋๋ต์ ๊ฐ๋จํฉ๋๋ค, async/await์ ์ถํ์
๋๋ค."
"async/await๊ฐ ๋๋ฆฌ ์ฑํ๋๋ฉด์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ง์ ์ํ Rx์ ํ์์ฑ์ด ์ค์ด๋ค๊ณ ์ฑํ๋ฅ ๋ ๊ฐ์ํ์ต๋๋ค. Unity์ Rx ํ์ค์ธ UniRx์ ๊ฐ๋ฐ์๋ก์ ์ ๋ ๊ฒ์ ์์ง(Unity)์ ๋ง๋ async/await ๋ฐํ์์ ํ์์ฑ์ ๋น ๋ฅด๊ฒ ์ธ์ํ๊ณ Unity์์ ํ์ํ ์กฐ๊ฑด(C# 7.0)์ด ์ถฉ์กฑ๋์๋ง์ UniTask๋ฅผ ๊ฐ๋ฐํ์ต๋๋ค."
์ด๊ฒ ๋ฌด์จ ์๋ฆฌ๋? Rx๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ์ด๋ฒคํธ ๊ธฐ๋ฐ LINQ, ๋ ๊ฐ์ง ๋ถ๋ถ์์ ๊ฐ์ ์ด ์์๋๋ฐ, async/await์ด ์ถํํ๋ฉด์ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ถ๋ถ์์์ ๊ฐ์ ์ ์์ด๋ฒ๋ฆฌ์ ์ฌ๋๋ค์ด ๋ฐ๋ก Rx๋ฅผ ๋ฒ๋ ธ๋ค๋ ์๊ธฐ์.
์ด์ํ์ง? ๊ฐ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๊ฐ๋
์ด๋ฉด ์ฐ๋ Rx๋ฅผ ๊ณ์ ์ฐ์ง ์ Rx๋ฅผ ๋ฒ๋ ค๋ฒ๋ฆด๊น?
๋ต์ ๊ฐ๋จํ๋ค.
์ข๋ค๊ณ ๋ฏฟ์๊ฒ ์ฐ๋ค๋ณด๋๊น ๋ถํธํ๊ธฐ ๋๋ฌธ์.
์คํธ๋ฆผ์ด๋ ๊ฐ๋
์ด ๋๋ฒ๊น
์ ํ๋ค๊ฒ ๋ง๋ค๊ณ ์ฝ๋์ ๊ฐ๋
์ฑ์ ๋จ์ด๋จ๋ฆฌ๊ฑฐ๋ .
ํนํ ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ํฌ๋ฉด ํด์๋ก Rx๋ ๊ธฐํ๊ธ์์ ์ผ๋ก ๋๋ฒ๊น
์ ํ๋ค๊ฒ ๋ง๋ฌ.
์คํธ๋ฆผ๋ค์ด ์ด๋ป๊ฒ ์ฎ์ฌ์๋์ง ์๊ธฐ ํ๋๋๊น.
๊ฐ๋ฐ ๊ธฐ๊ฐ์ ๋ง์ ๋น์จ์ ๋๋ฒ๊น
ํ๋๋ฐ ๋ณด๋ด๋๋ฐ ๊ทธ๊ฑธ ํ๋ค๊ฒ ๋ง๋ ๋ค? ์์ฒญ๋ ๋๋ฉ๋ฆฌํธ์ง.
๊ทธ๋๋งย ๋น๋๊ธฐ ์ฒ๋ฆฌ ์ชฝ์ ๋์์ด ์์ผ๋๊น ์ฐ๊ณ ์์๋๋ฐ ๋์์ด ๋์๋ค? ๊ณ์ ์ฐ๊ณ ์์ ์ด์ ๊ฐ ์์.
์ด๋ฒคํธ ๊ธฐ๋ฐ LINQ,์ชฝ์ผ๋ก๋ ์ด๋?
๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ถ๋ถ์ ๋บ Rx๋ ํ๋ ์์ํฌ ์์์ ์ฐ์ผ ๋ถ๋ถ์ด ๊ทนํ ์ ์.
๊ตฌ๊ธ์ UniRx๋ Rx๋ฅผ ๊ฒ์ํ๋ฉด ๋ค์ํ ์๊ฐ ๋ธ๋ก๊ทธ๋ค์ด ๋์ค๊ณ ์ด๊ฒ์ ๊ฒ Before, After ์์ ์ฝ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด์ "Rx๋ ์ด๋ ๊ฒ ํ๋ฅญํ๋ค!"๋ผ๊ณ ์๊ธฐํจ.
๋ฌธ์ ๋ ๊ฑ๋ค๊ฐ ์์ฑํ Before ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ก์ง์ด ๋งค์ฐ ๋จ์ํ๊ฑฐ๋ ์ ๋ฐ ์์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ฉด ์๋๋ค์ ํ๋ณธ์ ์ธ ์ฝ๋๋ผ๋๊ฑฐ์.
"HP๊ฐ 0์ด ๋ ๋๋ฅผ ๊ฐ์ํ๋ค๊ฐ 0์ด ๋๋ฉด OnDead ํจ์๋ฅผ ์คํํด์"
=> HP์ event๋ฅผ ๋ฑ๋กํด๋๊ณ HP ๊ณ์ฐ ์ค์ 0์ด ๋์ ๋ ํต๋ณด๋ฅผ ๋ฐ์ง ๋๊ฐ ๋ฉ์ฒญํ๊ฒ HP๊ฐ 0์ธ์ง ์๋์ง๋ฅผ ๊ณ์ ๊ฐ์ํ๊ณ ์์?
"Buffer๋ฅผ ์ด์ฉํด์ ๋๋ธ ํด๋ฆญ์ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด์!"
=> ์ค์๊ฐ์ผ๋ก ๋๋ธ ํด๋ฆญ ๊ฐ๊ฒฉ์ด๋ ํด๋ฆญ ํ์๋ฅผ ๋ฐ๊พธ๊ณ ์ถ์ผ๋ฉด ๊ทธ๋๋ง๋ค ์คํธ๋ฆผ์ ์๋ก ๊ตฌ์ฑํด์ผํ์์? ์ด๊ฒ ์ข์๊ฑฐ ๋ง๋?
์ฌ์ค์ ๊ฒ์์ผ๋ก ๋์ค๋ ์ ๋ณด๋ค์ ๊ทธ๋ฅ ์ง์ง ๋ญ๊ฐ ์ข์์ง ๋ชจ๋ฅด๋ Rx ์ข์ ํธ์์ธ๋ค์ ํธ์๋ผ๊ณ ๋ด์ผํ๋ค.
๋ค๋ง ๋งํ๋ฏ์ด ์ฐ์ผ ๋ถ๋ถ์ด ์์ ์๋๊ฒ ์๋๋ค, ์ ์๊ฑฐ์ง.
๋จ๋
์ผ๋ก ๋์ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ UI ๋ถ๋ถ์์ ๋ถ๋ช
์ ์ฉํ๊ฒ ํ์ฉํ ๊ณณ์ด ๋ง์.
"- Use UniRx as well, if your game architecture relies heavily on event handling. I'm working on a mobile multiplayer RPG with real-time combat. We use ECS for the core gameplay loop, but everything else (UI, resource management, meta) is built using traditional event-based approach. So for gameplay events we have special IComponentData and separate systems to handle those, but for non-gameplay stuff I'd still use IObservable as it's the interface to describe push-based streams (as opposed to pull-based async IEnumerable)"
๋ฉํฐํ๋ ์ด์ด RPG ๊ฒ์์ ๋ง๋๋ ํ ๊ฐ๋ฐ์๋ ๊ฒ์ ํ๋ ์ด ๋ถ๋ถ์ ์ ํต์ ์ธ ์ด๋ฒคํธ ๊ธฐ๋ฐ ๊ตฌ์กฐ๋ก ์์ฑ๋์ด ์์ด ์์ฐ์ง๋ง, ๊ฒ์ ํ๋ ์ด ์ธ์ ์ธ ๋ถ๋ถ์์ ์ฌ์ฉํ๋ค๊ณ ํจ.
๋ฌธ์ ๋ ์์ฃผ ํ์ ๋ ๊ณณ์ ๋ถ๋ถ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๊ณ Rx ํ๋ ์์ํฌ๋ฅผ ํ๋ก์ ํธ์ ์น์ด์ผํ๋๋๊ฑฐ์.
๋ถ๋ถ์ ์ผ๋ก ํ์ฉํ๊ธฐ ์ํด Rx ํ๋ ์์ํฌ๋ฅผ ํ๋ก์ ํธ์ ์น์์ผ๋ก์จ ์๊ธธ ์ ์๋ ์ฌ๋ฌ ๋ฌธ์ ๋ฅผ ๊ฐ๋นํ ๊ฒ์ธ๊ฐ?
๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ฌ๊ธฐ์ 'No'๋ผ๊ณ ๋ตํ๊ณ ๊ทธ๋์ ๋ฒ๋ ค์ง ๊ฒ์.
์์ํ๋ฏธ๋ ๊ธฐ์ฌ์ ์์ง Kotlin์ด๋ Swift์์ Rx๊ฐ ํ๋ฐํ ์ฐ์ธ๋ค๊ณ ์๊ธฐํ์ง๋ง, ์ฐพ์๋ณด๋๊น ์ ์ชฝ๋ ๋ถ์๊ธฐ๋ ๊ฐ๋๋ผ.
์ฌ๊ธฐ๋ ๋๋ฒ๊น
๊ณผ ๊ฐ๋
์ฑ ๋ฌธ์ ๋๋ฌธ์ async/await์ผ๋ก ๋์ด๊ฐ๋ ค๊ณ ํ๊ณ , UI ์ชฝ์๋ ์ ์ฉํ๋๊น ๊ทธ ๋ถ๋ถ์์ ํ์ ํด์ ์ฌ์ฉํ๋ ค๊ณ ํจ.
Kotlin๊ณผ Swift๋ ์์ฒด์ ์ผ๋ก Rx ํ๋ ์์ํฌ๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ๋ค UI์ชฝ๊ณผ ํธํ์ฑ์ด ์ข๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์๋ค์ด ๊ตณ์ด ๊ผญ ๋ฒ๋ ค์ผํ ์ด์ ๋ ์์.
ํ์ง๋ง ์ ๋ํฐ๋ ์๋์ง.
๊ทธ๋ผ ์์ํ๋ฏธ๋ ์๋ก์ด C# Rx ํ๋ ์์ํฌ์ธ R3๋ฅผ ์ ๋ง๋ค์๋?
"๊ทธ๋ ๋ค๋ฉด Rx์ ๊ฐ์น๋ ์ด๋์ ์์๊น์? ์ ๋ 'LINQ์ LINQ to Events๋ฅผ ์ด์ฉํ ๋ฉ๋ชจ๋ฆฌ ๋ด ๋ฉ์ธ์ง๋ฅผ ์ฒ๋ฆฌ'๋ผ๋ ๊ทผ๋ณธ์ผ๋ก ๋์๊ฐ๋ค๊ณ ๋ฏฟ์ต๋๋ค."
"๊ฒ์ ์์ง(Unity)์ ์ฌ์ฉ๋๋ UniRx ๊ฐ๋ฐ์๋ก์ ๋ณต์กํ๊ณ Event๊ฐ ๋ง์ ๊ฒ์ ์ดํ๋ฆฌ์ผ์ด์
์๋ ์ ๋ Rx๊ฐ ๋งค์ฐ ์ ์ตํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๊ด์ฐฐ์(Observer) ํจํด๊ณผ Event์ ์ค์์ฑ์ ๋ถ์ธํ ์ ์์ผ๋ฉฐ, "๋ ๋์ Event"๋ก์์ Rx์ ์ญํ ๋๋ ๊ถ๊ทน์ ์ธ ๊ด์ฐฐ์ ํจํด์ ๋ณํ์ง ์์ต๋๋ค.
"์ ๋ Rx์ ๊ฐ์น๋ฅผ ๋์ด๋ฆฌ๊ณ ์ถ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ Rx๋ฅผ ์ฌ๊ฑดํ๋๊ฑด ์ ๋ง์ด ํ ์ ์๋ค๊ณ ๋ฏฟ์์ต๋๋ค."
// Rx๊ฐ ์๊ธฐ ์ปค๋ฆฌ์ด์ ๋ง์ ์ํฅ์ ๋ผ์ณ์ ์ด๋ฐ ๋ง์ ํ๋๊ฑฐ์
์์ฝํ๋ฉด "Rx ์กด๋ ์ข์๋ฐ ์ ์์ฐ๋? ๋ด๊ฐ ์๋ก ๋ง๋ค์์ผ๋ ์จ์ค."์
์ฐธ ํธ๋ฃจ Rx ์ข์ ํธ์์ธ์ด๋ผ๊ณ ํ ์ ์์.
โโโ
๊ฒฐ๋ก
UniRx ๋ฐฐ์์ผํ๋? ์ง์งํ๊ฒ ๊ณ ๋ฏผํ ํ์ ์ ํ ์์.
๋ฐฐ์ฐ๊ณ ์ถ์ผ๋ฉด ๋ฐฐ์์ ์จ, ํธํ ์ฌ๋ํํ
๋ ๋ถ๋ช
ํธํ๊ฒ ์ง.
ํ์ง๋ง Rx๊ฐ ํ์ ๋ ์๋๊ณ , ๋ฏธ๋๋ฅผ ์ง๋ฐฐํ ํจ๋ฌ๋ค์๋ ์๋๋ฉฐ, ์ ๋ดํ ์ด์ ๋ ์๋ค.
์จ๋ณด๋๊น ๋ณ๋ก ๊ฐ์? ์ฐ์ง๋ง. ํ์ฌ๋ก์ฌ ๊ทธ์ ๊ฐ๋ผ์๊ณ ์๋ ๋ฐฐ์ผ ๋ฟ์.
"์ด ์ข์๊ฑธ ์ ์์ฐ์ง? ์ ์ด๋ ๊ฒ ์ ๋ณด๊ฐ ์์ด? ์ญ์ ํ๊ตญ ๊ฐ๋ฐ์ ์๋ผ๋ค์ ๋ฒ ๋์ค๋ง ์์ง ์ค๋ ฅ์ด ์์ด"
์ข์๊ฑธ ์ ์์ฐ๊ฒ ๋? ์์ข์ผ๋๊น ์์ฐ๋๊ฑฐ์.
๊ธฐ์ ์ ์๋ ์ ๋ณด๋ก ํ๋จํ์ง๋ง๊ณ ์ต๊ทผ ์ ๋ณด๋ก ํ๋จํด๋ผ.
์ ๊ทธ๋ฆฌ๊ณ UniRx๋ฅผ ์ฐ๋ฉด ํผํฌ๋จผ์ค์ ์ข๋ค๋๋ ์ด์ํ ์๋ฆฌ๋ฅผ ํ๋ ์ ๋ค์ด ์๋๋ฐ,
Observing ๋ฐฉ์์ด ์ ๋ ํผํฌ๋จผ์ค์ ์ข์ ์๊ฐ ์๋ค. ๋ฌผ๋ก ์ ๋๋ก ์ฌ์ฉํ๋ฉด ํผํฌ๋จผ์ค๊ฐ ๋ ๋๋น ์ง ๊ฒ๋ ํฌ๊ฒ ์์.
ํ์์ ์ฝ๋๋ฅผ ๊ฐ๋ก๊ฐ์ด ์งฐ์ผ๋ฉด, Rx์ ๋ง์ถฐ์ง๋ฉด์ ์ฝ๋๊ฐ ์ ๋ฆฌ๊ฐ ๋๋๊น ์๋์ ์ผ๋ก ํผํฌ๋จผ์ค๊ฐ ์ฌ๋ผ๊ฐ ์ ์์.
unirx ์ฐ๋ฉด ๋ฉํฐ์ฐ๋ ๋ ๋๋ ๊ธฐ๋ฅ๋ค์ด ์์ด์ ํผํฌ๋จผ์ค๋ ๋์์ง๋๊ฑฐ ์๋์ผ? ์ ๋ชจ๋ฆ
super ์ด๋๋ฆผ
๋๋ ๊ณต๊ฐํด์ unirx๋ ์ฌ์ฉ์ํ๊ณ unitask๋ง ์ฌ์ฉ์ค.
์ ๋ถ ์ ๋ง ๋ฌด์๋ฌด์ํ ๋ถ์ด๋๋ผ.
unitask ์ ๋ณด ์ฐพ์๋ณด๋๋ผ ๋ณธ์ง ๋ธ๋ก๊ทธ๋ ๊ฐ๋ดค๋๋ฐ
๋๋ ์ปค์ ์ ๋ฐ ์ฌ๋์ด ๋๊ณ ์ถ์ด!
https://neue.cc/
๋ญ๊ฐ๋ญ๊ฐ ์ ๋งคํด๋ณด์ฌ์ ์๊ท๋ชจ๋ก๋ง ์ฌ์ฉ์ค์ธ๋ฐ ์ด ๊ธ์ ์ฝ์ผ๋๊น ๋ช ํํด์ง๋ค์ ใณใณ
๊ทธ๋๋ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ๊ธฐ์ ์ข๋ค๊ณ ์๊ฐํจ ๋๋ฌด ํธํด
๋ด๋ง์ด ์ด๊ฑฐ์ UniRX๋ก ํธ์ถํ๋ ํจ์์ ๋ธ๋ ์ดํฌํฌ์ธํธ ํ๋ฒ๋ง ์ฐ์ด๋ณด๊ณ ์ฝ์คํ ๋ณด๋ฉด ์กด~๋๊ธด๊ฒ๋์ค๋๋ฐ ๋๋ฒ๊น ์ด์ผ ๋ญ Rx๊ณ ์๊ฐ๋๋ฉด ํ ์์๋ค ์น๊ณ ์ด๊ฒ ํผํฌ๋จผ์ค๊ฐ ์ข์๊ฑฐ๋ค๋ผ๋ ์๊ฐ์ ํ ์๊ฐ ์๋๋ฐ ๋ง์ด์ง
์์ฝ: 1. UniRx๋ฅผ ๋ฐฐ์์ผ ํ ํ์๋ ์์. 2. Rx๋ ํ์ฌ๋ก์๋ ํ์ ์ ์ด๊ฑฐ๋ ๋ฏธ๋๋ฅผ ์ง๋ฐฐํ ํจ๋ฌ๋ค์์ ์๋. 3. Rx๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ๊ฐ๋ฐ์์ ํธ์์ ์ ์ฉ์ฑ์ ์ฐ์ ๊ณ ๋ คํด์ผ ํจ. 4. Rx์ ํผํฌ๋จผ์ค ์ฐ์์ฑ ์ฃผ์ฅ์ ์ฌ์ค์ด ์๋. 5. UI ๋ฑ ํน์ ๋ถ๋ถ์์ Rx๋ฅผ ํ์ฉํ๋ ๊ฒ์ ์ ํฉํ ์ ์์. 6. ์ต์ ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ธฐ์ ์ ํ๋จํ๊ณ ๊ฒฐ์ ํ๋ ๊ฒ์ด ์ค์ํจ.
๋ unitask๋ ์ฐ๊ณ ์์
throttle์ด๋ merge ์ฌ์ฉํ๋ ๋ถ๋ถ์ ์ด๋ป๊ฒ ์๊ฐํจ?? ๋๋ ์ด๊ฑฐ๋ฅผ ๋์ฒดํ ์ ์์ผ๋ฉด ํ๊ณ ์ถ์๋ฐ ์์ง ์ ๋ชจ๋ฅด๊ฒ ์...
๋๊ฐ ๊ทธ๊ฑธ ์ ๊ผญ ํ์๋ก ํ๋์ง ๋ชจ๋ฅด๋๊น ๋๋ตํด์ค ์ ์๋ ๋ถ๋ถ์ด ์๋. ํ์ง๋ง ๋ณดํต์ ๊ฒฝ์ฐ UniTask๋ก ์ ํ์ด ๊ฐ๋ฅํจ. ์ฐ์ง ๋ง๋ผ๋ ์๊ธฐ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ํธํ๋ฉด ๊ทธ๋๋ก ์จ. ๋ ์ข์๋ฐ ๊ตณ์ด ๊ฐ๋ค๋ฒ๋ฆด๋ ค๊ณ ํ ํ์ ์์.
_subscription = _targetProvider.OnTargetChanged .Merge(_targetProvider.OnTargetStateChanged) .Merge(_goalSelector.OnGoalChanged) .Merge(_onExecuteDone) .Throttle(TimeSpan.FromSeconds(0.2f)) .Subscribe(OnNext); ์ด๋ฐ์์ผ๋ก ์ฐ๋ ๋ถ๋ถ์ด ํ๋ ์์. ์ด๋ฒคํธ๋ก ํํํ์๋ฉด ํํ๊ฐ๋ฅํ 3๊ฐ์ง์ ์ด๋ฒคํธ๊ฐ ์๊ณ ์ด ์ธ๊ฐ์ง ์ ํธ๋ฅผ mergeํ๊ณ throttleํด์ ๋ฐ๊ณ ์์.