Просмотр исходного кода

Game manager: entity level get

SG 1 год назад
Родитель
Сommit
8e07a8151c
4 измененных файлов с 97 добавлено и 19 удалено
  1. 12 0
      game_manager.c
  2. 19 0
      game_manager.h
  3. 50 17
      level.c
  4. 16 2
      level.h

+ 12 - 0
game_manager.c

@@ -159,4 +159,16 @@ Sprite* game_manager_sprite_load(GameManager* manager, const char* path) {
     furi_string_free(path_full);
     furi_string_free(path_full);
 
 
     return sprite;
     return sprite;
+}
+
+Level* game_manager_entity_level_get(GameManager* manager, Entity* entity) {
+    LevelList_it_t it;
+    LevelList_it(it, manager->levels);
+    while(!LevelList_end_p(it)) {
+        if(level_contains_entity(*LevelList_cref(it), entity)) {
+            return *LevelList_cref(it);
+        }
+        LevelList_next(it);
+    }
+    return NULL;
 }
 }

+ 19 - 0
game_manager.h

@@ -13,8 +13,27 @@ Level* game_manager_add_level(GameManager* manager, const LevelBehaviour* behavi
 
 
 void game_manager_next_level_set(GameManager* manager, Level* level);
 void game_manager_next_level_set(GameManager* manager, Level* level);
 
 
+/**
+ * @brief Get the current level
+ * @warning This function returns current level, but in entity start or stop callbacks, the level may be different from entity's level.
+ * For example, if an entity is added to a level_game and you currently are in level_pause, this function will return level_pause.
+ * Use game_manager_entity_level_get to get the entity's level, or save the level pointer somewhere.
+ * 
+ * @param manager game manager instance
+ * @return Level* level instance
+ */
 Level* game_manager_current_level_get(GameManager* manager);
 Level* game_manager_current_level_get(GameManager* manager);
 
 
+/**
+ * @brief Get the level of an entity
+ * @warning This function is kinda slow, use it only when other methods are not possible
+ * 
+ * @param manager 
+ * @param entity 
+ * @return Level* 
+ */
+Level* game_manager_entity_level_get(GameManager* manager, Entity* entity);
+
 GameEngine* game_manager_engine_get(GameManager* manager);
 GameEngine* game_manager_engine_get(GameManager* manager);
 
 
 InputState game_manager_input_get(GameManager* manager);
 InputState game_manager_input_get(GameManager* manager);

+ 50 - 17
level.c

@@ -10,6 +10,7 @@ LIST_DEF(EntityList, Entity*, M_POD_OPLIST);
     M_EACH(name, list, EntityList_t)
     M_EACH(name, list, EntityList_t)
 
 
 #define LEVEL_DEBUG(...) FURI_LOG_D("Level", __VA_ARGS__)
 #define LEVEL_DEBUG(...) FURI_LOG_D("Level", __VA_ARGS__)
+#define LEVEL_INFO(...) FURI_LOG_I("Level", __VA_ARGS__)
 #define LEVEL_ERROR(...) FURI_LOG_E("Level", __VA_ARGS__)
 #define LEVEL_ERROR(...) FURI_LOG_E("Level", __VA_ARGS__)
 
 
 struct Level {
 struct Level {
@@ -19,11 +20,16 @@ struct Level {
     const LevelBehaviour* behaviour;
     const LevelBehaviour* behaviour;
     void* context;
     void* context;
     GameManager* manager;
     GameManager* manager;
+
+    bool clear;
+    LevelClearCallback clear_callback;
+    void* clear_context;
 };
 };
 
 
 Level* level_alloc(const LevelBehaviour* behaviour, GameManager* manager) {
 Level* level_alloc(const LevelBehaviour* behaviour, GameManager* manager) {
     Level* level = malloc(sizeof(Level));
     Level* level = malloc(sizeof(Level));
     level->manager = manager;
     level->manager = manager;
+    level->clear = false;
     EntityList_init(level->entities);
     EntityList_init(level->entities);
     EntityList_init(level->to_add);
     EntityList_init(level->to_add);
     EntityList_init(level->to_remove);
     EntityList_init(level->to_remove);
@@ -71,22 +77,7 @@ static bool level_entity_in_list_p(const EntityList_t list, Entity* entity) {
     return false;
     return false;
 }
 }
 
 
-void level_free(Level* level) {
-    level_clear(level);
-
-    EntityList_clear(level->entities);
-    EntityList_clear(level->to_add);
-    EntityList_clear(level->to_remove);
-
-    if(level->behaviour->context_size > 0) {
-        free(level->context);
-    }
-
-    LEVEL_DEBUG("Freeing level at %p", level);
-    free(level);
-}
-
-void level_clear(Level* level) {
+static void level_clear_entities(Level* level) {
     size_t iterations = 0;
     size_t iterations = 0;
 
 
     do {
     do {
@@ -109,7 +100,23 @@ void level_clear(Level* level) {
 
 
         // entity_call_stop can call level_remove_entity or level_add_entity
         // entity_call_stop can call level_remove_entity or level_add_entity
         // so we need to process to_add and to_remove again
         // so we need to process to_add and to_remove again
-    } while(!EntityList_empty_p(level->to_add) || !EntityList_empty_p(level->to_remove));
+    } while(!EntityList_empty_p(level->to_add) || !EntityList_empty_p(level->to_remove) ||
+            !EntityList_empty_p(level->entities));
+}
+
+void level_free(Level* level) {
+    level_clear_entities(level);
+
+    EntityList_clear(level->entities);
+    EntityList_clear(level->to_add);
+    EntityList_clear(level->to_remove);
+
+    if(level->behaviour->context_size > 0) {
+        free(level->context);
+    }
+
+    LEVEL_DEBUG("Freeing level at %p", level);
+    free(level);
 }
 }
 
 
 Entity* level_add_entity(Level* level, const EntityDescription* description) {
 Entity* level_add_entity(Level* level, const EntityDescription* description) {
@@ -182,7 +189,19 @@ static void level_process_collision(Level* level, GameManager* manager) {
     }
     }
 }
 }
 
 
+void level_clear(Level* level, LevelClearCallback callback, void* context) {
+    level->clear_callback = callback;
+    level->clear_context = context;
+    level->clear = true;
+}
+
 void level_update(Level* level, GameManager* manager) {
 void level_update(Level* level, GameManager* manager) {
+    if(level->clear) {
+        level_clear_entities(level);
+        level->clear_callback(level, level->clear_context);
+        level->clear = false;
+    }
+
     level_process_add(level);
     level_process_add(level);
     level_process_remove(level);
     level_process_remove(level);
     level_process_update(level, manager);
     level_process_update(level, manager);
@@ -273,4 +292,18 @@ Entity* level_entity_get(const Level* level, const EntityDescription* descriptio
 
 
 void* level_context_get(Level* level) {
 void* level_context_get(Level* level) {
     return level->context;
     return level->context;
+}
+
+bool level_contains_entity(const Level* level, const Entity* entity) {
+    FOREACH(item, level->entities) {
+        if(*item == entity) {
+            return true;
+        }
+    }
+    FOREACH(item, level->to_add) {
+        if(*item == entity) {
+            return true;
+        }
+    }
+    return false;
 }
 }

+ 16 - 2
level.h

@@ -16,12 +16,17 @@ typedef struct {
     size_t context_size;
     size_t context_size;
 } LevelBehaviour;
 } LevelBehaviour;
 
 
+/** Level reset callback */
+typedef void (*LevelClearCallback)(Level* level, void* context);
+
 /**
 /**
- * @brief Remove all entities from the level
+ * @brief Clear entities and call callback at the start of the next update
  * 
  * 
  * @param level level instance
  * @param level level instance
+ * @param callback callback
+ * @param context context
  */
  */
-void level_clear(Level* level);
+void level_clear(Level* level, LevelClearCallback callback, void* context);
 
 
 /**
 /**
  * @brief Add an entity to the level
  * @brief Add an entity to the level
@@ -84,6 +89,15 @@ Entity* level_entity_get(const Level* level, const EntityDescription* descriptio
  */
  */
 void* level_context_get(Level* level);
 void* level_context_get(Level* level);
 
 
+/**
+ * @brief Check if the level contains an entity
+ * 
+ * @param level level instance
+ * @param entity entity
+ * @return true if the level contains the entity
+ */
+bool level_contains_entity(const Level* level, const Entity* entity);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif