From 268bafc10a8722cd9f526cefb389f9ededeb68ef Mon Sep 17 00:00:00 2001 From: quou Date: Mon, 24 Apr 2023 21:53:59 +1000 Subject: Add ECS. --- ecs.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 ecs.c (limited to 'ecs.c') diff --git a/ecs.c b/ecs.c new file mode 100644 index 0000000..494a79f --- /dev/null +++ b/ecs.c @@ -0,0 +1,153 @@ +#include +#include + +/* Very simple Entity Component System, created to help a + * Discord user understand the concept. + * + * I made it to be very easy to read and understand and + * as simple as possible while still having enough features + * to be usable for simple games. + * + * Areas for improvement: + * - Using an intermediate array (or "sparse set") instead + * of a bitset to avoid gaps in the component arrays. + * - Destroying entities - this can be done by simply + * removing all of the components in the current system, + * but you may want to have a way to re use-entity IDs. + * Hint: This will probably involve sacrificing some + * of the bits in the entity ID to store a "version" + * to check how many times the ID has been recycled. + * - Anything else you think you need :) + */ + +#define max_entities 256 +#define max_component_types 8 + +/* Entities are just IDs. */ +typedef int Entity; + +typedef enum { + ctype_null = 1 << 0, + ctype_transform = 1 << 1, + ctype_enemy = 1 << 2, + ctype_sprite = 1 << 3 +} CType; + +typedef struct { + int x, y; + int scale_x, scale_y; +} Transform; + +typedef struct { + int health; + int damage; +} Enemy; + +typedef struct { + int id; + /* Whatever else a sprite needs, you get the idea. */ +} Sprite; + +typedef struct { + /* Here are the component pools. */ + Transform transforms[max_entities]; + Enemy enemies[max_entities]; + Sprite sprites[max_entities]; + + /* If you have more than 8 different types of component, change this + * to an unsigned short or an int to fit the extra bits in the CType + * enum. */ + unsigned char bitset[max_entities]; + + int entity_count; +} World; + +void enemy_system(World* world) { + int i; + unsigned char bits; + Transform* transform; + Enemy* enemy; + + for (i = 0; i < world->entity_count; i++) { + bits = world->bitset[i]; + /* Iterate all entities with both a transform and an enemy component. */ + if ((bits & ctype_enemy) && (bits & ctype_transform)) { + transform = &world->transforms[i]; + enemy = &world->enemies[i]; + + /* Do enemy stuff here, pathfinding, shooting etc. */ + printf("Updating enemy for %d!\n", i); + } + } +}; + +void transform_system(World* world) { + int i; + unsigned char bits; + Transform* transform; + + for (i = 0; i < world->entity_count; i++) { + bits = world->bitset[i]; + /* Iterate all entities with a transform component */ + if (bits & ctype_transform) { + transform = &world->transforms[i]; + transform->x += 10; + + /* Do transform stuff here, for example updating matrices */ + printf("Updating transform for %d!\n", i); + } + } +} + +void sprite_system(World* world) { + /* etc. */ +} + +void init_world(World* world) { + world->entity_count = 0; +} + +Entity create_entity(World* world) { + /* Might want to verify that we don't overflow max_entities. */ + Entity e; + + e = world->entity_count++; + + /* Make sure each entity starts with no components. */ + world->bitset[e] = ctype_null; + + return e; +} + +void entity_add_components(World* world, Entity entity, unsigned int bits) { + /* Might want to verify that this entity is valid, etc. */ + world->bitset[entity] |= bits; +} + +void entity_remove_components(World* world, Entity entity, unsigned int bits) { + world->bitset[entity] &= ~bits; +} + +int main() { + World* world; + Entity a, b; + + world = (World*)malloc(sizeof *world); + + init_world(world); + + a = create_entity(world); + entity_add_components(world, a, ctype_transform | ctype_enemy); + + b = create_entity(world); + entity_add_components(world, b, ctype_transform); + + while (1) { + /* The game loop. */ + enemy_system(world); + transform_system(world); + sprite_system(world); + } + + free(world); +} -- cgit v1.2.3-54-g00ecf