Documentation

Systems

Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ систСмы Π² Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ ECS Wudgine, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‚ ΠΈΠ³Ρ€ΠΎΠ²ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ.

ΠžΡΠ½ΠΎΠ²Ρ‹ систСм

БистСмы Π² Wudgine β€” это классы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ Π΄Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‚ ΠΈΠ³Ρ€ΠΎΠ²ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ. Они Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ с Π³Ρ€ΡƒΠΏΠΏΠ°ΠΌΠΈ сущностСй, ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΡ… ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ Π½Π°Π±ΠΎΡ€Ρ‹ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ².

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ систСмы

// Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ класс систСмы
class ISystem {
public:
    virtual ~ISystem() = default;
    virtual void initialize() {}
    virtual void update(float deltaTime) {}
    virtual void lateUpdate(float deltaTime) {}
    virtual void fixedUpdate(float fixedDeltaTime) {}
    virtual void cleanup() {}
};

// ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΉ систСмы
class MovementSystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_query;

public:
    MovementSystem(World* world) : m_world(world) {
        // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ запроса для сущностСй с Π½ΡƒΠΆΠ½Ρ‹ΠΌΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ
        m_query = m_world->createQuery()
            .with<TransformComponent>()
            .with<VelocityComponent>()
            .build();
    }

    void update(float deltaTime) override {
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° всСх сущностСй, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… запросу
        m_query.forEach([deltaTime](Entity entity, 
                                   TransformComponent& transform, 
                                   VelocityComponent& velocity) {
            // ОбновлСниС ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ Π½Π° основС скорости
            transform.position += velocity.value * deltaTime;
        });
    }
};

// РСгистрация систСмы Π² ΠΌΠΈΡ€Π΅
world.addSystem<MovementSystem>();

Π–ΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» систСмы

БистСмы ΠΈΠΌΠ΅ΡŽΡ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°:

  • initialize(): ВызываСтся ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· ΠΏΡ€ΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ систСмы
  • update(deltaTime): ВызываСтся ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΠ°Π΄Ρ€ для обновлСния Π»ΠΎΠ³ΠΈΠΊΠΈ
  • lateUpdate(deltaTime): ВызываСтся послС update всСх систСм
  • fixedUpdate(fixedDeltaTime): ВызываСтся с фиксированным Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ шагом для Ρ„ΠΈΠ·ΠΈΠΊΠΈ
  • cleanup(): ВызываСтся ΠΏΡ€ΠΈ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½ΠΈΠΈ систСмы

Π’ΠΈΠΏΡ‹ систСм

БистСмы обновлСния (Update Systems)

Π’Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΠ°Π΄Ρ€ ΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ ΠΈΠ³Ρ€ΠΎΠ²ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ:

class AISystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_query;

public:
    AISystem(World* world) : m_world(world) {
        m_query = m_world->createQuery()
            .with<AIComponent>()
            .with<TransformComponent>()
            .build();
    }

    void update(float deltaTime) override {
        m_query.forEach([this, deltaTime](Entity entity, 
                                         AIComponent& ai, 
                                         TransformComponent& transform) {
            // Поиск блиТайшСй Ρ†Π΅Π»ΠΈ
            Entity target = findNearestTarget(entity, transform.position);
            if (target.isValid()) {
                ai.target = target;
                // ОбновлСниС повСдСния ИИ
                updateBehavior(entity, ai, transform, target, deltaTime);
            }
        });
    }

private:
    Entity findNearestTarget(Entity self, const Vector3& position) {
        // РСализация поиска блиТайшСй Ρ†Π΅Π»ΠΈ
        // ...
        return Entity();
    }

    void updateBehavior(Entity entity, AIComponent& ai, 
                       TransformComponent& transform, 
                       Entity target, float deltaTime) {
        // РСализация повСдСния ИИ
        // ...
    }
};

БистСмы Ρ„ΠΈΠ·ΠΈΠΊΠΈ (Physics Systems)

Π’Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ с фиксированным Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ шагом для ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎΠΉ симуляции Ρ„ΠΈΠ·ΠΈΠΊΠΈ:

class PhysicsSystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_query;
    PhysicsWorld m_physicsWorld;

public:
    PhysicsSystem(World* world) : m_world(world) {
        m_query = m_world->createQuery()
            .with<RigidbodyComponent>()
            .with<TransformComponent>()
            .build();
            
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ физичСского ΠΌΠΈΡ€Π°
        m_physicsWorld.initialize();
    }

    void fixedUpdate(float fixedDeltaTime) override {
        // Бинхронизация трансформаций с физичСским ΠΌΠΈΡ€ΠΎΠΌ
        syncTransformsToPhysics();
        
        // Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ шага физичСской симуляции
        m_physicsWorld.step(fixedDeltaTime);
        
        // Бинхронизация Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Ρ„ΠΈΠ·ΠΈΠΊΠΈ с ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ трансформации
        syncPhysicsToTransforms();
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° столкновСний
        processCollisions();
    }

private:
    void syncTransformsToPhysics() {
        // Бинхронизация ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΉ ΠΈ ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ΠΎΠ² ΠΈΠ· TransformComponent Π² физичСский ΠΌΠΈΡ€
        // ...
    }
    
    void syncPhysicsToTransforms() {
        // Бинхронизация Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² физичСской симуляции ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹
        // ...
    }
    
    void processCollisions() {
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ΅Π΄ΡˆΠΈΡ… столкновСний
        // ...
    }
};

БистСмы Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° (Rendering Systems)

ΠžΡ‚Π²Π΅Ρ‡Π°ΡŽΡ‚ Π·Π° сбор ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΡƒ Π΄Π°Π½Π½Ρ‹Ρ… для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°:

class RenderSystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_meshQuery;
    EntityQuery m_cameraQuery;
    RenderPipeline m_renderPipeline;

public:
    RenderSystem(World* world) : m_world(world) {
        m_meshQuery = m_world->createQuery()
            .with<MeshRendererComponent>()
            .with<TransformComponent>()
            .build();
            
        m_cameraQuery = m_world->createQuery()
            .with<CameraComponent>()
            .with<TransformComponent>()
            .build();
            
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€Π° Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°
        m_renderPipeline.initialize();
    }

    void lateUpdate(float deltaTime) override {
        // Поиск Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        Entity mainCamera = findMainCamera();
        if (!mainCamera.isValid()) return;
        
        // Π‘Π±ΠΎΡ€ Π΄Π°Π½Π½Ρ‹Ρ… для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°
        std::vector<RenderObject> renderObjects;
        collectRenderObjects(renderObjects);
        
        // Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°
        m_renderPipeline.render(mainCamera, renderObjects);
    }

private:
    Entity findMainCamera() {
        // Поиск основной ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        Entity result;
        int highestPriority = -1;
        
        m_cameraQuery.forEach([&](Entity entity, CameraComponent& camera, TransformComponent& transform) {
            if (camera.isActive() && camera.getPriority() > highestPriority) {
                highestPriority = camera.getPriority();
                result = entity;
            }
        });
        
        return result;
    }
    
    void collectRenderObjects(std::vector<RenderObject>& renderObjects) {
        // Π‘Π±ΠΎΡ€ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°
        m_meshQuery.forEach([&](Entity entity, MeshRendererComponent& renderer, TransformComponent& transform) {
            if (renderer.isVisible()) {
                RenderObject obj;
                obj.entity = entity;
                obj.mesh = renderer.getMesh();
                obj.material = renderer.getMaterial();
                obj.transform = transform.getWorldMatrix();
                obj.layer = renderer.getLayer();
                
                renderObjects.push_back(obj);
            }
        });
    }
};

БистСмы ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса (UI Systems)

ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ элСмСнты ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса:

class UISystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_uiQuery;
    UIManager m_uiManager;

public:
    UISystem(World* world) : m_world(world) {
        m_uiQuery = m_world->createQuery()
            .with<UIElementComponent>()
            .with<TransformComponent>()
            .build();
            
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° UI
        m_uiManager.initialize();
    }

    void update(float deltaTime) override {
        // ОбновлСниС состояния UI элСмСнтов
        m_uiQuery.forEach([&](Entity entity, UIElementComponent& ui, TransformComponent& transform) {
            // ОбновлСниС ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈ состояния UI элСмСнта
            ui.update(deltaTime);
        });
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° для UI
        processUIInput();
    }
    
    void lateUpdate(float deltaTime) override {
        // Π Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ UI послС всСй ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠΉ сцСны
        m_uiManager.render();
    }

private:
    void processUIInput() {
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° для UI элСмСнтов
        // ...
    }
};

БистСмы Π²Π²ΠΎΠ΄Π° (Input Systems)

ΠžΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π²ΠΎΠ΄:

class InputSystem : public ISystem {
private:
    World* m_world;
    InputManager m_inputManager;
    EventBus* m_eventBus;

public:
    InputSystem(World* world, EventBus* eventBus) 
        : m_world(world), m_eventBus(eventBus) {
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° Π²Π²ΠΎΠ΄Π°
        m_inputManager.initialize();
        
        // РСгистрация ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² Π²Π²ΠΎΠ΄Π°
        registerInputHandlers();
    }

    void update(float deltaTime) override {
        // ΠžΠΏΡ€ΠΎΡ устройств Π²Π²ΠΎΠ΄Π°
        m_inputManager.pollDevices();
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π°ΠΆΠ°Ρ‚ΠΈΠΉ клавиш
        processKeyboardInput();
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° ΠΌΡ‹ΡˆΠΈ
        processMouseInput();
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° Π³Π΅ΠΉΠΌΠΏΠ°Π΄Π°
        processGamepadInput();
    }

private:
    void registerInputHandlers() {
        // РСгистрация ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² Π²Π²ΠΎΠ΄Π°
        m_inputManager.registerKeyCallback(KeyCode::W, [this](bool pressed) {
            if (pressed) {
                m_eventBus->publish<MoveEvent>(Vector3(0, 0, 1));
            }
        });
        
        // Π”Ρ€ΡƒΠ³ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ...
    }
    
    void processKeyboardInput() {
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° с ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€Ρ‹
        // ...
    }
    
    void processMouseInput() {
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° ΠΌΡ‹ΡˆΠΈ
        // ...
    }
    
    void processGamepadInput() {
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π²ΠΎΠ΄Π° Π³Π΅ΠΉΠΌΠΏΠ°Π΄Π°
        // ...
    }
};

ΠŸΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Ρ‹ ΠΈ зависимости систСм

Установка ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ΠΎΠ²

// РСгистрация систСм с ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π°ΠΌΠΈ
world.addSystem<InputSystem>(100);       // Высокий ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚, выполняСтся ΠΏΠ΅Ρ€Π²ΠΎΠΉ
world.addSystem<AISystem>(50);           // Π‘Ρ€Π΅Π΄Π½ΠΈΠΉ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚
world.addSystem<MovementSystem>(30);     // Низкий ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚
world.addSystem<PhysicsSystem>(20);      // ΠžΡ‡Π΅Π½ΡŒ Π½ΠΈΠ·ΠΊΠΈΠΉ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚
world.addSystem<RenderSystem>(-100);     // ΠžΡ‚Ρ€ΠΈΡ†Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚, выполняСтся послСднСй

Зависимости ΠΌΠ΅ΠΆΠ΄Ρƒ систСмами

// ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ систСмы с зависимостями
class CombatSystem : public ISystem {
private:
    World* m_world;
    HealthSystem* m_healthSystem;
    AnimationSystem* m_animationSystem;

public:
    CombatSystem(World* world) : m_world(world) {
        // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ зависимых систСм
        m_healthSystem = m_world->getSystem<HealthSystem>();
        m_animationSystem = m_world->getSystem<AnimationSystem>();
        
        if (!m_healthSystem || !m_animationSystem) {
            Debug::logError("CombatSystem requires HealthSystem and AnimationSystem");
        }
    }

    void update(float deltaTime) override {
        // ИспользованиС Π΄Ρ€ΡƒΠ³ΠΈΡ… систСм
        // ...
    }
};

// РСгистрация систСм Π² ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌ порядкС
world.addSystem<HealthSystem>();
world.addSystem<AnimationSystem>();
world.addSystem<CombatSystem>();

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ систСм

ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅

class ParticleSystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_query;
    ThreadPool m_threadPool;

public:
    ParticleSystem(World* world) : m_world(world) {
        m_query = m_world->createQuery()
            .with<ParticleComponent>()
            .with<TransformComponent>()
            .build();
            
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΡƒΠ»Π° ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
        m_threadPool.initialize(std::thread::hardware_concurrency());
    }

    void update(float deltaTime) override {
        // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ всСх сущностСй с частицами
        auto entities = m_query.getEntities();
        size_t entityCount = entities.size();
        
        // ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½Π°Ρ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° частиц
        m_threadPool.parallelFor(0, entityCount, [&](size_t i) {
            Entity entity = entities[i];
            auto& particles = entity.getComponent<ParticleComponent>();
            auto& transform = entity.getComponent<TransformComponent>();
            
            // ОбновлСниС частиц
            updateParticles(particles, transform, deltaTime);
        });
    }

private:
    void updateParticles(ParticleComponent& particles, 
                        const TransformComponent& transform, 
                        float deltaTime) {
        // ОбновлСниС состояния частиц
        // ...
    }
};

ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ…

class PathfindingSystem : public ISystem {
private:
    World* m_world;
    EntityQuery m_query;
    NavigationMesh m_navMesh;
    std::unordered_map<Entity, Path> m_pathCache;
    float m_cacheTimeout = 1.0f;

public:
    PathfindingSystem(World* world) : m_world(world) {
        m_query = m_world->createQuery()
            .with<AIComponent>()
            .with<TransformComponent>()
            .build();
            
        // Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ сСтки
        m_navMesh.load("assets/navmesh/level1.navmesh");
    }

    void update(float deltaTime) override {
        // ОбновлСниС кэша ΠΏΡƒΡ‚Π΅ΠΉ
        updatePathCache(deltaTime);
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° запросов Π½Π° поиск ΠΏΡƒΡ‚ΠΈ
        m_query.forEach([this](Entity entity, AIComponent& ai, TransformComponent& transform) {
            if (ai.needsPath && ai.target.isValid()) {
                // Поиск ΠΏΡƒΡ‚ΠΈ ΠΊ Ρ†Π΅Π»ΠΈ
                Vector3 start = transform.position;
                Vector3 end = ai.target.getComponent<TransformComponent>().position;
                
                // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° кэша
                Path path;
                if (tryGetCachedPath(entity, start, end, path)) {
                    ai.currentPath = path;
                } else {
                    // ВычислСниС Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΏΡƒΡ‚ΠΈ
                    path = m_navMesh.findPath(start, end);
                    ai.currentPath = path;
                    
                    // Π‘ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ Π² кэш
                    cachePath(entity, start, end, path);
                }
                
                ai.needsPath = false;
            }
        });
    }

private:
    void updatePathCache(float deltaTime) {
        // ОбновлСниС Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΆΠΈΠ·Π½ΠΈ ΠΊΡΡˆΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… ΠΏΡƒΡ‚Π΅ΠΉ
        // ...
    }
    
    bool tryGetCachedPath(Entity entity, const Vector3& start, 
                         const Vector3& end, Path& outPath) {
        // ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΏΡƒΡ‚ΡŒ ΠΈΠ· кэша
        // ...
        return false;
    }
    
    void cachePath(Entity entity, const Vector3& start, 
                  const Vector3& end, const Path& path) {
        // Π‘ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ ΠΏΡƒΡ‚ΠΈ Π² кэш
        // ...
    }
};

БистСмныС Π³Ρ€ΡƒΠΏΠΏΡ‹

// ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π³Ρ€ΡƒΠΏΠΏΡ‹ систСм
class PhysicsSystemGroup : public SystemGroup {
public:
    PhysicsSystemGroup(World* world) : SystemGroup(world) {
        // Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ систСм Π² Π³Ρ€ΡƒΠΏΠΏΡƒ
        addSystem<CollisionDetectionSystem>();
        addSystem<RigidbodySystem>();
        addSystem<ConstraintSystem>();
        addSystem<PhysicsDebugSystem>();
    }
};

// РСгистрация Π³Ρ€ΡƒΠΏΠΏΡ‹ систСм
world.addSystemGroup<PhysicsSystemGroup>();

Бобытия ΠΈ сообщСния

// ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ события
struct CollisionEvent {
    Entity entityA;
    Entity entityB;
    Vector3 contactPoint;
    Vector3 contactNormal;
    float impulse;
};

// БистСма, ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΡŽΡ‰Π°Ρ события
class CollisionSystem : public ISystem {
private:
    World* m_world;
    EventBus* m_eventBus;
    PhysicsWorld m_physicsWorld;

public:
    CollisionSystem(World* world, EventBus* eventBus) 
        : m_world(world), m_eventBus(eventBus) {
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ физичСского ΠΌΠΈΡ€Π°
        m_physicsWorld.initialize();
        
        // РСгистрация ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π° для столкновСний
        m_physicsWorld.setCollisionCallback([this](const PhysicsContact& contact) {
            // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ события столкновСния
            CollisionEvent event;
            event.entityA = contact.bodyA->getUserData<Entity>();
            event.entityB = contact.bodyB->getUserData<Entity>();
            event.contactPoint = contact.point;
            event.contactNormal = contact.normal;
            event.impulse = contact.impulse;
            
            // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ события
            m_eventBus->publish<CollisionEvent>(event);
        });
    }

    void fixedUpdate(float fixedDeltaTime) override {
        // Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ шага физичСской симуляции
        m_physicsWorld.step(fixedDeltaTime);
    }
};

// БистСма, ΠΏΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‰Π°ΡΡΡ Π½Π° события
class DamageSystem : public ISystem {
private:
    World* m_world;
    EventBus* m_eventBus;
    EventSubscription m_collisionSubscription;

public:
    DamageSystem(World* world, EventBus* eventBus) 
        : m_world(world), m_eventBus(eventBus) {
        // Подписка Π½Π° события столкновСний
        m_collisionSubscription = m_eventBus->subscribe<CollisionEvent>(
            [this](const CollisionEvent& event) {
                // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° столкновСния
                processCollision(event);
            }
        );
    }

    ~DamageSystem() {
        // ΠžΡ‚ΠΏΠΈΡΠΊΠ° ΠΎΡ‚ событий
        m_collisionSubscription.unsubscribe();
    }

private:
    void processCollision(const CollisionEvent& event) {
        // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π·Π΄ΠΎΡ€ΠΎΠ²ΡŒΡ ΠΈ ΡƒΡ€ΠΎΠ½Π°
        if (event.entityA.hasComponent<HealthComponent>() && 
            event.entityB.hasComponent<DamageComponent>()) {
            
            auto& health = event.entityA.getComponent<HealthComponent>();
            auto& damage = event.entityB.getComponent<DamageComponent>();
            
            // ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΡƒΡ€ΠΎΠ½Π°
            float damageAmount = damage.value * event.impulse * 0.1f;
            health.currentHealth -= damageAmount;
            
            // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° смСрти
            if (health.currentHealth <= 0) {
                // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ события смСрти
                m_eventBus->publish<DeathEvent>({event.entityA, event.entityB});
            }
        }
    }
};

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ шаги

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ ознакомились с систСмами Π² Wudgine, Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ:

Запросы ΠΈ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹

Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅, ΠΊΠ°ΠΊ эффСктивно Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Ρ‚ΡŒ сущности с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΌΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ.

Π’Π΅Π±-интСрфСйсы

Π£Π·Π½Π°ΠΉΡ‚Π΅, ΠΊΠ°ΠΊ ΠΈΠ½Ρ‚Π΅Π³Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²Π΅Π±-Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ Π² ваши ΠΈΠ³Ρ€Ρ‹.

Wudgine β€’ Β© 2025