Entity loading and unloading implemented somewhat
This commit is contained in:
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user