Skip to content
Kit implementation of Entity/Component/System paradigm
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src Removed unnecessary comments Apr 16, 2019
tests Added second entity to movement example Apr 16, 2019
.gitignore Moved test logic to it's own file, updated getComponent to return an … Dec 19, 2018
LICENSE Initial commit Oct 28, 2018
README.md Updated README quick start to actually work Apr 16, 2019

README.md

kit-ecs

Kit implementation of Entity/Component/System paradigm

Quick Start Guide

Creating an Entity is easy:

var player: Entity = Entity.new("Player");

The static new function returns a stack allocated Entity, taking in the name of the Entity. If you wish to create a heap allocated (pointer) to an Entity:

var player: Ptr[Entity] = allocator.alloc(sizeof Entity);
player = Entity.new("Player");

Next we should create an Engine, which is the entry point to the entire ECS structure.

var engine: Engine = Engine.new();

An application will typically only have one Engine, an Entity can only have one Engine.

Adding the our Entity to the Engine is easy.

engine.addEntity(player);

Next we will create a Component to add to our Entity.

struct PositionComponent {
    var x: Float;
    var y: Float;
}

implement Component for PositionComponent{
    function typeIdentifier(): CString{
        return "Position";
    }
}

struct VelocityComponent {
    var x: Float;
    var y: Float;
}

implement Component for VelocityComponent{
    function typeIdentifier(): CString{
        return "Velocity";
    }
}

The Trait Component requires the method typeIdentifier() to be defined. This should return a unique CString that denotes the type of the component.

Adding the Component to the Entity is simple, and can be done before or after adding to the Engine as Entites will let the Engine know it has changed.

var playerPosition: PositionComponent = struct PositionComponent {
    x: 12.0,
    y: 12.0
};

var playerVelocity: VelocityComponent = struct VelocityComponent {
    x: 1.2,
    y: 1.2
};

player.addComponent(playerPosition);
player.addComponent(playerVelocity);

We've now done the Entity and Component section of ECS, now we should cover the System.

struct MovementSystem{
    var entityIsMoving: Bool = false;
}

implement System for MovementSystem{

    public function update(delta: Float, engine: Ptr[Engine]): Void{
        var entitesWithPosition = engine.entitiesForComponents(2, "Position", "Velocity");

        for entity in entitesWithPosition{

            var componentPosition = entity.getComponent("Position").unwrap().base() as Ptr[PositionComponent];
            var componentVelocity = entity.getComponent("Position").unwrap().base() as Ptr[VelocityComponent];

            this.entityIsMoving = true;
            componentPosition.x += (componentVelocity.x * delta);
            componentPosition.y += (componentVelocity.y * delta);
            this.entityIsMoving = false;
        }
    }
    function typeIdentifier(): CString {
        return "Position";
    }
}

Trait System requires struct to define two methods, update(delta: Float, engine: Ptr[Engine]) and typeIdentifier(), the later returns a unique CString identifer for this system. The former method is called each iteration of the engine update method, and is passed the delta time and a pointer to the Engine itself for querying.

You would then add the system itself to the engine.

var movementSystem = struct MovementSystem{
    entityIsMoving: false
};

engine.addSystem(movementSystem.typeIdentifier(), movementSystem);

Inside your game loop, you would then call:

engine.update(GetDeltaTime());

The engine will then call update on every system it has.

You can’t perform that action at this time.