add entity list

This commit is contained in:
Rokas Puzonas 2025-12-06 01:53:32 +02:00
parent 7310056eea
commit 8679fa5aa2
11 changed files with 303 additions and 44 deletions

36
src/entity_id.c Normal file
View File

@ -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)
};
}

27
src/entity_id.h Normal file
View File

@ -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);

142
src/entity_list.c Normal file
View File

@ -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 };
}

37
src/entity_list.h Normal file
View File

@ -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

View File

@ -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)
}

22
src/game.h Normal file
View File

@ -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);

View File

@ -1,4 +1,4 @@
#include "main.h"
#include "game_debug.h"
#ifdef IMGUI_ENABLED
#define NO_FONT_AWESOME

8
src/game_debug.h Normal file
View File

@ -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);

View File

@ -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;

View File

@ -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);

6
src/resources.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
struct Resources {
};
void resources_init(struct Resources *resources);