Closed johnbanq closed 1 year ago
现在这个架构可以保证运行时强类型
如果完全动态化要怎么获得强类型支持呢?
现在这个架构可以保证运行时强类型
是的,这么搞的话类型安全会变弱,会无法知道某类实体在运行时拥有哪些组件。这是这个设计的一个弱点。
不过我认为组件化架构的重点是组件,实体只是组件的拼装而已,所以这里可以酌情牺牲。
另一种做法是在实体接口定义里定义组件的getter函数,用这种方法强制某类实体必须拥有某个组件。同时提供通用的getComponent方法方便扩展
我觉得应该评估是否真的需要这么强的动态性 如果需要在运行时动态增删组件,换成是我的话,我会选择新建一个实体定义 强类型带来的好处是很大的
我觉得应该评估是否真的需要这么强的动态性 如果需要在运行时动态增删组件,换成是我的话,我会选择新建一个实体定义 强类型带来的好处是很大的
那么可以考虑上面提到的做法,在实体接口定义里写组件的getter函数,明确定义某类实体有什么组件。同时保留通用方法,允许插件给实体挂载新组件。通用方法可以暂不提供,后续再做添加。这样既有类型安全,又有可扩展性,可扩展性还可以日后视情形加入。
例如这样:
interface Entity {
// 通用方法,允许插件添加新组件, 可以暂不提供 //
void addComponent(Component component);
<T extends Component> void removeComponent(Class<T> clazz);
<T extends Component> @Nullable T getComponent(Class<T> clazz);
}
interface Sheep extends Entity {
// 强制拥有这些组件 //
PositionComponent getPositionComponent();
HealthComponent getHealthComponent();
}
这是个涉及到偏好的问题,如果有了最终结论就留言关掉吧
参照AttackComponent.java的内容,目前Allay内部有一套基于接口继承实现的组件系统。组件接口以getter/setter的形式指定状态,实体接口通过继承组件接口的方式来决定到底要拥有什么状态。具体实例将在运行时编织而成。
这么干确实非常精巧,但我担心这会限制系统的可扩展性,第三方插件是无法让现有接口继承新接口的。
目前基于组件的设计基本都在使用组合方式:即提供getComponent/addComponent这类成员,具体可以参考目前的ECS系统设计,例如artemis-odb https://github.com/junkdog/artemis-odb 和ashley https://github.com/libgdx/ashley
这么干的话可扩展性会很好,性能其实也可以通过运行时代码生成来完成——我们可以把组件实例变成实现类的特殊成员变量,然后在get的时候如果if匹配就直接返回,以便JIT内联。甚至可以将组件实例打开,直接存储其内容,以实现和继承不相上下的性能。