Skip to content

Valeryn4/StaticECS

Repository files navigation

StaticECS

This Template ECS (Entity Component System)

облегченная реализация ECS, через агегирующие шаблоны и явную композицию через кортежи. Тут все отдано на откуп программисту. Создание Entity, наполнение его компонентами и получение компонентов - все просчитывается в Компайл тайме. Данная библиотека не содержит в себе готовых компонентов или систем. Только базовый функционал!!!

EntityComp<Components...>
  • Сущность-композитор. Все данные хранятся в кортеже, внутри сущности. Доступ к ним вызывает std::get.
Component<DATA></b> 
  • Шаблонный компонент. Каждый тип компонента уникальный и не имеет базового общего класса. DATA - это любая структура с данными и методами для работы с данными. В компоненьте ни в коме случае, не должна выполняться логика!!!! Только базовый фунционал для работы с данными.
System<Component>
  • Шаблонная система связанная с компонентом. Это абстрактная система с методами Update и Draw. Как система будет работать и взаимоействовать с компонентами - остается на откуп программисту. Т.к. сущности и компоненты не знают ничего об системах, систему можно реализовать независимо от фреймворка, не наследуя ни от какого либо класса
Component<DATA>::Pool
  • Пулл компонентов. Имеет статический инстанс. В основном, это необходимо системе.
EventComponent
SystemEvent
  • Простейшая система событий, где событие - есть функция передающайся в std::function<void()>

пример:

    Render::Texture _texture;

    using Sprite = Component<SpriteData>;
    using Transform = Component<TransformData>;
    using MoveTo = Component<MoveToData>;

    using Entity = EntityComp<Sprite, Transform, MoveTo>;

    SpriteSystem _spriteSystem;
    MoveSystem _moveSystem;

    Entity _entity;

    void Init()
    {
        _entity.GetComponent<Sprite>().SetTexture(_texture);
        _entity.GetComponent<Transform>().SetPosition(math::Vector3(500,500,500));
        _entity.GetComponent<MoveTo>().SetParam(math::Vector3(900, 900, 900), 10.f);
    }

    void Draw()
    {
        //отрисовка компонентов спрайт
        _spriteSystem.Draw();
    }

    void Update(float dt)
    {
        //обновлени движения сущностей.
        _moveSystem.Update(dt); 
    }

пример с событиями:

//Данные для компонента-слушателя
struct ListenerTargetData
{
    std::string name =  "Target_0";
    int i = 0; 

    void Set(int v)
    {
        i = v;
        printf("Listener %s i set to %i\n", name.c_str(), i);
    }
};

//данные для компонента слушателя бродкастов
struct ListenerBrodcastData
{
    std::string name = "Brodcast";
    int i = 0;

    void Set(int v)
    {
        i = v;
        printf("ListenerBrodcast %s i set to %i\n", name.c_str(), i);
    }
};

//Компонент слушателя одиночки
using ListenerTargetComp = StaticECS::Component<ListenerTargetData>;
//компонент слушателя бродкастов
using ListenerBrodcastComp = StaticECS::Component< ListenerBrodcastData>;
//компонент event
using EventComponent = StaticECS::EventComponent;

//сущность генерирующая события и слушатель одиночка
using Entity = StaticECS::EntityComp< EventComponent, ListenerTargetComp>;
//сущность слушатель бродкастов и слушатель одиночка (ВНИМАНИЕ! МЫ СПЕЦИАЛЬНО ДОБАВИЛИ СЮДА СЛУШАТЕЛЯ-ОДИНОЧКУ! ДЛЯ ДЕМОНСТРАЦИИ)
using Entity2 = StaticECS::EntityComp<ListenerBrodcastComp, ListenerTargetComp>;




int main()
{
    //создаем сущность, которая будет генерировать события
    Entity entity;
    //создаем систему
    StaticECS::SystemEvent system_;

    //получаем указатели на компоненты бродкастера
    auto listener = entity.GetComponentPtr<ListenerTargetComp>();
    auto event = entity.GetComponentPtr<EventComponent>(); //компонент event, в который мы будем посылать кобытия


    //создаем 10 сущностей, которые будут ловить бродкасты, посылаемые в ListenerBrodcastComp
    for (int i = 0; i < 10; ++i)
    {
        auto e = new Entity2();
        e->GetComponent<ListenerBrodcastComp>().name = "Brodcast_" + std::to_string(i);
    }

    
    //Пусть это будет у наж GameLoop
    std::thread thread([listener, event, &system_]() 
    {


        for (int i = 0; i < 10; ++i)
        {

            auto parent = event->GetParent();

            //отправляем три события в целевой компонент самому себе. Ключ является parent!
            for (int z = 0; z < 3; ++z)
            {
                
                event->PushEvent([parent]()
                {
                    //так мы получаем компонент-слушатель, который принадлежит той же сущности, что и создает ивент
                    //если такого компонента нет - получим nullptr
                    auto comp = ListenerTargetComp::Pool::Instance().GetComponent(parent); 
                    if (comp)
                    {
                        comp->Set(comp->i + 1);
                    }
                });

                
            }

            //отправляем событие-бродкаст, которео отправиться всем компонентам ListenerBrodcastComp
            event->PushEvent([]() 
            {
                auto& pool = ListenerBrodcastComp::Pool::Instance().GetPool();

                //обратиет внимание! Что порядок перебора зависит от реализации std::unorder_map
                for (auto &&v : pool)
                {
                    v.second->Set(v.second->i + 1);
                }
                
            });

            printf("\nUpdate all events!\n");
            system_.Update(1);

            using namespace std::chrono_literals;
            std::this_thread::sleep_for(1s);
        }

    });


    thread.join();

    system("pause");
}

About

This Template ECS (Entity Component System)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages