libgdx (Ashley Framework ECS) - 系统与另一个系统对话的正确方式是什么?

libgdx (Ashley Framework ECS) - What is the proper way of talking system to another system?

SystemSystem

目前我正在使用 ashley 框架开发 CharacterSystemGunSystemBulletSystem。我的问题是我不知道这是否是与其他 system.

交谈 system 的正确方式

我的 CharacterSystem 方法 onProcessEntitycharacter attack 被触发时我使用了 getEngine().getSystem(GunSystem.class).trigger(true) 并且在 GunSystem 里面我有一个方法Bullet 的生成实体。当 BulletSystem 在相机外时处理物体的释放。

子问题使用ECS框架创建Bulletclass的正确方法是什么?

我从未将 Ashley 用作 ECS,但通常 Systems 不应相互通信。

原因:当Systems进行交流时,他们不会相互独立。独立 Systems 允许您自由添加和删除它们,而不必担心代码中断。当缺少重要的 Systems 时,游戏逻辑当然可能会中断。

有一个 Factory (class) 可以创建项目符号实体。然后在每个System中使用Factory可以构建新的子弹实体。

我在游戏中经常使用 Ashley ECS,在最近的一个项目 (https://github.com/basimkhajwal/LSD) 中,我 运行 遇到了类似的情况。我的方法可能不是标准的,它可能会在不同的项目设置中出现问题,但使用 事件队列 对我来说是一个很好的解决方案。

本质上,您有一个 enum(在我的例子中是 GameEvent),它处理需要传递的所有不同事件,例如 PLAYER_DIEDLAUNCH_PLAYER 和很快。我使用 Ashley 的 signals 接口创建了一个简单的事件队列存储,系统可以在每个滴答时轮询该事件。如下:

public class EventQueue implements Listener<GameEvent> {

    private PriorityQueue<GameEvent> eventQueue;

    public EventQueue() {
        eventQueue = new PriorityQueue<GameEvent>();
    }

    public GameEvent[] getEvents() {
        GameEvent[] events = eventQueue.toArray(new GameEvent[0]);
        eventQueue.clear();
        return events;
    }

    public GameEvent poll() {
        return eventQueue.poll();
    }

    @Override
    public void receive(Signal<GameEvent> signal, GameEvent event) { 
        eventQueue.add(event);
    }

}

接下来,在我的 GameWorld class 中,加载 Ashley Engine 并用系统填充它的那个,我有一个 Signal<GameEvent> 这是主要的backbone 用于我的事件队列。在这里,像Listener<T>一样,Signal<T>已经是Ashley的一部分了。

一些系统然后需要能够触发此信号/从中接收事件,以便它们在构造函数中使用此 Signal class。 EntitySystem 然后可以绑定一个侦听器或触发事件,然后将这些事件传递给其他侦听器。例如。我的 LaserSystem class(简体):

public class LaserSystem extends IteratingSystem implements Disposable, ContactListener {

    ...    

    private Signal<GameEvent> gameEventSignal;
    private EventQueue eventQueue;

    public LaserSystem(Signal<GameEvent> gameEventSignal) {
        super(Family.all(LaserComponent.class).get(), Constants.SYSTEM_PRIORITIES.LASER);

        this.gameEventSignal = gameEventSignal;

        eventQueue = new EventQueue();
        gameEventSignal.add(eventQueue);
    }

    ...

    @Override
    public void beginContact(Contact contact) {

        ....

        LaserComponent laserComponent = laserMapper.get(laser);
        laserComponent.updateLaser = true;

        if (other.getComponent(PlayerComponent.class) != null) {
            gameEventSignal.dispatch(GameEvent.LASER_COLLISION);
        }
    }
}

希望这是有道理的,也可以随时阅读我的​​项目代码以获取更多示例用法。