2017-01-13 7 views
2

Я использую фреймворк entity-component-system (ECS) для создания 2D-космического шутера. Мои компоненты только для данных, мои системы обрабатывают всю логику, а сущности - это в основном идентификаторы.Component-Entity-System - Обработка ввода

Вот некоторые из моих компонентов:

struct LaserCannon { 
    bool shooting; 
}; 

struct Thrusters { 
    bool up, left, right, down; 
    float acceleration; 
}; 

struct Movement { 
    sf::Vector2f velocity, acceleration; 
    float maxSpeed; 
}; 

Я использую довольно прохладно системы ввода, построенный одним из разработчиков SFML, называется thor. Он сопоставляет входы, такие как sf::Keyboard::W, моим собственным событиям более высокого уровня, таким как Control::UP. Я могу проверить, было ли событие возбуждено через inputMap->isActive(Control::UP), а затем ответить соответствующим образом.

Это приносит исходный вход 'вверх' один уровень абстракции - но мне нужно идти немного дальше. Мне нужны сущности, чтобы иметь возможность реагировать на такие вещи, как Control::UP, и активировать результирующие объекты уровня сущности, такие как активация движителей корабля игрока. Я еще этого не делал, потому что я не знаю, как подойти к нему с помощью компонентов и систем!

Я пришел с одним из возможных решений: я мог бы создать новый компонент под названием PlayerShipController, который имеет булевы, представляющие все вещи, которые я хочу контролировать. Тогда я мог бы иметь систему, которая реагирует на ввод и устанавливает эти булевы соответственно так:

struct PlayerShipController { 
    bool up, left, right, down, shoot; 
}; 

// Input handling system 
struct InputSystem : public entityx::System<InputSystem> { 
    InputSystem(std::shared_ptr<thor::ActionMap<Event>> inputMap) : inputMap(inputMap) {} 

    void update(entityx::EntityManager &es, entityx::EventManager &events, entityx::TimeDelta dt) override { 

     // Iterate across all entities with a PlayerShipController 
     es.each<cm::PlayerShipController>([dt, this](entityx::Entity entity, cm::PlayerShipController &controller) { 
      if (inputMap->isActive(Event::LEFT_BUTTON)) { 
       controller.left = true; 
      } 
      if (inputMap->isActive(Event::UP_BUTTON)) { 
       controller.up = true; 
      } 
      if (inputMap->isActive(Event::RIGHT_BUTTON)) { 
       controller.right = true; 
      } 
      if (inputMap->isActive(Event::DOWN_BUTTON)) { 
       controller.down = true; 
      } 
     }); 
    }; 
    std::shared_ptr<thor::ActionMap<Event>> inputMap; 
}; 

Но мне интересно, если есть другие, возможно, более эффективные способы для достижения этой цели. То, что мне действительно не нравится в моем решении, заключается в том, что он требует, чтобы я написал систему, которая очень специфична для игры (ей нужен PlayerShipController - waaay слишком конкретный, я думаю!)! Я думаю, что было бы намного опрятно иметь какой-то средний слой. Для меня решение ниже намного круче!

  1. прессы пользователя «ш»
  2. «ш» переводится в Control::UP по Thor InputMap
  3. Control::UP каким-то образом отображается на события на уровне образований, как Ship::THRUST_UP, ибо только корабли управляются пользователем
  4. события Entity уровня, такие как Ship::THRUST_UP переводятся в действия как активация Thrusters::up булево

Что такое especi что я в идеале мог бы использовать одни и те же события на уровне сущности для управления многими другими вещами, такими как взрыва астероидов, или вражеское судно с использованием подруливающих устройств. Я просто не понимаю, как его реализовать, или интегрировать в ECS. Как я могу это сделать?

ответ

2

Одной из идей было бы создать диспетчер событий, чтобы при проведении ключевых событий, как вы делаете это выше, они могут быть отправлены любому игровому объекту, который подписался на конкретное событие. EntityX имеет встроенные объекты событий, которые позволят вам сделать это. Посмотрите here.

 Смежные вопросы

  • Нет связанных вопросов^_^