| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- #include "entity.h"
- #include "entity_i.h"
- #include <stdlib.h>
- #include <furi.h>
- #ifdef ENTITY_DEBUG
- #define ENTITY_D(...) FURI_LOG_D("Entity", __VA_ARGS__)
- #else
- #define ENTITY_D(...)
- #endif
- static int32_t entities_count = 0;
- int32_t entities_get_count(void) {
- return entities_count;
- }
- Entity* entity_alloc(const EntityDescription* description) {
- entities_count++;
- Entity* entity = malloc(sizeof(Entity));
- entity->position = VECTOR_ZERO;
- entity->description = description;
- entity->context = NULL;
- if(description && description->context_size > 0) {
- entity->context = malloc(description->context_size);
- }
- entity->collider = NULL;
- entity->collider_offset = VECTOR_ZERO;
- ENTITY_D("Allocated at %p", entity);
- entity->collider_dirty = false;
- return entity;
- }
- void entity_collider_add_circle(Entity* entity, float radius) {
- furi_check(entity->collider == NULL, "Collider already added");
- entity->collider = malloc(sizeof(Collider));
- entity->collider->type = ColliderTypeCircle;
- entity->collider->circle.radius = radius;
- entity->collider_dirty = true;
- }
- void entity_collider_add_rect(Entity* entity, float width, float height) {
- furi_check(entity->collider == NULL, "Collider already added");
- entity->collider = malloc(sizeof(Collider));
- entity->collider->type = ColliderTypeRect;
- entity->collider->rect.half_width = width / 2;
- entity->collider->rect.half_height = height / 2;
- entity->collider_dirty = true;
- }
- void entity_collider_remove(Entity* entity) {
- furi_check(entity->collider != NULL, "Collider not added");
- free(entity->collider);
- entity->collider = NULL;
- entity->collider_dirty = false;
- }
- void entity_collider_offset_set(Entity* entity, Vector offset) {
- entity->collider_offset = offset;
- entity->collider_dirty = true;
- }
- Vector entity_collider_offset_get(Entity* entity) {
- return entity->collider_offset;
- }
- static Vector entity_collider_position_get(Entity* entity) {
- return (Vector){
- .x = entity->position.x + entity->collider_offset.x,
- .y = entity->position.y + entity->collider_offset.y,
- };
- }
- void entity_free(Entity* entity) {
- entities_count--;
- ENTITY_D("Freeing at %p", entity);
- if(entity->context) {
- free(entity->context);
- }
- if(entity->collider) {
- free(entity->collider);
- }
- free(entity);
- }
- const EntityDescription* entity_description_get(Entity* entity) {
- return entity->description;
- }
- Vector entity_pos_get(Entity* entity) {
- return entity->position;
- }
- void entity_pos_set(Entity* entity, Vector position) {
- entity->position = position;
- entity->collider_dirty = true;
- }
- void* entity_context_get(Entity* entity) {
- return entity->context;
- }
- void entity_call_start(Entity* entity, GameManager* manager) {
- if(entity->description && entity->description->start) {
- entity->description->start(entity, manager, entity->context);
- }
- }
- void entity_call_stop(Entity* entity, GameManager* manager) {
- if(entity->description && entity->description->stop) {
- entity->description->stop(entity, manager, entity->context);
- }
- }
- void entity_call_update(Entity* entity, GameManager* manager) {
- if(entity->description && entity->description->update) {
- entity->description->update(entity, manager, entity->context);
- }
- }
- void entity_call_render(Entity* entity, GameManager* manager, Canvas* canvas) {
- if(entity->description && entity->description->render) {
- entity->description->render(entity, manager, canvas, entity->context);
- }
- }
- void entity_call_collision(Entity* entity, Entity* other, GameManager* manager) {
- if(entity->description && entity->description->collision) {
- entity->description->collision(entity, other, manager, entity->context);
- }
- }
- bool entity_collider_circle_circle(Entity* entity, Entity* other) {
- Vector pos1 = entity_collider_position_get(entity);
- Vector pos2 = entity_collider_position_get(other);
- float dx = pos1.x - pos2.x;
- float dy = pos1.y - pos2.y;
- float distance = sqrtf(dx * dx + dy * dy);
- return distance < entity->collider->circle.radius + other->collider->circle.radius;
- }
- bool entity_collider_rect_rect(Entity* entity, Entity* other) {
- Vector pos1 = entity_collider_position_get(entity);
- Vector pos2 = entity_collider_position_get(other);
- float left1 = pos1.x - entity->collider->rect.half_width;
- float right1 = pos1.x + entity->collider->rect.half_width;
- float top1 = pos1.y - entity->collider->rect.half_height;
- float bottom1 = pos1.y + entity->collider->rect.half_height;
- float left2 = pos2.x - other->collider->rect.half_width;
- float right2 = pos2.x + other->collider->rect.half_width;
- float top2 = pos2.y - other->collider->rect.half_height;
- float bottom2 = pos2.y + other->collider->rect.half_height;
- return left1 < right2 && right1 > left2 && top1 < bottom2 && bottom1 > top2;
- }
- bool entity_collider_circle_rect(Entity* circle, Entity* rect) {
- Vector pos1 = entity_collider_position_get(circle);
- Vector pos2 = entity_collider_position_get(rect);
- float left = pos2.x - rect->collider->rect.half_width;
- float right = pos2.x + rect->collider->rect.half_width;
- float top = pos2.y - rect->collider->rect.half_height;
- float bottom = pos2.y + rect->collider->rect.half_height;
- float closestX = fmaxf(left, fminf(pos1.x, right));
- float closestY = fmaxf(top, fminf(pos1.y, bottom));
- float dx = pos1.x - closestX;
- float dy = pos1.y - closestY;
- float distance = sqrtf(dx * dx + dy * dy);
- return distance < circle->collider->circle.radius;
- }
- bool entity_collider_check_collision(Entity* entity, Entity* other) {
- furi_check(entity->collider);
- furi_check(other->collider);
- if(entity->collider->type == ColliderTypeCircle) {
- Entity* circle = entity;
- if(other->collider->type == ColliderTypeCircle) {
- return entity_collider_circle_circle(circle, other);
- } else {
- return entity_collider_circle_rect(circle, other);
- }
- } else {
- Entity* rect = entity;
- if(other->collider->type == ColliderTypeCircle) {
- return entity_collider_circle_rect(other, rect);
- } else {
- return entity_collider_rect_rect(rect, other);
- }
- }
- }
- bool entity_collider_exists(Entity* entity) {
- return entity->collider != NULL;
- }
- void entity_send_event(
- Entity* sender,
- Entity* receiver,
- GameManager* manager,
- uint32_t type,
- EntityEventValue value) {
- if(receiver->description && receiver->description->event) {
- EntityEvent event = {
- .type = type,
- .sender = sender,
- .value = value,
- };
- receiver->description->event(receiver, manager, event, receiver->context);
- }
- }
|