107 lines
2.9 KiB
C
107 lines
2.9 KiB
C
/**
|
|
* 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);
|
|
}
|
|
} |