我在遊戲和最近的項目中使用Ashley ECS相當多(https://github.com/basimkhajwal/LSD)我遇到過類似的情況。我的方法可能不是標準的,它可能會在不同的項目設置中發生,但使用事件隊列對我來說是一個很好的解決方案。
從本質上說,你有一個enum
(在我的情況GameEvent
)負責處理所有不同的事件需要傳遞周圍像PLAYER_DIED
,LAUNCH_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
類,它加載阿什利Engine
,並與系統填充它的人,我有一個這是我的事件隊列中的主要骨幹。在這裏,如Listener<T>
,Signal<T>
已經是阿什利的一部分。
有些系統需要能夠觸發這個信號/從它接收事件,所以他們把這個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);
}
}
}
希望這是有道理的,也覺得免費閱讀我的項目的代碼更用法示例。
我使用libgdx,你推薦ECS框架與libgdx一起使用? – ronscript
Ashley或artemis-odb。不知道任何其他ECS。 –