Entity system in Bulletcoin


Entity system in Bulletcoin

Hello everyone! One important thing to figure out while creating a game is how you are going to handle your different game objects. Many will just let the engine handle it, but when you are using a framework it’s not as easy. So we developed a barebones entity system that we are nicknaming Entitia. Let’s take a look at how our entity system works and how we created it

What is an entity

In our system, an entity is simply a type that can represent anything game object in our world. For example, let’s say we have two game objects implemented in our world

// Enemy code
typedef struct Enemy
{
    int health;
    bool isBoss;
    Vector2D position;
    int damage;
    Color enemyColor;
} Enemy;

Enemy newEnemyObject(Vector2D position)
{
    //...
}

void updateEnemy(Enemy* enemy)
{
   // ...
}

void drawEnemy(Enemy* enemy)
{
   // ...
}

and

// Player code
typedef struct Player
{
    int health;
    Vector2D position;
    int damage;
    Color playerColor;
} Player;

Player newPlayerObject(Vector2D position)
{
    // ...
}

void updatePlayer(Player* player)
{
    // ...
}

void drawPlayer(Player* player)
{
   // ...
}

Both have very similar outlines, with small differences. So here is where entities come into play. We can take all the common information that most or all of our game objects are going to use and put it into one shared type.

// Entity code
typedef struct Entity
{
    Color color;
    Vector2D position;
    bool isVisible;
} Entity;

But we still have some variables missing, we can add those variables with a pointer to any type. And, we also need functions to update and draw this entity

    void* extraDataStruct;
    void (*update)(Entity*);
    void (*draw)(Entity*);
Entity updateEntity(Entity* entity)
{
    entity->update();
}

Entity drawEntity(Entity* entity)
{
    entity->draw();
}

void freeEntity(Entity* entity)
{
    free(entity->extraDataStruct);
}

All that is left is a function that creates these entities and implementations for the `update` and `draw` function pointers. We can do this in the enemy and player code

```c
// Enemy code
typedef EnemyData
{
   int health;
   int damage;
   bool isBoss;
} EnemyData;

void enemyUpdate(Entity* entity)
{
    // ...
}

void enemyDraw(Entity* entity)
{
   // ...
}

Entity newEnemyEntity(Vector2D position)
{
    Entity entity;
    entity.color = COLOR_RED;
    entity.position = position;
    entity.isVisible = true;
    
    EnemyData* data = malloc(sizeof(EnemyData));
    data->health = 100;
    data->damage = 15;
    data->isBoss = false;

    entity.update = enemyUpdate;
    entity.draw = enemyDraw;
    entity.extraDataStruct = &data;
    return entity;
}

Now, this is a big oversimplification and Bulletcoin’s entity system includes much more including entity buffers and recycling, but hopefully, this made you understand more about entities and how a basic entity system could work.

Real-world example

Again, the example showed is a big oversimplification, but a similar idea was used when creating the entity system in BulletCoin.

Below is an example of the Bulletcoin entity system in-use entity example

That rectangle isn’t that special, but it is not just a normal rectangle variable. It is an entity inside the entity buffer that is controlled with one universal update_entity function.

Leave a comment

Log in with itch.io to leave a comment.