entity.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include "entity.h"
  2. #include "entity_i.h"
  3. #include <stdlib.h>
  4. #include <furi.h>
  5. #ifdef ENTITY_DEBUG
  6. #define ENTITY_D(...) FURI_LOG_D("Entity", __VA_ARGS__)
  7. #else
  8. #define ENTITY_D(...)
  9. #endif
  10. static int32_t entities_count = 0;
  11. int32_t entities_get_count(void) {
  12. return entities_count;
  13. }
  14. typedef enum {
  15. ColliderTypeCircle,
  16. ColliderTypeRect,
  17. } ColliderType;
  18. typedef struct {
  19. ColliderType type;
  20. union {
  21. struct {
  22. float radius;
  23. } circle;
  24. struct {
  25. float half_width;
  26. float half_height;
  27. } rect;
  28. };
  29. } Collider;
  30. struct Entity {
  31. Vector position;
  32. const EntityDescription* description;
  33. void* context;
  34. Collider* collider;
  35. Vector collider_offset;
  36. };
  37. Entity* entity_alloc(const EntityDescription* description) {
  38. entities_count++;
  39. Entity* entity = malloc(sizeof(Entity));
  40. entity->position = VECTOR_ZERO;
  41. entity->description = description;
  42. entity->context = NULL;
  43. if(description && description->context_size > 0) {
  44. entity->context = malloc(description->context_size);
  45. }
  46. entity->collider = NULL;
  47. entity->collider_offset = VECTOR_ZERO;
  48. ENTITY_D("Allocated at %p", entity);
  49. return entity;
  50. }
  51. void entity_collider_add_circle(Entity* entity, float radius) {
  52. furi_check(entity->collider == NULL, "Collider already added");
  53. entity->collider = malloc(sizeof(Collider));
  54. entity->collider->type = ColliderTypeCircle;
  55. entity->collider->circle.radius = radius;
  56. }
  57. void entity_collider_add_rect(Entity* entity, float width, float height) {
  58. furi_check(entity->collider == NULL, "Collider already added");
  59. entity->collider = malloc(sizeof(Collider));
  60. entity->collider->type = ColliderTypeRect;
  61. entity->collider->rect.half_width = width / 2;
  62. entity->collider->rect.half_height = height / 2;
  63. }
  64. void entity_collider_offset_set(Entity* entity, Vector offset) {
  65. entity->collider_offset = offset;
  66. }
  67. Vector entity_collider_offset_get(Entity* entity) {
  68. return entity->collider_offset;
  69. }
  70. static Vector entity_collider_position_get(Entity* entity) {
  71. return (Vector){
  72. .x = entity->position.x + entity->collider_offset.x,
  73. .y = entity->position.y + entity->collider_offset.y,
  74. };
  75. }
  76. void entity_free(Entity* entity) {
  77. entities_count--;
  78. ENTITY_D("Freeing at %p", entity);
  79. if(entity->context) {
  80. free(entity->context);
  81. }
  82. if(entity->collider) {
  83. free(entity->collider);
  84. }
  85. free(entity);
  86. }
  87. const EntityDescription* entity_description_get(Entity* entity) {
  88. return entity->description;
  89. }
  90. Vector entity_pos_get(Entity* entity) {
  91. return entity->position;
  92. }
  93. void entity_pos_set(Entity* entity, Vector position) {
  94. entity->position = position;
  95. }
  96. void* entity_context_get(Entity* entity) {
  97. return entity->context;
  98. }
  99. void entity_call_start(Level* level, Entity* entity) {
  100. if(entity->description && entity->description->start) {
  101. entity->description->start(entity, level, entity->context);
  102. }
  103. }
  104. void entity_call_stop(Level* level, Entity* entity) {
  105. if(entity->description && entity->description->stop) {
  106. entity->description->stop(entity, level, entity->context);
  107. }
  108. }
  109. void entity_call_update(Entity* entity, GameManager* manager) {
  110. if(entity->description && entity->description->update) {
  111. entity->description->update(entity, manager, entity->context);
  112. }
  113. }
  114. void entity_call_render(Entity* entity, GameManager* manager, Canvas* canvas) {
  115. if(entity->description && entity->description->render) {
  116. entity->description->render(entity, manager, canvas, entity->context);
  117. }
  118. }
  119. void entity_call_collision(Entity* entity, Entity* other, GameManager* manager) {
  120. if(entity->description && entity->description->collision) {
  121. entity->description->collision(entity, other, manager, entity->context);
  122. }
  123. }
  124. bool entity_collider_circle_circle(Entity* entity, Entity* other) {
  125. Vector pos1 = entity_collider_position_get(entity);
  126. Vector pos2 = entity_collider_position_get(other);
  127. float dx = pos1.x - pos2.x;
  128. float dy = pos1.y - pos2.y;
  129. float distance = sqrtf(dx * dx + dy * dy);
  130. return distance < entity->collider->circle.radius + other->collider->circle.radius;
  131. }
  132. bool entity_collider_rect_rect(Entity* entity, Entity* other) {
  133. Vector pos1 = entity_collider_position_get(entity);
  134. Vector pos2 = entity_collider_position_get(other);
  135. float left1 = pos1.x - entity->collider->rect.half_width;
  136. float right1 = pos1.x + entity->collider->rect.half_width;
  137. float top1 = pos1.y - entity->collider->rect.half_height;
  138. float bottom1 = pos1.y + entity->collider->rect.half_height;
  139. float left2 = pos2.x - other->collider->rect.half_width;
  140. float right2 = pos2.x + other->collider->rect.half_width;
  141. float top2 = pos2.y - other->collider->rect.half_height;
  142. float bottom2 = pos2.y + other->collider->rect.half_height;
  143. return left1 < right2 && right1 > left2 && top1 < bottom2 && bottom1 > top2;
  144. }
  145. bool entity_collider_circle_rect(Entity* entity, Entity* other) {
  146. Vector pos1 = entity_collider_position_get(entity);
  147. Vector pos2 = entity_collider_position_get(other);
  148. float left = pos2.x - other->collider->rect.half_width;
  149. float right = pos2.x + other->collider->rect.half_width;
  150. float top = pos2.y - other->collider->rect.half_height;
  151. float bottom = pos2.y + other->collider->rect.half_height;
  152. float closestX = fmaxf(left, fminf(pos1.x, right));
  153. float closestY = fmaxf(top, fminf(pos1.y, bottom));
  154. float dx = pos1.x - closestX;
  155. float dy = pos1.y - closestY;
  156. float distance = sqrtf(dx * dx + dy * dy);
  157. return distance < entity->collider->circle.radius;
  158. }
  159. bool entity_collider_check_collision(Entity* entity, Entity* other) {
  160. furi_check(entity->collider);
  161. furi_check(other->collider);
  162. if(entity->collider->type == ColliderTypeCircle) {
  163. if(other->collider->type == ColliderTypeCircle) {
  164. return entity_collider_circle_circle(entity, other);
  165. } else {
  166. return entity_collider_circle_rect(entity, other);
  167. }
  168. } else {
  169. if(other->collider->type == ColliderTypeCircle) {
  170. return entity_collider_circle_rect(other, entity);
  171. } else {
  172. return entity_collider_rect_rect(entity, other);
  173. }
  174. }
  175. }
  176. bool entity_collider_exists(Entity* entity) {
  177. return entity->collider != NULL;
  178. }
  179. void entity_send_event(Entity* entity, uint32_t type, EntityEventValue value) {
  180. if(entity->description && entity->description->event) {
  181. EntityEvent event = {
  182. .type = type,
  183. .sender = entity,
  184. .value = value,
  185. };
  186. entity->description->event(entity, NULL, event, entity->context);
  187. }
  188. }