Component와 그 데이터를 처리하는 System으로 분리하는 아키텍처.

요소 역할
Entity 고유 ID. 실체를 구분하는 식별자
Component 데이터만 가진 조각
System 특정 Component 조합을 가진 Entity를 처리하는 로직

Entity

Entity는 게임 월드에 존재하는 하나의 ID

Entity 의미
Player Entity 플레이어를 나타내는 ID
Enemy Entity 적을 나타내는 ID
Bullet Entity 총알을 나타내는 ID
Item Entity 아이템을 나타내는 ID
using Entity = uint32;

Entity Player = 1;
Entity Enemy = 2;
Entity Bullet = 3;

Entity 자체는 기능을 가지지 않는다.
Entity가 어떤 Component를 가지고 있느냐에 따라 의미가 결정된다.


Component

Component는 데이터만 가진다.

struct PositionComponent
{
    float X;
    float Y;
    float Z;
};

struct VelocityComponent
{
    float X;
    float Y;
    float Z;
};

struct HealthComponent
{
    float CurrentHealth;
    float MaxHealth;
};

Component는 가능하면 로직을 가지지 않는다.
데이터를 담고, System이 그 데이터를 처리한다.


System

특정 Component 조합을 가진 Entity들을 찾아서 처리한다.
예를 들어 이동 시스템은 PositionComponentVelocityComponent를 가진 Entity만 처리한다.

void MovementSystem(float DeltaTime)
{
    for (Entity E : EntitiesWith<PositionComponent, VelocityComponent>())
    {
        PositionComponent& Position = GetComponent<PositionComponent>(E);
        VelocityComponent& Velocity = GetComponent<VelocityComponent>(E);

        Position.X += Velocity.X * DeltaTime;
        Position.Y += Velocity.Y * DeltaTime;
        Position.Z += Velocity.Z * DeltaTime;
    }
}

System은 Entity가 어떤 Component를 가지고 있는지를 기준으로 동작.


ECS 예시

플레이어, 적, 총알을 ECS로 표현하면 다음처럼 구성할 수 있다.

Entity Component 조합
Player Position, Velocity, Health, Input, Mesh, Inventory
Enemy Position, Velocity, Health, AI, Mesh
Bullet Position, Velocity, Damage, Collider, Lifetime
Item Position, Mesh, ItemData, Pickup

상속 구조 없이 Component 조합만으로 대상의 특징을 만든다.


OOP 방식과 ECS 방식

OOP는 기능 조합이 많아질수록 상속 구조가 복잡해지고 메모리가 커진다.

방식 특징
OOP 클래스 상속 중심
ECS Component 조합 중심
OOP 확장 새 클래스를 만들기 쉬움
ECS 확장 새 Component와 System을 추가하기 쉬움
OOP 문제 상속 구조가 깊어질 수 있음
ECS 문제 구조가 추상적이고 초기 설계가 어려움

ECS 장점

  • ECS는 상속보다 조합을 중심으로 한다.
    기능이 늘어나도 상속 계층을 깊게 만들 필요가 없다.

  • Component는 데이터만 가지고, System은 로직만 가진다.
    데이터 구조와 처리 흐름이 명확해진다.

  • ECS는 많은 Entity를 한 번에 처리하는 데 강하다.
    OOP 방식에서는 각 Actor가 자기 Tick에서 개별적으로 동작한다.
    ECS에서는 System이 모든 Entity를 한 번에 처리한다.

  • ECS는 데이터 중심 구조이기 때문에 CPU 캐시 효율과 대량 처리에 유리하다.


ECS 단점

  • 구조가 직관적이지 않을 수 있음
    OOP에서는 Enemy->Attack()처럼 객체 중심으로 읽힌다.
    ECS에서는 AttackSystemAttackComponent를 가진 Entity들을 처리한다.

  • 디버깅이 어려울 수 있음
    로직이 여러 System으로 나뉘기 때문에,
    하나의 Entity가 왜 특정 상태가 되었는지 추적이 어려울 수 있다.

  • 작은 프로젝트에는 과할 수 있음
    Entity 수가 적고, 기능이 단순한 프로젝트라면 ECS 구조가 오히려 복잡할 수 있다.

Unreal의 Actor Component와 ECS 차이

Unreal의 Component는 기능을 붙이는 객체,
ECS의 Component는 순수 데이터

Unreal Actor Component

flowchart TD
    A[AActor] --> B[UActorComponent]
    A --> C[USceneComponent]
    C --> D[UStaticMeshComponent]
    C --> E[USkeletalMeshComponent]

Unreal의 Actor Component 구조는 전통적인 의미의 ECS와 다르다.

구분 Unreal Actor Component ECS
중심 Actor 객체 Entity ID
Component UObject 기반 기능 객체 데이터 조각
로직 위치 Actor 또는 Component 내부 System
Tick Actor/Component별 Tick 가능 System 단위 업데이트
데이터 배치 객체 단위로 흩어짐 Component 배열 중심
처리 방식 객체 중심 데이터 중심

Unreal에서 ECS가 필요한 경우

대량의 객체를 처리해야 하는 경우 ECS적 사고가 유용하다.

Actor를 수천 개 Tick시키는 대신, Manager나 Subsystem이 데이터를 모아서 일괄 처리하면 ECS에 가까운 구조가 된다.


Unreal식 ECS 응용

ECS 원칙 Unreal 적용
데이터와 로직 분리 DataAsset, Struct, Component 분리
System 단위 처리 Subsystem, Manager Actor 사용
대량 객체 일괄 갱신 개별 Tick 제거 후 Manager Tick 사용
Component 조합 ActorComponent로 기능 조합
캐시 친화적 데이터 TArray 구조체 배열 사용
이벤트 기반 처리 GameplayMessageSubsystem, Delegate 사용

ECS의 데이터 중심 처리 장점을 일부 가져오는 방식

USTRUCT()
struct FEnemyRuntimeData
{
    GENERATED_BODY()

    UPROPERTY()
    TObjectPtr<AActor> EnemyActor;

    FVector Location;
    FVector Velocity;
    float Health;
    float UpdateInterval;
};
void UEnemySimulationSubsystem::UpdateEnemies(float DeltaTime)
{
    for (FEnemyRuntimeData& Enemy : Enemies)
    {
        Enemy.Location += Enemy.Velocity * DeltaTime;
    }
}

요약

개념 요약
Entity 객체를 나타내는 ID
Component Entity가 가진 데이터
System Component 조합을 처리하는 로직
ECS 핵심 상속보다 조합, 객체보다 데이터 중심
장점 대량 처리, 확장성, 캐시 효율, 병렬화
단점 구조 난이도, 디버깅 난이도, 초기 설계 비용
Unreal Component 기능 객체에 가까움
ECS Component 순수 데이터에 가까움
반응형

'CS' 카테고리의 다른 글

컴퓨터 구조  (0) 2026.04.01
스레드  (0) 2026.04.01
메모리  (0) 2026.04.01