减少实体组件系统中的 Duck-typing 劣势

reduce Duck-typing disadvantage in entity-component-system

如何减少实体组件系统中的 Duck-typing 现象?

例子

这是一个coliru demo.

我的 ECS 中有 2 个系统 :-

System_Projectile : 管理所有射弹和子弹方面。
System_Physic : 管理物理组件。

有 2 个组件类型:Com_Projectile , Physics.

有时,我发现在某些组件中缓存指向另一个实体的指针是很好的:-

class Com_Projectile : public Component{
    public:
    Entity* physic;
    Entity* physicSecondary; //just to show that it is possible to have >1 physic
};

如果我想改变 Com_Projectile 的位置,我会调用 manage(Com_Projectile::physic)

class System_Projectile{
    public: static void manage(Entity* projectile){
        Com_Projectile* comP = getComponent<Com_Projectile>(projectile);
        //suffer duck-typing at "comP->physic"
        System_Physic::setVelocity(comP->physic,Vec3(1,0,0));
    }
};

问题

基于上述片段的真实程序运行正常。
但是,在编码时,Com_Projectile::physic 遭受鸭子打字。

在我过去的日子里,当我使用很多(深)继承时,它要容易得多,就像这样:-

    physic->setVelocity(Vec3(1,0,0));

我真的很想念那些列出所有与物理相关的函数的可爱的内容帮助。

问题

如何减少ECS系统某部分的duck-typing?
更具体地说,什么是再次启用可爱内容辅助的设计模式?

我目前的解决方法

Com_Projectile缓存Physic* physic而不是Entity*:-

class Com_Projectile{
    public: Physics* physic; //edited from "Entity* physic"
};

缺点:-

How to reduce duck-typing in some certain part of ECS system?
More specifically, what is a design pattern to enable the cute content-assist again?

一个想法是将您的组件实现视为您与系统交互的管道。无论如何,这就是他们的意图,成为一种影响行为的数据驱动方式。

class Physics : public Component<Physics> {
public:
  Vector3 GetVelocity() const;
  void SetVelocity(const Vector3& velocity);
private:
  Vector3 velocity_;
}

现在为了设置速度,只需调用:

Physics* physics = getComponent<Physics>( projectile->physic );
if ( physics ) 
  physics->SetVelocity( Vector3( 1, 0, 0 ) );

然后物理系统的工作是获取物理组件上的速度并将其与任何其他数据属性一起应用于内部物理模拟。

换句话说,将系统的输入状态视为当前组件值和先前系统发出的任何其他可变状态的组合。

除了避免您提到的鸭式输入之外,您最终得到的代码更容易理解,也更容易流动。它还打开了一扇门,很容易被脚本系统和其他外部影响者通过操纵 getter/setters 对您的组件进行变异。