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

时间:2016-07-05 16:20:11

标签: java libgdx box2d

SystemSystem

目前,我正在使用ashley框架开发CharacterSystemGunSystemBulletSystem。我的问题是我不知道这是否是system与其他system对话的正确方式。

我的CharacterSystem方法onProcessEntitycharacter attack被触发后我使用了getEngine().getSystem(GunSystem.class).trigger(true)而在GunSystem内我有一个方法生成Bullet的实体。虽然BulletSystem可以在镜头外处理身体的释放。

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

2 个答案:

答案 0 :(得分:2)

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

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

Factory(类)确实创建了子弹实体。然后在每个Factory中使用System,这可以构建新的子弹实体。

答案 1 :(得分:2)

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

从本质上讲,您有一个enum(在我的情况下为GameEvent),可以处理需要传递的所有不同事件,例如PLAYER_DIEDLAUNCH_PLAYER等等。我使用Ashley的signals接口创建了一个简单的排队事件存储库,系统可以在每个tick上进行轮询。如下:

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类中,加载Ashley Engine并用系统填充它的那个,我有一个Signal<GameEvent>,它是我的事件队列的主要骨干。在此处,与Listener<T>一样,Signal<T>已经是Ashley的一部分。

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

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);
        }
    }
}

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

相关问题