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

More declarative way to setup game

SG 1 год назад
Родитель
Сommit
299da8d5f5
10 измененных файлов с 98 добавлено и 34 удалено
  1. 9 0
      director.c
  2. 2 0
      director.h
  3. 2 0
      director_i.h
  4. 8 0
      engine.h
  5. 38 11
      level.c
  6. 3 8
      level.h
  7. 9 1
      level_i.h
  8. 14 6
      level_manager.c
  9. 1 1
      level_manager.h
  10. 12 7
      main.c

+ 9 - 0
director.c

@@ -8,6 +8,7 @@ struct Director {
     RunningGameEngine* engine;
     LevelManager* level_manager;
     InputState input;
+    void* game_context;
 };
 
 Director* director_alloc() {
@@ -47,3 +48,11 @@ LevelManager* director_level_manager_get(Director* director) {
 Level* director_level_get(Director* director) {
     return level_manager_current_level_get(director->level_manager);
 }
+
+void* director_game_context_get(Director* director) {
+    return director->game_context;
+}
+
+void director_game_context_set(Director* director, void* context) {
+    director->game_context = context;
+}

+ 2 - 0
director.h

@@ -18,6 +18,8 @@ LevelManager* director_level_manager_get(Director* director);
 
 Level* director_level_get(Director* director);
 
+void* director_game_context_get(Director* director);
+
 #ifdef __cplusplus
 }
 #endif

+ 2 - 0
director_i.h

@@ -15,6 +15,8 @@ void director_engine_set(Director* director, RunningGameEngine* engine);
 
 void director_level_manager_set(Director* director, LevelManager* level_manager);
 
+void director_game_context_set(Director* director, void* context);
+
 #ifdef __cplusplus
 }
 #endif

+ 8 - 0
engine.h

@@ -5,3 +5,11 @@
 #include "level_manager.h"
 #include "director.h"
 #include "entity.h"
+
+typedef struct {
+    void (*start)(LevelManager* level_manager, void* context);
+    void (*stop)(void* context);
+    size_t context_size;
+} Game;
+
+extern const Game game;

+ 38 - 11
level.c

@@ -16,17 +16,21 @@ struct Level {
     EntityList_t entities;
     EntityList_t to_add;
     EntityList_t to_remove;
-    LevelBehaviour behaviour;
+    const LevelBehaviour* behaviour;
     void* context;
 };
 
-Level* level_alloc(void) {
+Level* level_alloc(const LevelBehaviour* behaviour) {
     Level* level = malloc(sizeof(Level));
     EntityList_init(level->entities);
     EntityList_init(level->to_add);
     EntityList_init(level->to_remove);
-    level->behaviour = LEVEL_BEHAVIOUR_EMPTY;
-    level->context = NULL;
+    level->behaviour = behaviour;
+    if(behaviour->context_size > 0) {
+        level->context = malloc(behaviour->context_size);
+    } else {
+        level->context = NULL;
+    }
     LEVEL_DEBUG("Allocated level at %p", level);
     return level;
 }
@@ -72,6 +76,10 @@ void level_free(Level* level) {
     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);
 }
@@ -102,13 +110,8 @@ void level_clear(Level* level) {
     } while(!EntityList_empty_p(level->to_add) || !EntityList_empty_p(level->to_remove));
 }
 
-void level_behaviour_set(Level* level, LevelBehaviour behaviour, void* context) {
-    level->behaviour = behaviour;
-    level->context = context;
-}
-
-Entity* level_add_entity(Level* level, const EntityDescription* behaviour) {
-    Entity* entity = entity_alloc(behaviour);
+Entity* level_add_entity(Level* level, const EntityDescription* description) {
+    Entity* entity = entity_alloc(description);
     EntityList_push_back(level->to_add, entity);
     entity_call_start(level, entity);
     return entity;
@@ -163,4 +166,28 @@ void level_render(Level* level, Director* director, Canvas* canvas) {
     FOREACH(item, level->entities) {
         entity_call_render(*item, director, canvas);
     }
+}
+
+void level_call_start(Level* level) {
+    if(level->behaviour->start) {
+        level->behaviour->start(level, level->context);
+    }
+}
+
+void level_call_stop(Level* level) {
+    if(level->behaviour->stop) {
+        level->behaviour->stop(level, level->context);
+    }
+}
+
+void level_call_alloc(Level* level) {
+    if(level->behaviour->alloc) {
+        level->behaviour->alloc(level, level->context);
+    }
+}
+
+void level_call_free(Level* level) {
+    if(level->behaviour->free) {
+        level->behaviour->free(level, level->context);
+    }
 }

+ 3 - 8
level.h

@@ -9,18 +9,13 @@ extern "C" {
 typedef struct Level Level;
 
 typedef struct {
+    void (*alloc)(Level* level, void* context);
+    void (*free)(Level* level, void* context);
     void (*start)(Level* level, void* context);
     void (*stop)(Level* level, void* context);
-    void (*update_pre)(Level* level, Director* director, void* context);
-    void (*update_post)(Level* level, Director* director, void* context);
-    void (*render_pre)(Level* level, Director* director, Canvas* canvas, void* context);
-    void (*render_post)(Level* level, Director* director, Canvas* canvas, void* context);
+    size_t context_size;
 } LevelBehaviour;
 
-#define LEVEL_BEHAVIOUR_EMPTY ((LevelBehaviour){NULL, NULL, NULL, NULL, NULL, NULL})
-
-void level_behaviour_set(Level* level, LevelBehaviour behaviour, void* context);
-
 void level_clear(Level* level);
 
 Entity* level_add_entity(Level* level, const EntityDescription* behaviour);

+ 9 - 1
level_i.h

@@ -5,7 +5,7 @@
 extern "C" {
 #endif
 
-Level* level_alloc(void);
+Level* level_alloc(const LevelBehaviour* behaviour);
 
 void level_free(Level* level);
 
@@ -13,6 +13,14 @@ void level_update(Level* level, Director* director);
 
 void level_render(Level* level, Director* director, Canvas* canvas);
 
+void level_call_alloc(Level* level);
+
+void level_call_free(Level* level);
+
+void level_call_start(Level* level);
+
+void level_call_stop(Level* level);
+
 #ifdef __cplusplus
 }
 #endif

+ 14 - 6
level_manager.c

@@ -20,9 +20,12 @@ LevelManager* level_manager_alloc() {
 }
 
 void level_manager_free(LevelManager* lm) {
+    level_call_stop(lm->current_level);
+
     LevelList_it_t it;
     LevelList_it(it, lm->levels);
     while(!LevelList_end_p(it)) {
+        level_call_free(*LevelList_cref(it));
         level_free(*LevelList_cref(it));
         LevelList_next(it);
     }
@@ -31,12 +34,14 @@ void level_manager_free(LevelManager* lm) {
     free(lm);
 }
 
-Level* level_manager_add_level(LevelManager* manager) {
-    UNUSED(manager);
-    Level* level = level_alloc();
-    LevelList_push_back(manager->levels, level);
-    if(!manager->current_level) {
-        manager->current_level = level;
+Level* level_manager_add_level(LevelManager* lm, const LevelBehaviour* behaviour) {
+    UNUSED(lm);
+    Level* level = level_alloc(behaviour);
+    LevelList_push_back(lm->levels, level);
+    level_call_alloc(level);
+    if(!lm->current_level) {
+        lm->current_level = level;
+        level_call_start(level);
     }
     return level;
 }
@@ -51,9 +56,12 @@ Level* level_manager_current_level_get(LevelManager* lm) {
 
 void level_manager_update(LevelManager* lm, Director* director) {
     if(lm->next_level) {
+        level_call_stop(lm->current_level);
         lm->current_level = lm->next_level;
+        level_call_start(lm->current_level);
         lm->next_level = NULL;
     }
+
     level_update(lm->current_level, director);
 }
 

+ 1 - 1
level_manager.h

@@ -7,7 +7,7 @@ extern "C" {
 
 typedef struct LevelManager LevelManager;
 
-Level* level_manager_add_level(LevelManager* manager);
+Level* level_manager_add_level(LevelManager* manager, const LevelBehaviour* behaviour);
 
 void level_manager_next_level_set(LevelManager* manager, Level* level);
 

+ 12 - 7
main.c

@@ -1,13 +1,11 @@
 #include <furi.h>
+#include "engine.h"
 #include "game_engine.h"
 #include "director_i.h"
 #include "level_manager_i.h"
 #include "level_i.h"
 #include "entity_i.h"
 
-void game_setup(Level* level);
-void game_destroy(void);
-
 static void frame_cb(RunningGameEngine* engine, Canvas* canvas, InputState input, void* context) {
     Director* director = context;
     director_input_set(director, input);
@@ -24,9 +22,13 @@ int32_t game_app(void* p) {
     Director* director = director_alloc();
     LevelManager* level_manager = level_manager_alloc();
     director_level_manager_set(director, level_manager);
-    Level* level = level_manager_add_level(level_manager);
 
-    game_setup(level);
+    void* game_context = NULL;
+    if(game.context_size > 0) {
+        game_context = malloc(game.context_size);
+        director_game_context_set(director, game_context);
+    }
+    game.start(level_manager, NULL);
 
     GameEngineSettings settings = game_engine_settings_init();
     settings.fps = 60.0f;
@@ -39,11 +41,14 @@ int32_t game_app(void* p) {
     game_engine_run(engine);
     game_engine_free(engine);
 
-    game_destroy();
-
     level_manager_free(level_manager);
     director_free(director);
 
+    game.stop(game_context);
+    if(game_context) {
+        free(game_context);
+    }
+
     int32_t entities = entities_get_count();
     if(entities != 0) {
         FURI_LOG_E("Game", "Memory leak detected: %ld entities still allocated", entities);