Keep in mind that this wiki is still work in progress!!
It this chapter I will explain how to create simple working program in Bubel ECS.
Program exists of given steps:
- Library initialization
- Setup data
- Registration process
- Update loop
- Freeing memory
Library initialization
Library initialization is simple and requires one call:
EntityManager.initialize();
This call will allocate global EntityManager object which can be accessed as gEntitiyManager from now. EntityManager.initialize() has three optional arguments:
threads_count- maximum number of threads. Data for threads is allocated there. Default value is one.page_size- number of bytes per chunk. Its value have to be power of two. Currently default value is 32768 (32KB), and maximum allowed value is 65536 (64KB)block_pages_count- number of chunks in one allocation. 128 by default. Library allocates multiple chunks at once usingmallocand then suballocate chunks when needed.
Registration process
Components, system and events need to be registered before usage. Registration process will assign unique ID for each registered element. This process ideally should be done once at start of program. Systems can be re-registered in case of hot-reload. Re-registered systems are destroying and re-created.
First of all we need to create some components and systems. Let's create simple position and velocity components:
struct CLocation
{
float x, y;
}
struct CVelocity
{
float x, y;
}
As you can see, component is simply a standard structure.
Next will be system for gravity:
struct GravitySystem
{
//gravity vector. This value can be changed in runtime
vec2 gravity_vector = vec2(0, -9.8);
//nested struct has to have name "EntitiesData" as templates will be looking for that name
struct EntitiesData
{
//variable length will contain number of entities in batch. Name "length" is essential
uint length;
//assign velocity component to that system. We need only velocity of entity
CVelocity[] celocity;
}
//"onUpdate" callback is called during update process for entity batches
void onUpdate(EntitiesData data)
{
//foreach entity
foreach(i; 0..data.length)
{
//add gravity to entity
data.velocity[i].x += gravity_vector.x;
data.velocity[i].y += gravity_vector.y;
}
}
}
We have gravity applied to entities, but we need also movement system:
struct MovementSystem
{
//nested struct has to have name "EntitiesData" as templates will be looking for that name
struct EntitiesData
{
//variable length will contain number of entities in batch. Name "length" is essential
uint length;
//assign location component to that system
CLocation[] location;
//assign velocity component to that system
CVelocity[] celocity;
}
//"onUpdate" callback is called during update process for entity batches
void onUpdate(EntitiesData data)
{
//foreach entity
foreach(i; 0..data.length)
{
//move entities by velocity
data.location[i].x += data.velocity[i].x;
data.location[i].y += data.velocity[i].y;
//slow down entities a little bit
data.velocity[i].x *= 0.99;
data.velocity[i].y *= 0.99;
//jump off from floor
if(data.location[i].y < 0 && data.velocity[i].y < 0)
{
//swap velocity vector 'y' direction
data.velocity[i].y = -data.velocity[i].y;
}
}
}
}
Now we can register those elements:
//begin registration process
gEntityManager.beginRegister();
//register components
gEntityManager.registerComponent!CLocation;
gEntityManager.registerComponent!CVelocity;
//register systems. Components used by system have to be registered before it
gEntityManager.registerSystem!GravitySystem(0 /*system priority*/);
gEntityManager.registerSystem!MovementSystem(1 /*system priority*/);
//end registration process
gEntityManager.endRegister();
Setup data
Before we could run code we need add some entities. I will also show how you can change system data.
//get gravity system instance
GravitySystem* gravity_system = gEntityManager.getSystem!GravitySystem;
//change gravity vector
graivty_system.gravity_vector = vec2(0, -9.81);
//create new template. Templates are required to adding entities
EntityTemplate* tmpl = gEntityManager.allocateTemplate(
[becsID!CLocation, becsID!CVelocity].staticArray //allocate with those components
);
//Now we will set default value for template velocity component
//Get component from template
CVelocity* tmpl_veclocity = tmpl.getComponent!CVelocity;
//change value
tmpl_velocity.y = 5;
//create component with values for new entity
CLocation loc = CLocation(10,10);
//add new entity
gEntityManager.addEntity(
tmpl, //template to use for new entity
[ComponentRef(&loc, becsID!CLocation)].staticArray //change location component values. Rest of data will be taken from template
);
Update loop
while(1)
{
//start frame
gEntityManager.begin();
//call update process
gEntityManager.update();
//end frame
gEntityManager.end();
}
TODO