entity.c 5.7 KB

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