level.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. level_clear(level);
  61. EntityList_clear(level->entities);
  62. EntityList_clear(level->to_add);
  63. EntityList_clear(level->to_remove);
  64. LEVEL_DEBUG("Freeing level at %p", level);
  65. free(level);
  66. }
  67. void level_clear(Level* level) {
  68. size_t iterations = 0;
  69. do {
  70. // process to_add and to_remove
  71. level_process_add(level);
  72. level_process_remove(level);
  73. // remove entities from entities list
  74. FOREACH(item, level->entities) {
  75. if(!level_entity_in_list_p(level->to_remove, *item)) {
  76. level_remove_entity(level, *item);
  77. }
  78. }
  79. // check if we are looping too many times
  80. iterations++;
  81. if(iterations >= 100) {
  82. LEVEL_ERROR("Level free looped too many times");
  83. }
  84. // entity_call_stop can call level_remove_entity or level_add_entity
  85. // so we need to process to_add and to_remove again
  86. } while(!EntityList_empty_p(level->to_add) || !EntityList_empty_p(level->to_remove));
  87. }
  88. void level_behaviour_set(Level* level, LevelBehaviour behaviour, void* context) {
  89. level->behaviour = behaviour;
  90. level->context = context;
  91. }
  92. Entity* level_add_entity(Level* level, const EntityDescription* behaviour) {
  93. Entity* entity = entity_alloc(behaviour);
  94. EntityList_push_back(level->to_add, entity);
  95. entity_call_start(level, entity);
  96. return entity;
  97. }
  98. void level_remove_entity(Level* level, Entity* entity) {
  99. EntityList_push_back(level->to_remove, entity);
  100. entity_call_stop(level, entity);
  101. }
  102. static void level_process_update(Level* level, Director* director) {
  103. FOREACH(item, level->entities) {
  104. entity_call_update(*item, director);
  105. }
  106. }
  107. static void level_process_collision(Level* level, Director* director) {
  108. EntityList_it_t it_first;
  109. EntityList_it_t it_second;
  110. EntityList_it(it_first, level->entities);
  111. while(!EntityList_end_p(it_first)) {
  112. if(entity_collider_exists(*EntityList_cref(it_first))) {
  113. // start second iterator at the next entity,
  114. // so we don't check the same pair twice
  115. EntityList_it_set(it_second, it_first);
  116. EntityList_next(it_second);
  117. while(!EntityList_end_p(it_second)) {
  118. if(entity_collider_exists(*EntityList_cref(it_second))) {
  119. Entity* first = *EntityList_ref(it_first);
  120. Entity* second = *EntityList_ref(it_second);
  121. if(entity_collider_check_collision(first, second)) {
  122. entity_call_collision(first, second, director);
  123. entity_call_collision(second, first, director);
  124. }
  125. }
  126. EntityList_next(it_second);
  127. }
  128. }
  129. EntityList_next(it_first);
  130. }
  131. }
  132. void level_update(Level* level, Director* director) {
  133. level_process_add(level);
  134. level_process_remove(level);
  135. level_process_update(level, director);
  136. level_process_collision(level, director);
  137. }
  138. void level_render(Level* level, Director* director, Canvas* canvas) {
  139. FOREACH(item, level->entities) {
  140. entity_call_render(*item, director, canvas);
  141. }
  142. }