如何通过ECS转换和处理(控制)面向对象的游戏对象?

我很难将OOP游戏对象转换成Ashley ECS框架。 我有一个角色,枪和子弹类。 角色使用枪作为武器,枪类有一个处理子弹创造的火法。 在下面的代码中,是我目前WeaponSystem武器系统,它可以像Gun类一样用于任何武器的通用系统。

 public interface Weapon { void use(); } public class WeaponComponent implements Component { Weapon weapon; } public class WeaponSystem extends IteratingSystem { ... // Constructor ... // Process Entity public void use(Entity weapon) { WeaponComponent weaponComponent = Components.getWeapon(weapon); weaponComponent.use(); ... } } 

字符系统

 public class CharacterSystem extends IteratingSytem { ... // Constuctor ... // Process Entity public void attack(Entity character) { getEngine().getSystem(WeaponSystem.class).use(character); // also can be use like this // CharacterComponent characterComponent = ... // it seems that, it was redundant // characterComponent.weapon.use(); } } 

而用户控制系统…

 public class UserControlledSystem extends IteratingSystem { ... public void move(Entity character) { ... Set character directions InputComponent input ... input.key == arrow key, etc... getEngine().getSystem(CharacterSystem.class).move(character, direction); } public void attack(Entity character) { getEngine().getSystem(CharacterSystem.class).attack(character); } } 

基于这篇文章 ,他们正在使用事件调度器。 但是我真的需要使用调度程序吗? 有可能不使用调度程序,只是纯ECS? 无论如何,让我们回到主要问题( 如何通过ECS转换和处理(控制)面向对象的游戏对象? )。 目前,Ashley ECS 实体可以访问引擎和系统。 就像上面的代码示例一样,你认为这是处理系统的正确方法吗?

我不太熟悉阿什利的ECS系统。 他们使用调度程序的原因是跨多个对象共享信息。 这通常是为了减less课程中的耦合,这使得在实践中更容易管理,但不容易devise。 通常这种方法主要用于基于事件的系统。

说一个脚本游戏事件,服务器,或堆栈python。

对于过于复杂和大规模的游戏,你有成千上万的不同的对象,需要由一台计算机或其他东西管理。 实际上我会使用调度系统,

您可以使用ECS系统而不需要广播消息。 但是你会发现,随着你的项目日益复杂,单纯的ECS系统变成了一个痛苦的屁股。

基本上你会做一两件事。 你会调用实体的更新,并一次更新它的组件。 或者您运行每个系统并更新组件。 但有一段时间,你会发现你的系统需要来自其他系统的数据,这是调度员发光最好的地方。

直接来自系统的调度员和呼叫系统打破了架构。 系统不应该直接调用来更新,如果有的话,只有调用方法来设置一些标志或数据要处理的时候,该系统。

如果角色系统知道武器系统,那么如果你改变武器系统以不同的方式行事,你可能会遇到麻烦。 UserControlledSystem是一样的:它是否真的需要知道如何调用系统来移动它,并按顺序调用它?

解决这个问题的一个好方法就是简单地写下你需要做什么来传递一个系统信息,一个消息,一个组件,它可能被销毁或者只是被重用,在一个对象池中,或者甚至从来没有被删除来自实体。 我们来看看UserControlled类。 如果我们只是设定速度而不是调用系统呢? 如果我按右键,那么我只是设置velocity.x = 1f例如。 然后,当MovementSystem迭代时,它试图将该速度添加到字符,并相应地调整位置。 但是我们能做得更好吗? 我们可以创建一个组件UserControlsComponent,它有几个布尔标志来表示一个方向是否被按下。 然后我们创建一个UserControlsSystem,检查这些标志和行为。 有什么优势? 那么开始吧,我们只是简单地处理input,并设置一些标志,这意味着我们不关心最终结果,我们只是表示玩家想要做的事情,例如,向右移动。 现在负责将这些标志转换为动作的系统将读取标志,相应地执行动作,并将标志设置为false,以指示它们被消耗。 接下来会发生的是,即使你使用不同的控制器,你甚至可以创建一个系统来处理这种types的控制器,而不需要复制代码。

它确实创造了更多的代码,但不一定是复杂的,因为最终,如果代码被分解成更小,更容易处理,可读的块,那么您将从中受益,并且获得更大的灵活性。