ABOUT ME

-

Total
-
  • C/C++ Entity Component System (Flecs)
    컴퓨터/C & C++ 2020. 8. 4. 19:46
    728x90
    반응형

    Flecs

    소개

    Flecs는 C89 / C99 / C++11를 위한 빠르고, 가벼운 Entity Component System(ECS) 빌드 툴이다.

    아래는 foot-print 목록이다.

    • Blazing fast iteration speeds with direct access to raw C arrays across multiple components
    • Built-in support for entity hierarchies, prefabs, nested prefabs and prefab variants
    • An efficient lock-free architecture allows for modifying entities across multiple threads
    • Expressive entity queries with support for and, or, not and optional operators
    • Systems that are time triggered, rate triggered, run every frame or run only when needed
    • A customizable core that lets you include only the features you need

     

    1. Entity Component System

     ECS란 무엇일까?

    한줄로 표현하자면, 데이터 목적(data-oriented)으로 코딩을 하는 시스템이다. (게임에 많이 쓰임)

    ECS에는 아래 3가지의 핵심 키워드가 있다.

    • entity (독립체) : 독립체들, things, indices, ID라고 생각하면 편하고, 값을 갖고 있지 않음
    • component (요소) : 데이터, entity로 정리되기 보단, 데이터 자체로 정리됨 (data-oriented)
    • system (체계) : 데이터를 변형하기 위한 코드

    system 예제) 모든 독립체들이 프레임마다 움직일 때 위치를 업데이트 해줌

     

    정리

    • entity들은 unique ID를 갖는다.
    • component는 plain 데이터 타입을 갖는다.
    • systemcomponent 기반 entity들에 맞는 행동들을 제어한다.

     

    2. Flecs 라이브러리

    우선 라이브러리를 사용하려면 아래 두 파일을 작업 환경에 추가한다.

    flec.c
    0.60MB
    flec.h
    0.28MB

    github.com/SanderMertens/flecs/blob/master/flecs.c

    github.com/SanderMertens/flecs/blob/master/flecs.h

     

    1. Hello World

    #include "flec.h"
    
    typedef struct Position {
        float x;
        float y;
    } Position;
    
    int main(int argc, char *argv[]) {
        /* Create the world, pass arguments for overriding the number of threads,fps
         * or for starting the admin dashboard (see flecs.h for details). */
        ecs_world_t *world = ecs_init_w_args(argc, argv);
    
        /* Register a component with the world. */
        ECS_COMPONENT(world, Position);
    
        /* Create a new empty entity  */
        ECS_ENTITY(world, MyEntity, 0);
    
        /* Set the Position component on the entity */
        ecs_set(world, MyEntity, Position, {10, 20});
    
        /* Get the Position component */
        const Position *p = ecs_get(world, MyEntity, Position);
    
        printf("Position of %s is {%f, %f}\n", 
            ecs_get_name(world, MyEntity), p->x, p->y);
    
        /* Cleanup */
        return ecs_fini(world);
    }

    2. Move System (프레임마다  1.0 좌표 이동)

    #include "flec.h"
    
    /* Component types */
    typedef struct Vector2D {
        float x;
        float y;
    } Vector2D;
    
    /* Typedefs can be used as component types */
    typedef Vector2D Position;
    typedef Vector2D Velocity;
    
    /* Implement a simple move system */
    void Move(ecs_iter_t *it) {
        /* Get the two columns from the system signature */
        ECS_COLUMN(it, Position, p, 1);
        ECS_COLUMN(it, Velocity, v, 2);
    
        for (int i = 0; i < it->count; i ++) {
            p[i].x += v[i].x;
            p[i].y += v[i].y;
    
            /* Print something to the console so we can see the system is being
             * invoked */
            printf("%s moved to {.x = %f, .y = %f}\n",
                ecs_get_name(it->world, it->entities[i]),
                p[i].x, p[i].y);
        }
    }
    
    int main(int argc, char *argv[]) {
        /* Create the world, pass arguments for overriding the number of threads,fps
         * or for starting the admin dashboard (see flecs.h for details). */
        ecs_world_t *world = ecs_init_w_args(argc, argv);
    
        /* Register components */
        ECS_COMPONENT(world, Position);
        ECS_COMPONENT(world, Velocity);
    
        /* Define a system called Move that is executed every frame, and subscribes
         * for the 'Position' and 'Velocity' components */
        ECS_SYSTEM(world, Move, EcsOnUpdate, Position, Velocity);
    
        /* Create an entity with Position and Velocity. Creating an entity with the
         * ECS_ENTITY macro is an easy way to create entities with multiple
         * components. Additionally, entities created with this macro can be looked
         * up by their name ('MyEntity'). */
        ECS_ENTITY(world, MyEntity, Position, Velocity);
    
        /* Initialize values for the entity */
        ecs_set(world, MyEntity, Position, {0, 0});
        ecs_set(world, MyEntity, Velocity, {1, 1});
    
        /* Set target FPS for main loop to 1 frame per second */
        ecs_set_target_fps(world, 1);
    
        printf("Application move_system is running, press CTRL-C to exit...\n");
    
        /* Run systems */
        while ( ecs_progress(world, 0));
    
        /* Cleanup */
        return ecs_fini(world);
    }

    3. Sorting

    #include "flec.h"
    
    typedef struct Position {
        float x;
        float y;
    } Position;
    
    /* Order by x member of Position */
    int compare_position(
        ecs_entity_t e1,
        void* ptr1,
        ecs_entity_t e2,
        void* ptr2)
    {
        Position* p1 = ptr1;
        Position* p2 = ptr2;
        return p1->x - p2->x;
    }
    
    /* Iterate query, printed values will be ordered */
    void print_query(ecs_query_t* q) {
        ecs_iter_t it = ecs_query_iter(q);
        while (ecs_query_next(&it)) {
            Position* p = ecs_column(&it, Position, 1);
    
            int32_t i;
            for (i = 0; i < it.count; i++) {
                printf("{%f, %f}\n", p[i].x, p[i].y);
            }
        }
    }
    
    int main(int argc, char* argv[]) {
        ecs_world_t* world = ecs_init();
    
        ECS_COMPONENT(world, Position);
    
        /* Create entities, set Position in random order */
        ecs_entity_t e = ecs_set(world, 0, Position, { 3, 0 });
        ecs_set(world, 0, Position, { 1, 0 });
        ecs_set(world, 0, Position, { 6, 0 });
        ecs_set(world, 0, Position, { 2, 0 });
        ecs_set(world, 0, Position, { 5, 0 });
        ecs_set(world, 0, Position, { 4, 0 });
    
        /* Create a query for component Position */
        ecs_query_t* q = ecs_query_new(world, "Position");
    
        /* Order by Position component */
        ecs_query_order_by(world, q, ecs_entity(Position), compare_position);
    
        /* Iterate query, print values of Position */
        printf("-- First iteration\n");
        print_query(q);
    
        /* Change the value of one entity, invalidating the order */
        ecs_set(world, e, Position, { 7, 0 });
    
        /* Iterate query again, printed values are still ordered */
        printf("\n-- Second iteration\n");
        print_query(q);
    
        /* Cleanup */
        return ecs_fini(world);
    }

     

    참고 : https://github.com/SanderMertens/flecs

     

    SanderMertens/flecs

    High performance Entity Component System for C89/99 and C++11 - SanderMertens/flecs

    github.com

     

    728x90

    댓글