2

I'm working on adding physics to an Entity System and am confused about the systems part of ECS.

For example, in a non-ECS project I might have something like this:

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

However in the ECS project, I would have a MovementSystem that operates on a PositionComponent and a VelocityComponent as well as a CollisionSystem that operates on a PositionComponent and a ShapeComponent. The result being something like:

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)

The difference being that in the non-ECS version the movement and collision are interleaved where as in the ECS version they are seperated. Is there a normal pattern to model this behavior in entity systems? I know the whole point of ECS is to get away from inheritance, but perhaps having both MovementSystem and CollisionSystem be part of a more general PhysicsSystem which calls the other systems update functions on a single entitiy rather than each system maintaining their own loops?

zorqy
  • 103
  • 7

3 Answers3

1

A straightforward approach could be to add to the movement component a desired destination along with the actual one. Then update only the former within the movement system.
On the other side, the collision system will try to apply the new position by switching it with the desired one and check for collisions one entity at a time.

Another approach could be to update only velocities within the movement system. Then add a more general physics system that updates position for an entity at a time and check for collisions, adjusting velocity and position if needed.

You can even define a single system that does exactly what you did previously: iterate over all the entities, update position for an entity at a time and check for collisions, then proceed with the next entity.
You don't have necessarily to separate movement system and collision system, do what sounds good for you and your game.

skypjack
  • 49,335
  • 19
  • 95
  • 187
1

In an ECS structure, your movement system doesn't care about your physics. The physics would have a system of it's own.

The Movement system updates a Position component based on some other component, say, Velocity.
The Physics system updates the Velocity component based on forces.
And the Collision system updates both the Position and Velocity components based on collisions (intersects with other objects).

Pseudocode:

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);
        }
    }
}
CosmicGiant
  • 6,275
  • 5
  • 43
  • 58
  • This would imply that the System needs to be executed in the correct order. I am facing the same problem at the moment, i have a CollisionSystem which send an Event to a Resolver if necessary. The Resolver will set the Delta = 0 for the next Calculation (if it's a normal Tile Entity). The MovementSystem applies the Delta to the Position, which will lead to no changes. But what if the CollisionSystem is executed before my Delta is set? So am i forced to use this Order? 1. InputSystem applies Speed on Delta, 2.CollisionSystem check for collision and set delta 0 3. MovementSystem applies Delta –  Dec 17 '19 at 14:32
  • @XenoRo Quick question: am I supposed to call systems from the game/main loop? Taking in your pseudocode above, when and where do you actually construct and call (`.Process()`) them, as you have to somehow integrate with something in the loop? – Berkant İpek Mar 22 '21 at 08:39
  • @BerkantIpek It is the nature of games (and any software with continuous interaction, really) to run in at least one loop. Most modern game engines operate with a semi-synchronous loop; a single loop in structure, but with many processes *not* running every iteration. Look at [Unity's loop](https://docs.unity3d.com/Manual/ExecutionOrder.html), for example. All iterations process visuals and base game logic (`Update`), but not every iteration processes physics (`FixedUpdate`). --- As for how that is done in ECS, or even taking a step back to the base game engine, depends on the ECS or GE. – CosmicGiant Apr 11 '21 at 03:11
  • @M.Soldin I'm pretty sure that the order problem is true independently of ECS. --- If you modify `speed` of a character after physics iteration; it goes to next frame --- ECS's advantages are in data structure promoting sequential memory access (faster), and parallelization (multi-threading) of the processing of systems (to some extent, multiple systems can process multiple entities and components) --- It's just a way of organizing software so each frame is faster, and you shouldn't think of it as a way to eliminate the need to properly order executions. That's still gonna be a thing. – CosmicGiant Apr 11 '21 at 03:22
0

Not every entity that moves is influenced by physics in a simulation...

I would split the MovementSystem into two types

  1. Movement for entities which are physics influenced.
  2. Movement for entities which are not physics influenced.

In the case of the latter, you can go ahead and take the direction on the MovementComponent in combination with the speed on the VelocityComponent and calculate the movement and position of the entity.

In the case of the former, you will need to allow physics to run its simulation, determine collisions and handle those. In either case, you'd need to then update the position for all entities influenced by physics.

So from a loop perspective, I'd expect to see

  1. Input system captures key/mouse input.
  2. Player controller system analyzes input and generates intent as appropriate.
  3. Run the movement for non-physics influenced entities.
  4. Execute the RigidBodyMovementSystem
  5. Resolve collisions
  6. Update position for all physics influenced entities.

Remember that even based on how you describe your systems, they can be decomposed into smaller system components that specifically handle one smaller task and the output from that step is the input to another system.

Naros
  • 19,928
  • 3
  • 41
  • 71
  • In your loop, you have 4 and 5 separated. My question was aimed at how to interleave those two systems. – zorqy Feb 20 '17 at 14:16