Entity Component System

8262 단어 EnTTECS

이 기사에 대하여



Entity Component System(이후 ECS)에 대해 설명합니다. 또한 ECS의 C++ 구현EnTT에 대해 소개합니다.

Entity Component System 정보



Entity Component System은 설계 패턴 중 하나입니다. 상속보다 위양을 우선하는 원칙에 따라,
엔티티(게임 장면을 구성하는 적 캐릭터, 문, 총알, etc...)을 부품을 조합하여 구현할 수 있도록 합니다. 이 기술은 긴 상속 관계로 인한 불투명한 구현을 피하고 디자인을 깨끗하게 만듭니다. 반면에 런타임 오버 헤드라는 단점도 있습니다.

ECS는 다음 세 가지 요소로 구성됩니다.
  • Entity
    컴퍼넌트를 추가하는 컨테이너입니다. 일반적으로 계층 구조를 취합니다. (일반적으로 Entity에는 SubEntity가 있습니다.)
  • Component
    객체의 동작, 외형, 데이터를 정의하는 클래스입니다.
  • 시스템
    System은 Entity와 Component를 활용하여 데이터를 기반으로 하는 동작과 로직을 유지합니다.

  • UML로 표현하면 이런 느낌입니다.
    Entity에 대해 여러 Component가 연결됩니다.



    System은 Entity를 통해 Entity 구성 요소의 Component에 액세스할 수 있습니다. 또, Entity를 개입시키지 않고 모든 Component에 대해서 루프할 수도 있습니다.

    ECS는 기존 OOP(객체 지향) 접근법에 비해 다음과 같은 이점이 있습니다.
    1. Entity는 포인터가 아닌 ID로 유지할 수 있습니다. 이로 인해 댕글링 포인터 (가리키는 대상이 유효하지 않은 상태에있는 포인터)가 발생하지 않습니다.
    2. 외부에 상태를 유지하기 쉬워집니다. 상태를 읽을 때 포인터를 다시 작성할 필요가 없습니다.
    3. 메모리의 데이터 위치를 재배치할 수 있습니다.
    4. 포인터를 사용하지 않으므로 네트워크를 통해 엔터티를 주고받을 수 있습니다.

    해보자! !



    위를 읽어보고 ECS에서 놀고 싶어졌다고 생각합니다. C++에서 ECS 구현 EnTT을 사용하여 ECS를 구현해 봅시다.

    Sample.cpp
    #include <entt/entt.hpp>
    #include <cstdint>
    struct position {
        float x;
        float y;
    };
    struct velocity {
        float dx;
        float dy;
    };
    
    // Systemに当たる部分。Entityの位置を更新する。
    void update_position(std::uint64_t dt, entt::registry &registry) {
        registry.view<position, velocity>().each([dt](auto &pos, auto &vel) {
            // gets all the components of the view at once ...
            pos.x += vel.dx * dt;
            pos.y += vel.dy * dt;
            // ...
        });
    }
    int main() {
        entt::registry registry;
        std::uint64_t dt = 16;
        for(auto i = 0; i < 10; ++i) {
            auto entity = registry.create();
            registry.assign<position>(entity, i * 1.f, i * 1.f);
            if(i % 2 == 0) { registry.assign<velocity>(entity, i * .1f, i * .1f); }
        }
        update_position(dt, registry);
    }
    

    그리고 싶을 때는 새로운 System과 Component를 추가하면 할 수 있습니다.

    draw.cpp
    struct Drawable {
        Image image; // 描画に使う画像
    };
    void update_drawing(entt::registry& registry)
    {  
        registry.view<Drawable, const position>().each([dt](auto &pos, auto &vel) {
          // 描画に使うロジック
        });
    }
    

    참고문헌


  • Entity Systems Wiki
  • Entity component system (ECS) explained with tennis players and courts
  • EnTT
  • 좋은 웹페이지 즐겨찾기