/** * Copyright (c) 2025 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "entity.h" #include "rpg/world/map.h" #include "assert/assert.h" #include "util/memory.h" #include "display/tileset/tileset_entities.h" #include "time/time.h" #include "util/math.h" void entityInit(entity_t *entity, const entitytype_t type, map_t *map) { assertNotNull(entity, "Entity pointer cannot be NULL"); assertNotNull(map, "Map pointer cannot be NULL"); assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type"); assertTrue(type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); memoryZero(entity, sizeof(entity_t)); entity->type = type; entity->map = map; // Init. I did use a callback struct but it was not flexible enough. switch(type) { case ENTITY_TYPE_PLAYER: playerInit(entity); break; case ENTITY_TYPE_NPC: npcInit(entity); break; default: break; } } void entityUpdate(entity_t *entity) { assertNotNull(entity, "Entity pointer cannot be NULL"); assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type"); assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); // Handle movement logic switch(entity->type) { case ENTITY_TYPE_PLAYER: playerMovement(entity); break; case ENTITY_TYPE_NPC: npcUpdate(entity); break; default: break; } // Apply velocity if(entity->velocity[0] != 0.0f || entity->velocity[1] != 0.0f) { entity->position[0] += entity->velocity[0] * TIME.delta; entity->position[1] += entity->velocity[1] * TIME.delta; // Hit test on other entities. entity_t *start = entity->map->entities; entity_t *end = &entity->map->entities[entity->map->entityCount]; // Our hitbox physicscircle_t self; glm_vec2_copy(entity->position, self.position); self.radius = TILESET_ENTITIES.tileWidth / 2.0f; physicscircle_t other; other.radius = self.radius; // TODO: what if multiple collisions? do { if(start == entity) continue; if(start->type == ENTITY_TYPE_NULL) continue; glm_vec2_copy(start->position, other.position); physicscirclecircleresult_t result; physicsCircleCheckCircle(self, other, &result); if(result.hit) { entity->position[0] -= result.normal[0] * result.depth; entity->position[1] -= result.normal[1] * result.depth; break; } } while((start++) != end); // Friction (and dampening) entity->velocity[0] *= ENTITY_FRICTION * TIME.delta; entity->velocity[1] *= ENTITY_FRICTION * TIME.delta; if(mathAbs(entity->velocity[0]) < ENTITY_MIN_VELOCITY) { entity->velocity[0] = 0.0f; } if(mathAbs(entity->velocity[1]) < ENTITY_MIN_VELOCITY) { entity->velocity[1] = 0.0f; } } if(entity->type == ENTITY_TYPE_PLAYER) { playerInteraction(entity); } }