【发布时间】:2017-05-28 12:45:26
【问题描述】:
我正在使用实体组件系统 (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 - 我觉得太具体了!)!我认为有一种中间层会更整洁。对我来说,下面的解决方案更酷!
- 用户按下“w”
- 'w'被thor inputMap翻译成
Control::UP -
Control::UP以某种方式映射到实体级事件,例如Ship::THRUST_UP,仅适用于用户控制的船只 -
Ship::THRUST_UP等实体级事件被转换为激活Thrusters::up布尔值等操作
这个解决方案特别酷的地方在于,理想情况下,我可以使用相同的实体级事件来控制许多其他事情,例如小行星爆炸或使用推进器的敌舰。我现在只是不知道如何实现它,或者将它集成到 ECS 中。我该怎么做?
【问题讨论】:
标签: c++ components sfml