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
, and an Entity
can only have one Engine
.
Adding an Entity
to an Engine
is a simple call.
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.