entity.c 6.7 KB

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