2

我正在为实体系统添加物理特性,但对 ECS 的系统部分感到困惑。

例如,在一个非 ECS 项目中,我可能会有这样的事情:

function updatePhysics()
    foreach(thisRobot in robots)
        thisRobot.move()
        foreach(otherRobot in robots)
            if(response = thisRobot.isColliding(otherRobot))
                thisRobot.resolveCollision(response)

然而,在 ECS 项目中,我将有一个在 PositionComponent 和 VelocityComponent 上运行的 MovementSystem,以及在 PositionComponent 和 ShapeComponent 上运行的 CollisionSystem。结果是这样的:

MovementSystem
    function update()
        foreach(entity in entities)
            this.move(entity)

CollisionSystem
    function update()
        foreach(thisEntity in entities)
            foreach(otherEntity in entities)
                if(response = this.isColliding(thisEntity, otherEntity)
                    this.resolve(thisEntity, response)

不同之处在于,在非 ECS 版本中,运动和碰撞是交错的,而在 ECS 版本中它们是分开的。在实体系统中是否存在对这种行为进行建模的正常模式?我知道 ECS 的全部意义在于摆脱继承,但也许让 MovementSystem 和 CollisionSystem 成为更通用的 PhysicsSystem 的一部分,它在单个实体上调用其他系统更新函数,而不是每个系统都维护自己的循环?

4

3 回答 3

1

在 ECS 结构中,您的运动系统并不关心您的物理特性。物理学会有自己的系统。

Movement系统会根据其他组件更新组件Position,例如Velocity.
系统根据力Physics更新Velocity组件。
系统会根据碰撞(与其他对象相交)Collision更新Position和组件。Velocity

伪代码:

MovementSystem {
    void Process(Entity e){
        e.GetComponent(PositionComponent).position += e.GetComponent(VelocityComponent).velocity;
    }
}

PhysicsSystem {
    void Process(Entity e){
        e.GetComponent(VelocityComponent).velocity += World.gravity;
        //And other physical forces being applied to the entity.
        //I guess you could have a 'Forces' component.
    }
}

CollisionSystem {
    void Process(Entity e){
        var collisions = SomeFunctionThatChecksCollisionsWithTheEntityInTheScene(e);

        foreach(collision in collisions) {
            e.GetComponent(VelocityComponent).velocity +=
                SomeFunctionToApplyForceBasedOnCollision(collision);
            e.GetComponent(PositionComponent).position +=
                SomeFunctionToOffsetAwayFromTheCollisionIntersection(collision);
        }
    }
}
于 2019-10-28T18:39:44.483 回答
0

一种直接的方法可以是在移动组件中添加所需的目的地以及实际目的地。然后只更新运动系统中的前者。
另一方面,碰撞系统将尝试通过将其切换为所需位置来应用新位置,并一次检查一个实体是否存在碰撞。

另一种方法可能是仅更新运动系统内的速度。然后添加一个更通用的物理系统,一次更新实体的位置并检查碰撞,并在需要时调整速度和位置。

您甚至可以定义一个与您之前所做的完全相同的系统:迭代所有实体,一次更新一个实体的位置并检查冲突,然后继续处理下一个实体。
您不必将运动系统和碰撞系统分开,做对您和您的游戏有益的事情。

于 2017-05-18T20:23:04.683 回答
0

并非每个移动的实体都会受到模拟中的物理影响......

我会把它MovementSystem分成两种类型

  1. 受物理影响的实体的运动。
  2. 不受物理影响的实体的运动。

在后者的情况下,您可以继续前进并MovementComponent结合 上的速度VelocityComponent并计算实体的移动和位置。

在前者的情况下,您将需要允许物理运行其模拟、确定碰撞并处理这些。无论哪种情况,您都需要更新所有受物理影响的实体的位置。

所以从循环的角度来看,我希望看到

  1. 输入系统捕获键/鼠标输入。
  2. 播放器控制器系统分析输入并根据需要生成意图。
  3. 为不受物理影响的实体运行运动。
  4. 执行 RigidBodyMovementSystem
  5. 解决冲突
  6. 更新所有受物理影响的实体的位置。

请记住,即使根据您描述系统的方式,它们也可以分解为更小的系统组件,专门处理一个较小的任务,并且该步骤的输出是另一个系统的输入。

于 2017-02-18T06:38:30.553 回答