libgdx (Ashley Framework ECS) - 系统与另一个系统对话的正确方式是什么?
libgdx (Ashley Framework ECS) - What is the proper way of talking system to another system?
System
至 System
目前我正在使用 ashley 框架开发 CharacterSystem
、GunSystem
、BulletSystem
。我的问题是我不知道这是否是与其他 system
.
交谈 system
的正确方式
我的 CharacterSystem
方法 onProcessEntity
当 character
attack
被触发时我使用了 getEngine().getSystem(GunSystem.class).trigger(true)
并且在 GunSystem
里面我有一个方法Bullet
的生成实体。当 BulletSystem
在相机外时处理物体的释放。
子问题使用ECS框架创建Bullet
class
的正确方法是什么?
我从未将 Ashley 用作 ECS,但通常 Systems
不应相互通信。
原因:当Systems
进行交流时,他们不会相互独立。独立 Systems
允许您自由添加和删除它们,而不必担心代码中断。当缺少重要的 Systems
时,游戏逻辑当然可能会中断。
有一个 Factory
(class) 可以创建项目符号实体。然后在每个System
中使用Factory
可以构建新的子弹实体。
我在游戏中经常使用 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
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);
}
}
}
希望这是有道理的,也可以随时阅读我的项目代码以获取更多示例用法。
System
至 System
目前我正在使用 ashley 框架开发 CharacterSystem
、GunSystem
、BulletSystem
。我的问题是我不知道这是否是与其他 system
.
system
的正确方式
我的 CharacterSystem
方法 onProcessEntity
当 character
attack
被触发时我使用了 getEngine().getSystem(GunSystem.class).trigger(true)
并且在 GunSystem
里面我有一个方法Bullet
的生成实体。当 BulletSystem
在相机外时处理物体的释放。
子问题使用ECS框架创建Bullet
class
的正确方法是什么?
我从未将 Ashley 用作 ECS,但通常 Systems
不应相互通信。
原因:当Systems
进行交流时,他们不会相互独立。独立 Systems
允许您自由添加和删除它们,而不必担心代码中断。当缺少重要的 Systems
时,游戏逻辑当然可能会中断。
有一个 Factory
(class) 可以创建项目符号实体。然后在每个System
中使用Factory
可以构建新的子弹实体。
我在游戏中经常使用 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
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);
}
}
}
希望这是有道理的,也可以随时阅读我的项目代码以获取更多示例用法。