-
Notifications
You must be signed in to change notification settings - Fork 3
ECS System
A system is a piece of logic that processes entities with specific components. Systems operate on entities that have the required components. For example:
- A MovementSystem might process all entities with both
PositionComponent
andVelocityComponent
to update their positions based on their velocities. - A RenderSystem would draw all entities that have a
SpriteComponent
.
In our game engine, developers and the community can create custom systems and components. Components are written in C++.
If you haven’t already read the ECS Component section, please take a moment to review it.
In this tutorial, we'll create a MovementSystem. This system requires two components: a PositionComponent and a VelocityComponent. The system will update the position based on the velocity.
First, create a MovementSystem.hpp
file. Include the following files:
#include "VelocityComponent.hpp"
#include "PositionComponent.hpp"
#include "Engine/Shared/Inteface/ISystem.hpp"
-
Velocity
andPosition
: two components (see ECS Component to create a component)(This files already includes IComponent.hpp) -
ISystem
: the interface class for system. To create a new system, it must inherit from this interface.
Now, let's create our system class. It must inherit from the ASystem
class.
class MovementSystem : public ASystem {
public:
MovementSystem(); // Constructor
~MovementSystem() = default; // Default destructor
};
Then, ISystem
has a single method to override, it's the method to get the function system:
class MovementSystem : public ASystem {
public:
std::function<void(ECS::Registry& reg, int idxPacketEntities)> getFunction() {
};
};
This method takes the Registry and the IdxPacketEntities as parameter. Like this, we can simply create our system function.
The function will get the components Position
and Velocity
and add the Velocity
to the Position
of all entities.
MovementSystem::MovementSystem() :
ASystem("MovementSystem") {}
void _updatePosition(ECS::Registry& entityManager, int idxPacketEntities) {
// we get all positions and velocities in the registry
ECS::SparseArray<IComponent> velocities = entityManager.get_components<IComponent>("VelocityComponent");
ECS::SparseArray<IComponent> positions = entityManager.get_components<IComponent>("PositionComponent");
// Then for each of positions and velocities...
for (std::size_t entity = 0; entity < velocities.size() && entity < positions.size(); entity ++) {
// ... we cast the IComponent into the right type ...
std::shared_ptr<VelocityComponent> velocity = std::dynamic_pointer_cast<VelocityComponent>(velocities[entity]);
std::shared_ptr<PositionComponent> position = std::dynamic_pointer_cast<PositionComponent>(positions[entity]);
// ... if they exist ...
if (!velocity || !position)
continue;
// ... and update the Position of an entity by adding the velocity to the position
position->x += velocity->dx
position->y += velocity->dy
}
};
Finally, in our method getFunction()
we want to return our system function:
std::function<void(ECS::Registry& reg)> getFunction()
{
return [this](ECS::Registry& reg) {
_updatePosition(reg);
};
}
Here we are ! We have our first system !
But that's not the end. How will the game Engine use our system ?
For that, we must create an entry point. When the system will load in the game Engine, it will call this entry point to get the System class.
For that, create a cpp
file named MovementSystem.cpp
put this on it:
#include "MovementSystem.hpp"
extern "C" {
EXPORT_SYMBOL ISystem* loadSystemInstance() {
return new MovementSystem();
}
}
This function will return our System class previously created, the EXPORT_SYMBOL
is a macro use to make windows able to open .dll
files.
Compile your System with this command in your terminal:
g++ -fPIC -shared -o theNameOfYourSystem.so yourFile.cpp yourComponent1.a yourComponent2.a ...
Don't forget to add all the needed components at the compilation to avoid errors.
Replace theNameOfYourSystem
by the name you want to give to your System file
, yourFile.cpp
by the MovementSystem.cpp
and yourComponent1.a
, etc... by the right names.
Finally, place your file .so
in the Game/Engine/ folder. The system will be automatically loaded when the game Engine will be running.