Brychan Dempsey 7b09b13889 Added System docs
Improved the accuracy of system.md
Added ECSSystem.md and SystemManager.md
2021-06-05 15:40:56 +12:00

3.8 KiB

| JavaECS | docs | system | System.md

System

In this section

About

Implementation

Examples

Notes

About

A system is a functionality that is executed regularly by the game engine.

The SystemManager ensures that the system has an up-to-date list of entities that the system would act upon. This is performed by comparing the system's declared required components with the components of a potential entity. An entity containing all required components is added to the system's list.

A system does not explicitly require any entities to be registered; but it can make more sense to directly perform such operations in the game loop.

TODO There is a single layer of inheritence in this design, which is the overriden init() and update() functions. This allows each system's update() to be called in a uniform way.

Implementation

All systems should extend ECSSystem, which implements the entities list as a simple set.

This can be overriden if there are certain requirements for the order of the entities (e.g. a Render System might require the further-most elements to be drawn first, to ensure the correct z-ordering)

class ECSSystem{
    Set<Integer> entities = new HashSet<>();
}
class NewSystem extends ECSSystem{
    void init() {}
    void update(/* any required parameters*/){
        /* implementation */
    }
}

Examples

System that operates on entities with multiple components

public class PhysicsSystem extends ECSSystem{
    ECS gameEngine;
    public PhysicsSystem(ECS gameEngine){
        this.gameEngine = gameEngine;
    }

    void init() {}

    void update(double dt){
        for (Integer entity : entities) {
            // Get entity components
            Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class.getName());
            RidgidBody ridgidBody = (RidgidBody)gameEngine.getComponentData(entity, RidgidBody.class.getName());
            Gravity gravity = (Gravity)gameEngine.getComponentData(entity, Gravity.class.getName());
            // Add the result of the accelerative forces to the ridgidbody's velocity
            ridgidBody.xdot += ridgidBody.xAcc * dt;
            ridgidBody.ydot += ridgidBody.yAcc * dt;

            // Gravity is a force of acceleration as above, but is generally considered to be constant.
            if (gravity.terminalX < 0 || Math.abs(ridgidBody.xdot) < gravity.terminalX){
                ridgidBody.xdot += gravity.x * dt;
            }
            if (gravity.terminalY < 0 || Math.abs(ridgidBody.ydot) < gravity.terminalY){
                ridgidBody.ydot += gravity.y * dt;
            }
            
            // Finally, move the vec2d by the new velocity
            pos.x += ridgidBody.xdot * dt;
            pos.y += ridgidBody.ydot * dt;
        }
    }
}

System that operates on a single component

public class LogVec2DSystem extends ECSSystem{
    ECS gameEngine;
    public LogVec2DSystem(ECS gameEngine){
        this.gameEngine = gameEngine;
    }

    void init() {}

    void update(double dt){
        for (Integer entity : entities) {
            Vec2D pos = (Vec2D)gameEngine.getComponentData(entity, Vec2D.class.getName());
            System.out.println(String.format("X: %.6g, Y: %.6g", pos.x, pos.y));
        }
    }
}

System that operates on no components

Note that it does not require a reference the the gameEngine; no component data is accessed.

public class FrameRateSystem extends ECSSystem{
    void init() {}

    void update(double dt, double idleTime){
        System.out.print(String.format("dt: %.3g (%.3g idle) ", dt, idleTime));
    }
}

Notes