level.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include "level.h"
  2. #include "level_i.h"
  3. #include "entity_i.h"
  4. #include <m-list.h>
  5. #include <furi.h>
  6. LIST_DEF(EntityList, Entity*, M_POD_OPLIST);
  7. #define M_OPL_EntityList_t() LIST_OPLIST(EntityList)
  8. #define FOREACH(name, list) for \
  9. M_EACH(name, list, EntityList_t)
  10. #define LEVEL_DEBUG(...) FURI_LOG_D("Level", __VA_ARGS__)
  11. #define LEVEL_ERROR(...) FURI_LOG_E("Level", __VA_ARGS__)
  12. struct Level {
  13. EntityList_t entities;
  14. EntityList_t to_add;
  15. EntityList_t to_remove;
  16. LevelBehaviour behaviour;
  17. void* context;
  18. };
  19. Level* level_alloc(void) {
  20. Level* level = malloc(sizeof(Level));
  21. EntityList_init(level->entities);
  22. EntityList_init(level->to_add);
  23. EntityList_init(level->to_remove);
  24. level->behaviour = LEVEL_BEHAVIOUR_EMPTY;
  25. level->context = NULL;
  26. LEVEL_DEBUG("Allocated level at %p", level);
  27. return level;
  28. }
  29. static void level_process_add(Level* level) {
  30. // move entities from to_add to entities
  31. FOREACH(item, level->to_add) {
  32. EntityList_push_back(level->entities, *item);
  33. }
  34. EntityList_clear(level->to_add);
  35. }
  36. static void level_process_remove(Level* level) {
  37. // remove entities in to_remove from entities and free them
  38. FOREACH(item, level->to_remove) {
  39. entity_free(*item);
  40. EntityList_it_t it;
  41. // find and remove the entity from the entities list
  42. for(EntityList_it(it, level->entities); !EntityList_end_p(it); EntityList_next(it)) {
  43. if(*EntityList_ref(it) == *item) {
  44. EntityList_remove(level->entities, it);
  45. break;
  46. }
  47. }
  48. }
  49. EntityList_clear(level->to_remove);
  50. }
  51. static bool level_entity_in_list_p(EntityList_t list, Entity* entity) {
  52. FOREACH(item, list) {
  53. if(*item == entity) {
  54. return true;
  55. }
  56. }
  57. return false;
  58. }
  59. void level_free(Level* level) {
  60. size_t iterations = 0;
  61. do {
  62. // process to_add and to_remove
  63. level_process_add(level);
  64. level_process_remove(level);
  65. // remove entities from entities list
  66. FOREACH(item, level->entities) {
  67. if(!level_entity_in_list_p(level->to_remove, *item)) {
  68. level_remove_entity(level, *item);
  69. }
  70. }
  71. // check if we are looping too many times
  72. iterations++;
  73. if(iterations >= 100) {
  74. LEVEL_ERROR("Level free looped too many times");
  75. }
  76. // entity_call_stop can call level_remove_entity or level_add_entity
  77. // so we need to process to_add and to_remove again
  78. } while(!EntityList_empty_p(level->to_add) || !EntityList_empty_p(level->to_remove));
  79. EntityList_clear(level->entities);
  80. EntityList_clear(level->to_add);
  81. EntityList_clear(level->to_remove);
  82. LEVEL_DEBUG("Freeing level at %p", level);
  83. free(level);
  84. }
  85. void level_behaviour_set(Level* level, LevelBehaviour behaviour, void* context) {
  86. level->behaviour = behaviour;
  87. level->context = context;
  88. }
  89. Entity* level_add_entity(Level* level, const EntityDescription* behaviour) {
  90. Entity* entity = entity_alloc(behaviour);
  91. EntityList_push_back(level->to_add, entity);
  92. entity_call_start(level, entity);
  93. return entity;
  94. }
  95. void level_remove_entity(Level* level, Entity* entity) {
  96. EntityList_push_back(level->to_remove, entity);
  97. entity_call_stop(level, entity);
  98. }
  99. static void level_process_update(Level* level, Director* director) {
  100. FOREACH(item, level->entities) {
  101. entity_call_update(*item, director);
  102. }
  103. }
  104. static void level_process_collision(Level* level, Director* director) {
  105. EntityList_it_t it_first;
  106. EntityList_it_t it_second;
  107. EntityList_it(it_first, level->entities);
  108. while(!EntityList_end_p(it_first)) {
  109. if(entity_collider_exists(*EntityList_cref(it_first))) {
  110. // start second iterator at the next entity,
  111. // so we don't check the same pair twice
  112. EntityList_it_set(it_second, it_first);
  113. EntityList_next(it_second);
  114. while(!EntityList_end_p(it_second)) {
  115. if(entity_collider_exists(*EntityList_cref(it_second))) {
  116. Entity* first = *EntityList_ref(it_first);
  117. Entity* second = *EntityList_ref(it_second);
  118. if(entity_collider_check_collision(first, second)) {
  119. entity_call_collision(first, second, director);
  120. entity_call_collision(second, first, director);
  121. }
  122. }
  123. EntityList_next(it_second);
  124. }
  125. }
  126. EntityList_next(it_first);
  127. }
  128. }
  129. void level_update(Level* level, Director* director) {
  130. level_process_add(level);
  131. level_process_remove(level);
  132. level_process_update(level, director);
  133. level_process_collision(level, director);
  134. }
  135. void level_render(Level* level, Director* director, Canvas* canvas) {
  136. FOREACH(item, level->entities) {
  137. entity_call_render(*item, director, canvas);
  138. }
  139. }