ECS
์
React-Three-Fiber ๋ฏธ๋ํ์ ํ๋ฉฐ ๊ฒ์๋ก์ง & ๋ ๋ ํจํด์ ๋ํด ์ฐพ์๋ณด๋ค๊ฐ ECS๋ฅผ ๋ฐ๊ฒฌํ๋ค. ์ง๊ด์ ์ด๊ณ ์ค์ฉ์ ์ธ ํจํด์ด๋ผ๊ณ ์๊ฐ๋ผ์ ๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ๋ค์ ์ ๋ฆฌํด ๋ณธ๋ค.
๊ทธ๋์ ๋ด๊ฐ ํ๋ ๋ฐฉ๋ฒ๋ค
C++ / DirectX
3D / 2D ๊ฒ์์ ํด๋ผ์ด์ธํธ ๋ฐ ์๋ฒ๋ฅผ ๊ฐ๋ฐํ๋ ์๊ธฐ์๋ค. ์์ง ์ด๋ผ๊ณ ๋ถ๋ฅผ๋งํ ํ๋ ์์ํฌ๊ฐ ์์ด ๋ ๋ ๋ถ๋ถ๋ง ๋ํํด๋์ ์ ํธ์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ๊ฐ์ง๊ณ ๊ฐ๋ฐ์ ํ๋ค.
์์์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ฒด ๋ด์์ Update, Render ๋ชจ๋ ์งํํ๋ ๊ตฌ์กฐ๋ก ๊ฐ๋ฐํ๋ค.
Unity
Unity๋ ๊ธฐ๋ณธ์ ์ผ๋ก GameObject๋ฅผ ์์ฑ์ ํ๊ณ ๊ธฐ๋ํ๋ ๋์๋ค์ ์คํฌ๋ฆฝํธ๋ก ๋ง๋ค์ด ์ค๋ธ์ ํธ์ ํ ๋นํ๋ ์ปดํฌ๋ํธ ๋ฐฉ์์ ๋ฐ๋ฅธ๋ค. ์ ์ถ๋ ฅ, ์์ง์, ๋ ๋๋ฑ์ ์ปดํฌ๋ํธํ ์ํจ๋ค. ํ๋์ ๊ฑฐ๋ํ ํด๋์ค๊ฐ ์กด์ฌํ๋๊ฒ ์๋, ๋ถ๋ฆฌ๋ ์ญํ ์ ๊ฐ์ง ์ปดํฌ๋ํธ๋ค์ ์กฐํฉ์ผ๋ก ๋ณต์กํํ๋(behaviour)์ ํ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋๋๊ฒ. ์ด ๊ตฌ์กฐ ๋ด์์ ๊ฐ๋ฐ์์ ์ญ๋๊ณผ ์ทจํฅ์ ๋ฐ๋ผ ๋ค์ํ ํจํด์ ์ ์ฉํ๊ฒ ๋๋๊ฒ์ด๋ค.
classDiagram
class GameObject
class Component
class RigidBody
class MonoBehaviour
RigidBody --|> Component
MonoBehaviour --|> Component
GameObject --> Component: list
๊ฐ ์ปดํฌ๋ํธ์์ ๊ฐ์ ํ๊ณ ์ถ์ ๋ชฉ์ ์ ์ด๋ฃจ๋ฉด๋๋ค. ํ๋ ๋ฐ ๋ ๋๋ ์ปดํฌ๋ํธ๋ก ๊ตฌํ๋๋ฉฐ ์ด ๊ณผ์ ์ค ๋ค๋ฅธ ์ปดํฌ๋ํธ ํน์ GameObject๋ฅผ ์ฐธ์กฐํ ์ ์๋ค.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
public float thrust;
public Rigidbody rb;
void Start() {
rb = GetComponent<Rigidbody>();
}
void FixedUpdate() {
rb.AddForce(transform.forward * thrust);
}
}
R3F(React Three Fiber)
React๋ ์ ์ธํ ํ๋ก๊ทธ๋๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, Three๋ ๊ทธ๋ํฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. ๋๊ฐ์ง๋ฅผ ๊ฐ์ง๊ณ ๊ฒ์์ ๋ง๋ค๋ ์ด๋ค์์ผ๋ก ์ฌ์ฉํ๊ฒ ๋ ๊น.
<Canvas>
<Scene>
<Camera />
<GameObjects>
<Player name={"james"} weapons={weapons} />
{otherPlayers}
{enemies}
<Fairy target={"james"} />
<SomeEffect target={"james"} />
</GameObjects>
</Scene>
</Canvas>
Unity ์ฒ๋ผ ์บ๋ฐ์ค์๋ค๊ฐ ์ค๋ธ์ ํธ๋ค์ ๋์ดํด ๋๊ฒ๋๋ค. ์ปดํฌ๋ํธ๋ค์ ์ํธ ์ฐธ์กฐํ ์ ์๊ณ ๋ถ๋ชจ ์์์ผ๋ก ๋์ผ ์ ์๋ค. Fairy๋ ์บ๋ฆญํฐ๋ฅผ ๋ฐ๋ผ๋ค๋๋ ์์ ์ด๋ฏ๋ก ์๋ ๋ฐฉ๋ฒ๋ค์ฒ๋ผ ๊ตฌํํ ์ ์๋ค๊ณ ๋ณธ๋ค. SomeEffect ๋ ๋น์ทํ๋ค.
const Fairy = ({ target }) => {
const { findObjectByName } = useObjects();
const ref = useRef();
useFrame(() => {
const targetObject = findObjectByName(target);
ref.current.position = targetObject.position;
// do some actions
});
return <mesh ref={ref}>...</mesh>;
};
one way or another
๊ทธ๋์, ์ด๋ค ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ๋ฐ์ ํ๋ค๋ณด๋, ๊ฐ ๊ฐ์ฒด๋ง๋ค ํํํ๊ณ ์ ํ๋ ๋ฐ์ดํฐ(์ํ, ๋ชฉ์ ), ๊ทธ๋ฆฌ๊ณ ํ๋์ ์ง์ ์ํํ๊ฒ๋ ๋์์ธํ๋ค. 1) ํด๋์ค์ ๊ด๊ณ๋ฅผ ์ด๋ป๊ฒ ์ ๋ฆฝํ ๊ฒ์ธ์ง 2) ์ด๋ค ๋ฉ์๋๋ฅผ ๋
ธ์ถ์ํฌ๊ฑด์ง - ์ฃผ๋ก ์ด ๋๊ฐ์ง์ ๋ํด์ ๊ณ ๋ฏผํ๋ฉฐ ๋ก์ง์ ์์ฑํด๊ฐ๋ค. ์ปดํฌ๋ํธ์ ํ์๊ฐ ๋ณต์กํด์ง ์๋ก ์ฝ๋ ๋ฉ์ด๋ฆฌ๋ ๋น๋ํด์ง๊ณ ๊ฐ ๊ฐ์ฒด๊ฐ์ ์ปคํ๋ง์ ์ฌํ๋๋ค. ์ค๋ณต์ ์ ๊ฑฐํ๊ธฐ ์ํด ์์ ๋ฑ์ ์ฌ์ฉํ๊ฒ ๋์ง๋ง, ๊ฒฐ๊ตญ ์๊ตฌ์ฌํญ์ ๋ณ๊ฒฝ์ด๋ ๊ธฐ๋ฅ์ ์ถ๊ฐ์ ๋ณ๊ฒฝ๋๋ ์ฝ๋์ ์์ ๊ธฐํ๊ธ์์ ์ผ๋ก ๋์ด๋๋ค. ๋ํ ๋ณต์กํ ๋ก์ง์ ๊ฐ์ง ๋ฉ์๋๋ฅผ ์ฌ๋ฌ ๊ฐ์ฒด์์ ์ํํ๋ค๋ณด๋ฉด ์ฑ๋ฅ์ ๋จ์ด์ง๋ค.
์๊ฐํด๋ณด๋ ๊ฐ๋ฐ ๋ชฉ์ , ์ํฉ, ๊ฐ๋ฐ์์ ์ญ๋๋ฑ์ ๋ฌ๋ฆฐ ๋ฌธ์ ์ผ ์๋ ์๋ค. OOP์ ๋จ์ ์ ์ฐพ์ ECS๋ก ๋ฆฌํฉํ ๋ง ํ ๋ช๋ช ์์ ๋ค์ ์ฐพ์๋ณด์๋๋ฐ, ์ฒ์์ ์! ํ๋ค๊ฐ๋ ์ด๋ด ์ด๊ฑด OOP์ ๋ฌธ์ ๋ผ๊ธฐ๋ณด๋ค๋ ์ค๊ณ์ ์ฐจ์ด์ธ ๊ฒฝ์ฐ๋ ์๊ณ .
ECS(Entity Component System)
ECS๋ ์ปดํฌ์ง์ ์ ์ ๊ทน ํ์ฉํ๋ ํจ๋ฌ๋ค์์ด๋ค.
- Entity: ์ฃผ์ฒด
- Component: ์ํ
- System: ํ์
์ฃผ์ฒด์ ์ํ๋ฅผ ๋ถ์ฌํ๋ฉด, ์์คํ (๋์์ฐ)์ด ํ์๋ฅผ ์งํํ๋ค.
Unity ์์์ classic vs ECS
// classic component
public class SomeActionComponent : MonoBehaviour {
private float x;
private float y;
void Start() {
x = 0;
y = 0;
}
void Update() {
x++;
y++;
}
}
// ecs ์์
struct PositionComponent {
float x;
float y;
}
class MovePositionSystem : ComponentSystem {
protected override void OnUpdate() {
Entities.ForEach((ref PositionComponent position, in Data data) => {
// update logics
position.Value.x = data.x
position.Value.y = data.y
})
}
}
- ์์ธํ ๋ด์ฉ์: ์ ๋ํฐ ๋งค๋ด์ผ
ECS ์ ์ฅ์
ECS๋ ์๋ง์ ๊ฐ์ฒด๋ค์ด ์กด์ฌํ ๋ ์์ฃผ ๋น ๋ฅด๋ค. (์ฑ๋ฅ ๋น๊ต ์์) ํต์์ ์ธ OOP๊ธฐ๋ฒ์ผ๋ก ์์ฑ๋ ์ฝ๋๋ ์๋์ ๊ฐ๋ค. (์ถ์ฒ)
for each entity
if entity can move
move(entity)
switch entity attacking type
when shooter
shoot(entity)
when melee
meleeAttack(entity)
when nothing
doNothing(entity)
if entity has health
checkIfDead(entity)
๊ฐ์ฒด์ ๊ด์ ์์ ์กฐ๊ฑด์ ๋ฐ๋ผ ํ๋์ ์ํํ๋ค. ๋ฐ๋ฉด ecs๋ฅผ ๋ณด๋ฉด
for each entity which can move
move(entity)
for each entity which can shoot
shoot(entity)
for each entity which can meleeAttack
meleeAttack(entity)
for each entity which has health
checkIfDead(entity)
ํด์ผํ ์ผ๋ค์ ๋ชจ์์ ์์คํ ๋ณ๋ก ์ฒ๋ฆฌํ ๋ฟ์ด๋ค. ์ด๋ค ์ํฐํฐ์ธ๊ฐ๋ ํฌ๊ฒ ์ค์ํ์ง ์๋ค. ์ ๋ฆฌํด๋ณด๋ฉด
- ํ์ํ ์ฝ๋๋ง ์ํ
- Data Oriented Design ์ ์ฅ์ ์ ๊ทน ํ์ฉ ๊ฐ๋ฅ, ์บ์ ํํธ์จ ํฅ์ ๋ฑ(DOD์ ์ฑ๋ฅ ์ฐธ๊ณ )
- ์ฝ๋ ๊ฐ๋ ์ฑ
์ฝ๋ ๊ฐ๋ ์ฑ์ ๋ํด์๋ ์ฌ๋ฌ ๊ด์ ์ด ์์ ์ ์๋ค๊ณ ๋ณธ๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋ฐ์ดํฐ๋ก๋ถํฐ ์์ ํ ๋ถ๋ฆฌ๋ ํ์๋ ์์ํจ์ ํํ๋ก ์์ฑ๋ ๊ฒ์ด๋ฉฐ ๊ฐ๋ฐ์๋ ํ์ฌ ๊ตฌํํ๊ณ ์๋ ํ์์ ๋ํด์๋ง ์จ์ ํ ์ง์คํ ์ ์๊ฒ ๋๋ค๊ณ ๋ณธ๋ค. ๋ค๋ง ์ด๋ฅผ ์ํด์๋ SRP๋ฅผ ์ค์ํด์ผํ๋ค.(ํ๋์ ์์คํ ์ ํ๋์ ์ด์ ์ ๋ํด์๋ง ์ปดํฌ๋ํธ๋ฅผ ๋ณ๊ฒฝํ๋ค)
์๋ฌธ์๋ต
Q) ์ด๋ค ํจ์๋ ๋ฐ์ดํฐ๊ฐ ๋ ์ ์์๊น?
A) ๊ธฐ๋ณธ์ ์ผ๋ก ์ปดํฌ๋ํธ์๋ lambda์์ ํฌํจํ ์ด๋ค ์ฐ์ฐ๋ ๋ฃ์ง ์๋๊ฒ ์ข๋ค
Q) ECS ๋ Data Oriented Deisgn ์ธ์ง?
A) ECS ๊ธฐ๋ฒ์ ์ด๋ค๊ณ ํด์ DOD๊ฐ ๋๋๊ฒ์ด ์๋, DOD๋ฅผ ํ์ฉํ๊ธฐ ์ข์ ํ๊ฒฝ์ด ๋ง๋ค์ด์ง๋ค.
ECS for Web
- ECS ํจํด์ ์น ๊ฐ๋ฐ์ ์ ์ฉํ๋ค๋ฉด? - ์์ฑ์ค
๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- miniplex: ecs in typescript github link
์ฐธ๊ณ ๋งํฌ
https://www.sebaslab.com/the-quest-for-maintainable-code-and-the-path-to-ecs/
Leave a comment