Entity loading and unloading implemented somewhat

This commit is contained in:
2025-06-13 17:29:26 -05:00
parent 9288c01887
commit 8289cac039
5 changed files with 76 additions and 5 deletions

View File

@ -7,6 +7,7 @@
#include "entity.h" #include "entity.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h"
entity_t ENTITIES[ENTITY_COUNT_MAX] = {0}; entity_t ENTITIES[ENTITY_COUNT_MAX] = {0};
@ -24,6 +25,8 @@ void entityInit(entity_t *entity, const entitytype_t type) {
ENTITY_CALLBACKS[type].init, ENTITY_CALLBACKS[type].init,
"Entity type has no init callback" "Entity type has no init callback"
); );
memoryZero(entity, sizeof(entity_t));
entity->type = type; entity->type = type;
ENTITY_CALLBACKS[type].init(entity); ENTITY_CALLBACKS[type].init(entity);

View File

@ -172,14 +172,20 @@ void chunkMapSetPosition(const uint16_t x, const uint16_t y) {
void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) {
assertNotNull(chunk, "Chunk pointer is null"); assertNotNull(chunk, "Chunk pointer is null");
// Zero out the chunk data.
memoryZero(chunk, sizeof(chunk_t));
// Set the chunk coordinates.
chunk->x = x; chunk->x = x;
chunk->y = y; chunk->y = y;
// Only load data if the chunk is within bounds.
if(x >= WORLD_WIDTH || y >= WORLD_HEIGHT) { if(x >= WORLD_WIDTH || y >= WORLD_HEIGHT) {
memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); memorySet(chunk->tiles, 0, sizeof(chunk->tiles));
return; return;
} }
// Is chunk data defined?
const chunkdata_t *chunkData = WORLD_CHUNKS[y * WORLD_WIDTH + x]; const chunkdata_t *chunkData = WORLD_CHUNKS[y * WORLD_WIDTH + x];
if(chunkData == NULL) { if(chunkData == NULL) {
memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); memorySet(chunk->tiles, 0, sizeof(chunk->tiles));
@ -201,15 +207,19 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) {
while(data < chunkData->entities + CHUNK_ENTITY_COUNT_MAX) { while(data < chunkData->entities + CHUNK_ENTITY_COUNT_MAX) {
if(data->type == ENTITY_TYPE_NULL) break; if(data->type == ENTITY_TYPE_NULL) break;
// Store that this chunk owns this entity ID.
chunk->entityIDs[chunk->entityCount++] = data->id;
// Check entity isn't loaded (still). // Check entity isn't loaded (still).
entity = ENTITIES; entity = ENTITIES;
do { do {
if(entity->id == data->id) break; if(entity->type != ENTITY_TYPE_NULL && entity->id == data->id) break;
entity++; entity++;
} while(entity < ENTITIES + ENTITY_COUNT_MAX); } while(entity < ENTITIES + ENTITY_COUNT_MAX);
if(entity != ENTITIES + ENTITY_COUNT_MAX) { if(entity != ENTITIES + ENTITY_COUNT_MAX) {
// Entity is already loaded, skip it. // Entity is already loaded, skip it.
printf("Entity ID %u already loaded, skipping...\n", data->id);
data++; data++;
continue; continue;
} }
@ -240,5 +250,54 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) {
} }
void chunkUnload(chunk_t *chunk) { void chunkUnload(chunk_t *chunk) {
uint8_t i;
entity_t *entity;
uint32_t id;
assertNotNull(chunk, "Chunk pointer is null"); assertNotNull(chunk, "Chunk pointer is null");
// Iterate over each entity this chunk owns.
i = 0;
while(i < chunk->entityCount) {
id = chunk->entityIDs[i++];
// Now, do we need to unload this entity?
bool_t shouldUnload = false;
// Now, find the entity loaded with this ID. It should be impossible for
// this entity to be unloaded (but may change in future).
entity = ENTITIES;
do {
if(entity->type != ENTITY_TYPE_NULL && entity->id == id) break;
entity++;
} while(entity < ENTITIES + ENTITY_COUNT_MAX);
// If the entity is still within our chunk bounds, it's getting unloaded
if(
entity->x >= chunk->x * CHUNK_WIDTH * TILE_WIDTH &&
entity->x < (chunk->x + 1) * CHUNK_WIDTH * TILE_WIDTH &&
entity->y >= chunk->y * CHUNK_HEIGHT * TILE_HEIGHT &&
entity->y < (chunk->y + 1) * CHUNK_HEIGHT * TILE_HEIGHT
) {
shouldUnload = true;
} else {
assertUnreachable(
"Entity has left its chunk bounds, we should not be unloading it but "
"I have yet to implement that properly. It will need to self-manage "
"its own unloading somehow, and also not be in a null chunk "
"when it does so."
);
}
// This entity is still in use, leave it loaded.
if(!shouldUnload) continue;
assertTrue(
entity < ENTITIES + ENTITY_COUNT_MAX,
"Entity ID not found for unloading"
);
// NULL the entity type, effectively unloading it.
printf("Unloading entity ID %u\n", entity->id);
entity->type = ENTITY_TYPE_NULL;
}
} }

View File

@ -20,8 +20,8 @@
typedef struct { typedef struct {
uint16_t x, y; uint16_t x, y;
tile_t tiles[CHUNK_TILE_COUNT]; tile_t tiles[CHUNK_TILE_COUNT];
// int32_t entityIDs[CHUNK_ENTITY_COUNT_MAX]; uint32_t entityIDs[CHUNK_ENTITY_COUNT_MAX];
// uint8_t entityCount; uint8_t entityCount;
} chunk_t; } chunk_t;
typedef struct { typedef struct {

View File

@ -41,6 +41,15 @@ void overworldUpdate() {
entityUpdate(entity++); entityUpdate(entity++);
} while(entity->type != ENTITY_TYPE_NULL); } while(entity->type != ENTITY_TYPE_NULL);
// Testing, follow player
entity = &ENTITIES[0]; // Player entity
assertTrue(
entity->type == ENTITY_TYPE_PLAYER,
"First entity must be player"
);
OVERWORLD_CAMERA_X = (uint32_t)floorf(entity->x);
OVERWORLD_CAMERA_Y = (uint32_t)floorf(entity->y);
uint16_t x, y; uint16_t x, y;
if(OVERWORLD_CAMERA_X < RENDER_WIDTH / 2) { if(OVERWORLD_CAMERA_X < RENDER_WIDTH / 2) {
x = 0; x = 0;

View File

@ -26,13 +26,13 @@ void drawOverworldDraw(void) {
if(OVERWORLD_CAMERA_X < RENDER_WIDTH / 2) { if(OVERWORLD_CAMERA_X < RENDER_WIDTH / 2) {
DRAW_OVERWORLD_CAMERA.target.x = 0; DRAW_OVERWORLD_CAMERA.target.x = 0;
} else { } else {
DRAW_OVERWORLD_CAMERA.target.x = (OVERWORLD_CAMERA_X - RENDER_WIDTH) / 2; DRAW_OVERWORLD_CAMERA.target.x = OVERWORLD_CAMERA_X - (RENDER_WIDTH / 2);
} }
if(OVERWORLD_CAMERA_Y < RENDER_HEIGHT / 2) { if(OVERWORLD_CAMERA_Y < RENDER_HEIGHT / 2) {
DRAW_OVERWORLD_CAMERA.target.y = 0; DRAW_OVERWORLD_CAMERA.target.y = 0;
} else { } else {
DRAW_OVERWORLD_CAMERA.target.y = (OVERWORLD_CAMERA_Y - RENDER_HEIGHT) / 2; DRAW_OVERWORLD_CAMERA.target.y = OVERWORLD_CAMERA_Y - (RENDER_HEIGHT / 2);
} }
BeginMode2D(DRAW_OVERWORLD_CAMERA); BeginMode2D(DRAW_OVERWORLD_CAMERA);