组件实体系统-输入处理



我正在使用实体组件系统(ECS)框架来制作2D空间射击游戏。我的组件只是数据,我的系统处理所有逻辑,实体基本上是ID。

以下是我的一些组件:

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-我认为太具体了!)!我认为有一个中间层会整洁得多。。对我来说,下面的解决方案要酷得多!

  1. 用户按"w">
  2. thor inputMap将'w'转换为Control::UP
  3. Control::UP以某种方式映射到实体级事件,如Ship::THRUST_UP,仅用于用户控制的船舶
  4. Ship::THRUST_UP这样的实体级事件被转换为像激活Thrusters::up布尔值这样的操作

这个解决方案特别酷的是,理想情况下,我可以使用相同的实体级别事件来控制许多其他事情,比如小行星爆炸,或者使用推进器的敌舰。我现在不知道如何实现它,或者将它集成到ECS中。我该怎么做?

一个想法是设置一个事件调度器,这样当像上面所做的那样轮询关键事件时,它们可以被发送到订阅了特定事件的任何游戏实体。EntityX具有允许您执行此操作的内置事件对象。看看这里。

最新更新