From 8679fa5aa2309d01e2cc3b68c1fd60b9b9b92cbe Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 6 Dec 2025 01:53:32 +0200 Subject: [PATCH] add entity list --- src/entity_id.c | 36 ++++++++++++ src/entity_id.h | 27 +++++++++ src/entity_list.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++ src/entity_list.h | 37 ++++++++++++ src/game.c | 21 ++++++- src/game.h | 22 +++++++ src/game_debug.c | 2 +- src/game_debug.h | 8 +++ src/main.c | 5 +- src/main.h | 41 ------------- src/resources.h | 6 ++ 11 files changed, 303 insertions(+), 44 deletions(-) create mode 100644 src/entity_id.c create mode 100644 src/entity_id.h create mode 100644 src/entity_list.c create mode 100644 src/entity_list.h create mode 100644 src/game.h create mode 100644 src/game_debug.h create mode 100644 src/resources.h diff --git a/src/entity_id.c b/src/entity_id.c new file mode 100644 index 0000000..7d2a3c0 --- /dev/null +++ b/src/entity_id.c @@ -0,0 +1,36 @@ +#include "entity_id.h" + +bool entity_id_eql(EntityId lhs, EntityId rhs) +{ + return lhs.packed == rhs.packed; +} + +bool entity_id_is_nil(EntityId id) +{ + return entity_id_eql(id, ENTITY_ID_NIL); +} + +uint32_t entity_id_get_index(EntityId id) +{ + return (id.packed & 0x00FFFFFF); +} + +uint8_t entity_id_get_generation(EntityId id) +{ + return (id.packed >> 24); +} + +struct UnpackedEntityId entity_id_unpack(EntityId id) +{ + return (struct UnpackedEntityId){ + .generation = entity_id_get_generation(id), + .index = entity_id_get_index(id) + }; +} + +EntityId entity_id_pack(struct UnpackedEntityId unpacked_id) +{ + return (EntityId){ + .packed = (unpacked_id.generation << 24) | (unpacked_id.index & 0x00FFFFFF) + }; +} diff --git a/src/entity_id.h b/src/entity_id.h new file mode 100644 index 0000000..c28f5dd --- /dev/null +++ b/src/entity_id.h @@ -0,0 +1,27 @@ +#pragma once + +#include "main.h" + +#define ENTITY_ID_INDEX_BITS 24 +#define ENTITY_ID_GENERATION_BITS 8 + +#define MAX_INDEX ((1 << ENTITY_ID_INDEX_BITS) - 1) +#define MAX_GENERATION ((1 << ENTITY_ID_GENERATION_BITS) - 1) + +#define ENTITY_ID_NIL (EntityId){ 0 } + +typedef struct { + uint32_t packed; +} EntityId; + +struct UnpackedEntityId { + uint32_t index; + uint8_t generation; +}; + +bool entity_id_eql(EntityId lhs, EntityId rhs); +bool entity_id_is_nil(EntityId id); +EntityId entity_id_pack(struct UnpackedEntityId unpacked_id); +struct UnpackedEntityId entity_id_unpack(EntityId id); +uint32_t entity_id_get_index(EntityId id); +uint8_t entity_id_get_generation(EntityId id); diff --git a/src/entity_list.c b/src/entity_list.c new file mode 100644 index 0000000..3543649 --- /dev/null +++ b/src/entity_list.c @@ -0,0 +1,142 @@ +#include "entity_list.h" + +void entity_list_ensure_capacity(struct EntityList *list, size_t expected_capacity) +{ + if (expected_capacity > list->capacity) { + size_t larger_capacity = MAX(MAX(list->capacity*2, 8), expected_capacity); + struct EntitySlot *larger_items = realloc(list->items, larger_capacity * sizeof(*larger_items)); + if (larger_items == NULL) { + PANIC_OOM(); + } + + for (size_t i = list->capacity; i < larger_capacity; i++) { + larger_items[i].used = false; + larger_items[i].generation = 0; + } + + list->items = larger_items; + list->capacity = larger_capacity; + } +} + +void entity_list_copy(struct EntityList *destination, struct EntityList *source) +{ + entity_list_ensure_capacity(destination, source->len); + + if (source->len > 0) { + memcpy( + destination->items, + source->items, + sizeof(*source->items) * source->len + ); + } + destination->len = source->len; +} + +struct Entity *entity_list_add(struct EntityList *list) +{ + struct Entity *result = NULL; + + for (size_t i = 1; i < list->len; i++) { + struct EntitySlot *slot = &list->items[i]; + if (!slot->used) { + slot->used = true; + result = &slot->entity; + break; + } + } + + if (result == NULL) { + uint32_t index = MAX(list->len, 1); + ASSERT(index <= MAX_INDEX); + + entity_list_ensure_capacity(list, index + 1); + list->len = index + 1; + + struct EntitySlot *slot = &list->items[index]; + ASSERT(!slot->used); + slot->used = true; + + result = &slot->entity; + } + + ASSERT(result != NULL); + memset(result, 0, sizeof(*result)); + + list->used_count++; + + return result; +} + +bool entity_list_remove(struct EntityList *list, struct Entity *entity) +{ + ASSERT(entity != NULL); + + struct EntitySlot *slot = container_of(entity, struct EntitySlot, entity); + if (!slot->used) { + return false; + } + + slot->used = false; + slot->generation++; + + ASSERT(list->used_count > 0); + list->used_count--; + + return true; +} + +bool entity_list_remove_by_id(struct EntityList *list, EntityId entity_id) +{ + struct Entity *entity = entity_list_get(list, entity_id); + if (!entity) { + return false; + } + + return entity_list_remove(list, entity); +} + +bool entity_list_exists(struct EntityList *list, EntityId entity_id) +{ + struct UnpackedEntityId unpacked = entity_id_unpack(entity_id); + if (unpacked.index >= list->len) { + return false; + } + + struct EntitySlot *entity_slot = &list->items[unpacked.index]; + if (!entity_slot->used) { + return false; + } + + return entity_slot->generation == unpacked.generation; +} + +struct Entity *entity_list_get(struct EntityList *list, EntityId entity_id) +{ + if (entity_list_exists(list, entity_id)) { + struct UnpackedEntityId unpacked = entity_id_unpack(entity_id); + return &list->items[unpacked.index].entity; + } + + return NULL; +} + +EntityId entity_list_get_id(struct EntityList *list, struct Entity *entity) +{ + ASSERT(entity != NULL); + + struct EntitySlot *slot = container_of(entity, struct EntitySlot, entity); + uint32_t offset = (void*)slot - (void*)list->items; + uint32_t index = offset / sizeof(struct EntitySlot); + + return entity_id_pack((struct UnpackedEntityId){ + .generation = slot->generation, + .index = index + }); +} + +void entity_list_free(struct EntityList *list) +{ + free(list->items); + *list = (struct EntityList){ 0 }; +} diff --git a/src/entity_list.h b/src/entity_list.h new file mode 100644 index 0000000..1f547f4 --- /dev/null +++ b/src/entity_list.h @@ -0,0 +1,37 @@ +#pragma once + +#include "main.h" +#include "entity_id.h" + +struct Entity { +}; + +struct EntitySlot { + bool used; + uint8_t generation; + struct Entity entity; +}; + +struct EntityList { + struct EntitySlot *items; + size_t len; + size_t capacity; + size_t used_count; +}; + +void entity_list_ensure_capacity(struct EntityList *list, size_t expected_capacity); +void entity_list_copy(struct EntityList *destination, struct EntityList *source); +void entity_list_free(struct EntityList *list); +struct Entity *entity_list_add(struct EntityList *list); +bool entity_list_exists(struct EntityList *list, EntityId entity_id); +struct Entity *entity_list_get(struct EntityList *list, EntityId entity_id); +EntityId entity_list_get_id(struct EntityList *list, struct Entity *entity); +bool entity_list_remove(struct EntityList *list, struct Entity *entity); +bool entity_list_remove_by_id(struct EntityList *list, EntityId entity_id); + +#define entity_list_foreach(list, _entity) for ( \ + size_t i = 1; \ + i < (list)->len && (_entity = &(list)->items[i].entity, true); \ + i++ \ + ) \ + if (!(list)->items[i].used) {} else diff --git a/src/game.c b/src/game.c index d322556..5fb3e37 100644 --- a/src/game.c +++ b/src/game.c @@ -1,4 +1,4 @@ -#include "main.h" +#include "game.h" void game_init(struct Game *game) { @@ -14,5 +14,24 @@ void game_free(struct Game *game) void game_tick(struct Game *game) { TracyCZoneN(game_tick, "game_tick", true); + + Vector2 dir = { 0 }; + if (IsKeyDown(KEY_W)) { + dir.y -= 1; + } + if (IsKeyDown(KEY_S)) { + dir.y += 1; + } + if (IsKeyDown(KEY_D)) { + dir.x += 1; + } + if (IsKeyDown(KEY_A)) { + dir.x -= 1; + } + + game->player_position = Vector2Add(game->player_position, Vector2Scale(dir, 50 * game->input.dt)); + + DrawRectangleV(game->player_position, (Vector2){ 50, 50 }, RED); + TracyCZoneEnd(game_tick) } diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..bcfc568 --- /dev/null +++ b/src/game.h @@ -0,0 +1,22 @@ +#pragma once + +#include "main.h" +#include "entity_list.h" + +struct Input { + float dt; + Vector2 mouse; +}; + +struct Game { + Vector2 canvas_size; + struct EntityList entities; + + Vector2 player_position; + + struct Input input; +}; + +void game_init(struct Game *game); +void game_free(struct Game *game); +void game_tick(struct Game *game); diff --git a/src/game_debug.c b/src/game_debug.c index 5ed1858..9a5cbec 100644 --- a/src/game_debug.c +++ b/src/game_debug.c @@ -1,4 +1,4 @@ -#include "main.h" +#include "game_debug.h" #ifdef IMGUI_ENABLED #define NO_FONT_AWESOME diff --git a/src/game_debug.h b/src/game_debug.h new file mode 100644 index 0000000..2a83a4b --- /dev/null +++ b/src/game_debug.h @@ -0,0 +1,8 @@ +#pragma once + +#include "main.h" +#include "game.h" + +void game_debug_init(); +void game_debug_deinit(); +void game_debug_show(struct Game *game); diff --git a/src/main.c b/src/main.c index f430063..5286a8d 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,9 @@ #include "main.h" +#include "resources.h" +#include "game.h" +#include "game_debug.h" -extern struct Resources g_resources = { 0 }; +struct Resources g_resources = { 0 }; struct WindowTransform { Vector2 offset; diff --git a/src/main.h b/src/main.h index 503559c..1a22a23 100644 --- a/src/main.h +++ b/src/main.h @@ -32,48 +32,7 @@ #define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member))) -struct Resources { -}; - -struct Entity { -}; - -struct EntitySlot { - bool used; - uint8_t generation; - struct Entity entity; -}; - -struct EntityList { - struct EntitySlot *items; - size_t len; - size_t capacity; - size_t used_count; -}; - -struct Input { - float dt; - Vector2 mouse; -}; - -struct Game { - Vector2 canvas_size; - struct EntityList entities; - - struct Input input; -}; - extern struct Resources g_resources; -void resources_init(struct Resources *resources); - -void game_init(struct Game *game); -void game_free(struct Game *game); -void game_tick(struct Game *game); - -void game_debug_init(); -void game_debug_deinit(); -void game_debug_show(struct Game *game); - Color rgb(uint8_t r, uint8_t g, uint8_t b); Color hex(const char *str); diff --git a/src/resources.h b/src/resources.h new file mode 100644 index 0000000..b6f52da --- /dev/null +++ b/src/resources.h @@ -0,0 +1,6 @@ +#pragma once + +struct Resources { +}; + +void resources_init(struct Resources *resources);