add entity list
This commit is contained in:
parent
7310056eea
commit
8679fa5aa2
36
src/entity_id.c
Normal file
36
src/entity_id.c
Normal 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
27
src/entity_id.h
Normal 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
142
src/entity_list.c
Normal 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
37
src/entity_list.h
Normal 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
|
||||||
21
src/game.c
21
src/game.c
@ -1,4 +1,4 @@
|
|||||||
#include "main.h"
|
#include "game.h"
|
||||||
|
|
||||||
void game_init(struct Game *game)
|
void game_init(struct Game *game)
|
||||||
{
|
{
|
||||||
@ -14,5 +14,24 @@ void game_free(struct Game *game)
|
|||||||
void game_tick(struct Game *game)
|
void game_tick(struct Game *game)
|
||||||
{
|
{
|
||||||
TracyCZoneN(game_tick, "game_tick", true);
|
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)
|
TracyCZoneEnd(game_tick)
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/game.h
Normal file
22
src/game.h
Normal 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);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include "main.h"
|
#include "game_debug.h"
|
||||||
|
|
||||||
#ifdef IMGUI_ENABLED
|
#ifdef IMGUI_ENABLED
|
||||||
#define NO_FONT_AWESOME
|
#define NO_FONT_AWESOME
|
||||||
|
|||||||
8
src/game_debug.h
Normal file
8
src/game_debug.h
Normal 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);
|
||||||
@ -1,6 +1,9 @@
|
|||||||
#include "main.h"
|
#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 {
|
struct WindowTransform {
|
||||||
Vector2 offset;
|
Vector2 offset;
|
||||||
|
|||||||
41
src/main.h
41
src/main.h
@ -32,48 +32,7 @@
|
|||||||
|
|
||||||
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
|
#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;
|
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 rgb(uint8_t r, uint8_t g, uint8_t b);
|
||||||
Color hex(const char *str);
|
Color hex(const char *str);
|
||||||
|
|||||||
6
src/resources.h
Normal file
6
src/resources.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Resources {
|
||||||
|
};
|
||||||
|
|
||||||
|
void resources_init(struct Resources *resources);
|
||||||
Loading…
Reference in New Issue
Block a user