Skip to main content
I've added `total_position_components` and `total_health_components` to indicate in a better way that every system iterates over Components and not Entities.
Source Link
Exaila
  • 687
  • 5
  • 7
struct ComponentLists
{
    Health health_components[100];
    Position position_components[100];
    int total_health_components;
    int total_position_components;
};
// a simplistic way of creating a new entity
void create_entity(ComponentLists* components)
{
    int id = ENTITIES++;// global number of entities 
    components.health_components[id].entity_id = id;
    components.total_health_components++;
    components.position_components[id].entity_id = id;
    components.total_position_components++;
    //initialise any other variable here
}

void update_health_system(Health* h, ComponentLists* components)
{
    if(h->current_health <= 0) 
    {
        kill_entity(components, h->entity_id);// this will remove all components that refer to that entity_id
    }
}

void update_position_system(Position* p, ComponentLists* components)
{
    if(p->y <= 0)
    { 
        // for simplicity's sake we assume that the id is the index.
        // In a real world example this won't be enough.
        // You may want to use a different data structure instead like a hash map or a binary tree.
        Health* h = components.health_components[p->entity_id];
        h->current_health--;
    }
}
void main_loop()
{
    ComponentLists components;

    create_entity(components);
    create_entity(components);

    while(1)
    {
        /*Now you can update each system one by one*/
        for(int i = 0; i < ENTITIES;components.total_position_components; ++i)
        {
            update_position_system(&components.position_components[i],components);
        }
        
        for(int i = 0; i < ENTITIES;components.total_health_components; ++i)
        {
            update_health_system(&components.health_components[i],components);
        }
    }
}
struct ComponentLists
{
    Health health_components[100];
    Position position_components[100];
};
// a simplistic way of creating a new entity
void create_entity(ComponentLists* components)
{
    int id = ENTITIES++;// global number of entities 
    components.health_components[id].entity_id = id;
    components.position_components[id].entity_id = id;
    //initialise any other variable here
}

void update_health_system(Health* h, ComponentLists* components)
{
    if(h->current_health <= 0) 
    {
        kill_entity(components, h->entity_id);// this will remove all components that refer to that entity_id
    }
}

void update_position_system(Position* p, ComponentLists* components)
{
    if(p->y <= 0)
    { 
        // for simplicity's sake we assume that the id is the index.
        // In a real world example this won't be enough.
        // You may want to use a different data structure instead like a hash map or a binary tree.
        Health* h = components.health_components[p->entity_id];
        h->current_health--;
    }
}
void main_loop()
{
    ComponentLists components;

    create_entity(components);
    create_entity(components);

    while(1)
    {
        /*Now you can update each system one by one*/
        for(int i = 0; i < ENTITIES; ++i)
        {
            update_position_system(&components.position_components[i],components);
        }
        
        for(int i = 0; i < ENTITIES; ++i)
        {
            update_health_system(&components.health_components[i],components);
        }
    }
}
struct ComponentLists
{
    Health health_components[100];
    Position position_components[100];
    int total_health_components;
    int total_position_components;
};
// a simplistic way of creating a new entity
void create_entity(ComponentLists* components)
{
    int id = ENTITIES++;// global number of entities 
    components.health_components[id].entity_id = id;
    components.total_health_components++;
    components.position_components[id].entity_id = id;
    components.total_position_components++;
    //initialise any other variable here
}

void update_health_system(Health* h, ComponentLists* components)
{
    if(h->current_health <= 0) 
    {
        kill_entity(components, h->entity_id);// this will remove all components that refer to that entity_id
    }
}

void update_position_system(Position* p, ComponentLists* components)
{
    if(p->y <= 0)
    { 
        // for simplicity's sake we assume that the id is the index.
        // In a real world example this won't be enough.
        // You may want to use a different data structure instead like a hash map or a binary tree.
        Health* h = components.health_components[p->entity_id];
        h->current_health--;
    }
}
void main_loop()
{
    ComponentLists components;

    create_entity(components);
    create_entity(components);

    while(1)
    {
        /*Now you can update each system one by one*/
        for(int i = 0; i < components.total_position_components; ++i)
        {
            update_position_system(&components.position_components[i],components);
        }
        
        for(int i = 0; i < components.total_health_components; ++i)
        {
            update_health_system(&components.health_components[i],components);
        }
    }
}
Source Link
Exaila
  • 687
  • 5
  • 7

As a pattern ECS and data oriented programming in general are closer to pure C than C++.

Entity component systems consist of three major elements.

  • Components are simply holding data; they shouldn't hold any logic. A simple struct should be enough to model them in C.
  • Systems is where all your logic lives.
  • Finally, Entities don't hold anything (logic or data). They are conceptually just a way of connecting components together. These can be represented as an ID in the component.

As an example you may have a game where your entities can have two components. A position component and a health component. These can be represented as two structs. Both structs hold an entity_id.

struct Position
{
    int entity_id;
    int x;
    int y;
};

struct Health
{
    int entity_id;
    int current_health;
    int max_health;
};

For every different type of component you need a list or an array of that component. To make things simpler I put everything in a single struct, sort of the root of the ECS. Also, for simplicity I am using just a member array. You may need to consider a better approach like a binary tree where the key of each node is the id of the component's entity.

struct ComponentLists
{
    Health health_components[100];
    Position position_components[100];
};

Based on these data structres you could define your systems as simple stateless functions. In ECS systems are meant to represent transformations that change the state of a component.

// a simplistic way of creating a new entity
void create_entity(ComponentLists* components)
{
    int id = ENTITIES++;// global number of entities 
    components.health_components[id].entity_id = id;
    components.position_components[id].entity_id = id;
    //initialise any other variable here
}

void update_health_system(Health* h, ComponentLists* components)
{
    if(h->current_health <= 0) 
    {
        kill_entity(components, h->entity_id);// this will remove all components that refer to that entity_id
    }
}

void update_position_system(Position* p, ComponentLists* components)
{
    if(p->y <= 0)
    { 
        // for simplicity's sake we assume that the id is the index.
        // In a real world example this won't be enough.
        // You may want to use a different data structure instead like a hash map or a binary tree.
        Health* h = components.health_components[p->entity_id];
        h->current_health--;
    }
}

Putting everything together, this is how a main loop could look like.

void main_loop()
{
    ComponentLists components;

    create_entity(components);
    create_entity(components);

    while(1)
    {
        /*Now you can update each system one by one*/
        for(int i = 0; i < ENTITIES; ++i)
        {
            update_position_system(&components.position_components[i],components);
        }
        
        for(int i = 0; i < ENTITIES; ++i)
        {
            update_health_system(&components.health_components[i],components);
        }
    }
}