From fd4f8ffbb153ca7f466e5105c20313e05736619d Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 4 Oct 2025 18:18:42 +0700 Subject: [PATCH] Restructured everything so hot reloading works --- .gitignore | 1 + Makefile | 5 +- game.cpp | 267 +++++++++++++++++++++++++++++++---------------------- game.h | 26 +++--- game.so | Bin 143680 -> 0 bytes main.cpp | 106 ++++++++------------- 6 files changed, 211 insertions(+), 194 deletions(-) delete mode 100755 game.so diff --git a/.gitignore b/.gitignore index 0817540..02bf6d2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ /game.fasl /writeimage *.fasl +*.so diff --git a/Makefile b/Makefile index f2ed9c7..4ae304b 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,11 @@ main: main.cpp game.h Makefile $(CC) $(CFLAGS) $(INCLUDES) main.cpp $(LDFLAGS) -o main game.so: game.cpp game.h lib.h sprites.h game_data.h Makefile - $(CC) $(CFLAGS) $(INCLUDES) -shared -fPIC game.cpp -L./lib -lraylib -lm -o game.so + $(CC) $(CFLAGS) $(INCLUDES) -shared -fPIC game.cpp -L./lib -lraylib -lm -o game.so.tmp + mv game.so.tmp game.so run: all - ./main + LD_LIBRARY_PATH=lib ./main clean: rm -vf *.so *.o main diff --git a/game.cpp b/game.cpp index 93f6f08..6295c23 100644 --- a/game.cpp +++ b/game.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include using namespace std; @@ -10,8 +12,7 @@ using namespace std; #include "game.h" #include "game_data.h" -// Assets Init() { -void Init() { +GameState *InitState() { knight_anims[ANIM_KNIGHT_IDLE] = knight_idle; knight_anims[ANIM_KNIGHT_RUN] = knight_run; knight_anims[ANIM_KNIGHT_ATTACK_SIDE1] = knight_attack_side1; @@ -28,41 +29,56 @@ void Init() { LoadTexture("./assets/Factions/Knights/Troops/Warrior/Blue/Warrior_Blue.png"); assets.textures[TEX_MOUSE_CURSOR] = LoadTexture("./assets/UI/Pointers/01.png"); assets.textures[TEX_TARGET_RETICLE] = LoadTexture("./assets/UI/Pointers/02.png"); - // return assets; + + auto game = new GameState; + game->assets = assets; + // TODO: Probably want to use idiomatic C++ here? + game->knights = (Knight*)calloc(MAX_KNIGHTS, sizeof(Knight)); + game->anim_playbacks = (SpriteAnimationPlayback*)calloc(MAX_KNIGHTS, sizeof(SpriteAnimationPlayback)); + const int entities = MAX_KNIGHTS; + for (int i = 0; i < entities; i++) { + f32 rand_x = GetRandomValue(165, 1130); + f32 rand_y = 100 + ((float)950 / (float)entities) * i; + game->knights[i].position = {rand_x,rand_y}; + + PlayAnimation(ANIM_KNIGHT_IDLE, knight_anims, &game->anim_playbacks[i]); + int rand_frame = GetRandomValue(0, knight_anims[ANIM_KNIGHT_IDLE].total_frames); + game->anim_playbacks[i].current_frame = rand_frame; + } + game->entity_count = entities; + + game->camera = Camera2D{.offset = {0, 0}, .target = {0, 0}, .rotation = 0.0f, .zoom = 1.0f}; + + return game; } -void Update(GameState *game, Camera2D *cam, float dt) { +GameState *Init() { + SetTraceLogLevel(4); + InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Tiny Knights"); + + int monitor = GetCurrentMonitor(); + int monitor_width = GetMonitorWidth(monitor); + int monitor_height = GetMonitorHeight(monitor); + int win_pos_x = monitor_width / 2 - SCREEN_WIDTH / 2; + int win_pos_y = monitor_height / 2 - SCREEN_HEIGHT / 2; + SetWindowPosition(win_pos_x, win_pos_y); + + SetTargetFPS(TARGET_FPS); + + HideCursor(); + + return InitState(); +} + +void Input(GameState *state) { if (IsMouseButtonPressed(0)) { - game->selection_mouse_start_pos = optional{GetScreenToWorld2D(GetMousePosition(), *cam)}; - } - - if (game->selection_mouse_start_pos.has_value()) { - Point start_pos = game->selection_mouse_start_pos.value(); - Point current_pos = GetScreenToWorld2D(GetMousePosition(), *cam); - - if (Vector2DistanceSqr(current_pos, start_pos) >= 100.0f) { - f32 width = current_pos.x - start_pos.x; - f32 height = current_pos.y - start_pos.y; - f32 x = width >= 0.0f ? start_pos.x : current_pos.x; - f32 y = height >= 0.0f ? start_pos.y : current_pos.y; - Rectangle rect = {x, y, fabs(width), fabs(height)}; - for (int i = 0; i < game->entity_count; i++) { - Rectangle mouse_select_area = { - game->knights[i].position.x + knight_colrect_select.x, - game->knights[i].position.y + knight_colrect_select.y, - knight_colrect_select.width, - knight_colrect_select.height, - }; - game->knights[i].selected = - CheckCollisionRecs(rect, mouse_select_area); - } - } + state->selection_mouse_start_pos = optional{GetScreenToWorld2D(GetMousePosition(), state->camera)}; } if (IsMouseButtonReleased(0)) { // TODO: This is what should happen when the distance is too small // Point start_pos = game->selection_mouse_start_pos.some.point; - Point start_pos = game->selection_mouse_start_pos.value(); - Point current_pos = GetScreenToWorld2D(GetMousePosition(), *cam); + Point start_pos = state->selection_mouse_start_pos.value(); + Point current_pos = GetScreenToWorld2D(GetMousePosition(), state->camera); if (Vector2DistanceSqr(current_pos, start_pos) >= 100.0f) { f32 width = current_pos.x - start_pos.x; @@ -70,72 +86,68 @@ void Update(GameState *game, Camera2D *cam, float dt) { f32 x = width >= 0.0f ? start_pos.x : current_pos.x; f32 y = height >= 0.0f ? start_pos.y : current_pos.y; Rectangle rect = {x, y, fabs(width), fabs(height)}; - for (int i = 0; i < game->entity_count; i++) { + for (int i = 0; i < state->entity_count; i++) { Rectangle mouse_select_area = { - game->knights[i].position.x + knight_colrect_select.x, - game->knights[i].position.y + knight_colrect_select.y, + state->knights[i].position.x + knight_colrect_select.x, + state->knights[i].position.y + knight_colrect_select.y, knight_colrect_select.width, knight_colrect_select.height, }; - game->knights[i].selected = + state->knights[i].selected = CheckCollisionRecs(rect, mouse_select_area); } } else { // TODO: This kind of sucks that we're doing all the math here to calculate // the position of the collider, we need a helper that calculates origin offset int k_idx = -1; - for (int i = 0; i < game->entity_count; i++) { + for (int i = 0; i < state->entity_count; i++) { Rectangle mouse_select_area = { - game->knights[i].position.x + knight_colrect_select.x, - game->knights[i].position.y + knight_colrect_select.y, + state->knights[i].position.x + knight_colrect_select.x, + state->knights[i].position.y + knight_colrect_select.y, knight_colrect_select.width, knight_colrect_select.height, }; if (CheckCollisionPointRec(current_pos, mouse_select_area)) { k_idx = i; } - game->knights[i].selected = false; + state->knights[i].selected = false; } if (k_idx != -1) { - game->knights[k_idx].selected = true; + state->knights[k_idx].selected = true; } } - game->selection_mouse_start_pos = optional{}; + state->selection_mouse_start_pos = optional{}; } if (IsMouseButtonPressed(1)) { - Point target_pos = GetScreenToWorld2D(GetMousePosition(), *cam); + Point target_pos = GetScreenToWorld2D(GetMousePosition(), state->camera); bool any = false; - for (int i = 0; i < game->entity_count; i++) { - if (game->knights[i].selected) { - game->knights[i].move_target_point = target_pos; - game->knights[i].ordered_to_move = true; + for (int i = 0; i < state->entity_count; i++) { + if (state->knights[i].selected) { + state->knights[i].move_target_point = target_pos; + state->knights[i].ordered_to_move = true; any = true; } } if (any) { - game->selected_point = optional{target_pos}; + state->selected_point = optional{target_pos}; } } - const float cam_move_speed = 1050.0f * dt; - Vector2 cam_vel = {}; - if (IsKeyDown(KEY_D)) { - cam_vel.x = -1; + f32 cam_speed = 5.0; + if (IsKeyDown(KEY_RIGHT)) { + state->camera.target.x += cam_speed; } - if (IsKeyDown(KEY_A)) { - cam_vel.x = 1; + if (IsKeyDown(KEY_LEFT)) { + state->camera.target.x -= cam_speed; } - if (IsKeyDown(KEY_W)) { - cam_vel.y = 1; + if (IsKeyDown(KEY_UP)) { + state->camera.target.y -= cam_speed; } - if (IsKeyDown(KEY_S)) { - cam_vel.y = -1; + if (IsKeyDown(KEY_DOWN)) { + state->camera.target.y += cam_speed; } - cam_vel = Vector2Normalize(cam_vel); - game->camera_position = Vector2Scale(cam_vel, cam_move_speed); - cam->offset = Vector2Add(cam->offset, game->camera_position); - // if (IsKeyPressed(KEY_SPACE) && game->selected_knight != -1) { + // if (IsKeyPressed(KEY_SPACE) && state->selected_knight != -1) { // int k_idx = game->selected_knight; // if (game->knights[k_idx].state != KNIGHT_ATTACKING) { // game->knights[k_idx].state = KNIGHT_ATTACKING; @@ -145,14 +157,50 @@ void Update(GameState *game, Camera2D *cam, float dt) { if (IsKeyPressed(KEY_F1)) { global_debug_mode = !global_debug_mode; } + if (IsKeyPressed(KEY_F2)) { + auto new_state = InitState(); + *state = *new_state; + } +} +void Update(GameState *state) { + // cout << "Cool" << endl; + if (state->selection_mouse_start_pos.has_value()) { + Point start_pos = state->selection_mouse_start_pos.value(); + Point current_pos = GetScreenToWorld2D(GetMousePosition(), state->camera); + + if (Vector2DistanceSqr(current_pos, start_pos) >= 100.0f) { + f32 width = current_pos.x - start_pos.x; + f32 height = current_pos.y - start_pos.y; + f32 x = width >= 0.0f ? start_pos.x : current_pos.x; + f32 y = height >= 0.0f ? start_pos.y : current_pos.y; + Rectangle rect = {x, y, fabs(width), fabs(height)}; + for (int i = 0; i < state->entity_count; i++) { + Rectangle mouse_select_area = { + state->knights[i].position.x + knight_colrect_select.x, + state->knights[i].position.y + knight_colrect_select.y, + knight_colrect_select.width, + knight_colrect_select.height, + }; + state->knights[i].selected = + CheckCollisionRecs(rect, mouse_select_area); + } + } + } + float dt = 0.33; + const float cam_move_speed = 1050.0f * dt; + // TODO: This was moved out of Input + Vector2 cam_vel = {}; + cam_vel = Vector2Normalize(cam_vel); + state->camera_position = Vector2Scale(cam_vel, cam_move_speed); + state->camera.offset = Vector2Add(state->camera.offset, state->camera_position); // Process animation data - TickSpriteAnimations(game->anim_playbacks, game->entity_count); + TickSpriteAnimations(state->anim_playbacks, state->entity_count); // Handle knight movement if they are moving somewhere - for (int i = 0; i < game->entity_count; i++) { + for (int i = 0; i < state->entity_count; i++) { Vector2 input_vel = {}; - Knight *knight = &game->knights[i]; + Knight *knight = &state->knights[i]; if (knight->ordered_to_move) { Vector2 target = knight->move_target_point; if (Vector2DistanceSqr(target, knight->position) < 2.5f) { @@ -165,9 +213,9 @@ void Update(GameState *game, Camera2D *cam, float dt) { // Handle the attacking state, if not handle state transitions if (knight->state == KnightState::ATTACKING) { - if (IsAnimationFinished(game->anim_playbacks[i])) { + if (IsAnimationFinished(state->anim_playbacks[i])) { knight->state = KnightState::IDLE; - PlayAnimation(ANIM_KNIGHT_IDLE, knight_anims, &game->anim_playbacks[i]); + PlayAnimation(ANIM_KNIGHT_IDLE, knight_anims, &state->anim_playbacks[i]); } } else { if (input_vel.x != 0) { @@ -175,12 +223,12 @@ void Update(GameState *game, Camera2D *cam, float dt) { } if (input_vel.x != 0 || input_vel.y != 0) { if (knight->state == KnightState::IDLE) { - PlayAnimation(ANIM_KNIGHT_RUN, knight_anims, &game->anim_playbacks[i]); + PlayAnimation(ANIM_KNIGHT_RUN, knight_anims, &state->anim_playbacks[i]); knight->state = KnightState::RUNNING; } } else { if (knight->state == KnightState::RUNNING) { - PlayAnimation(ANIM_KNIGHT_IDLE, knight_anims, &game->anim_playbacks[i]); + PlayAnimation(ANIM_KNIGHT_IDLE, knight_anims, &state->anim_playbacks[i]); knight->state = KnightState::IDLE; } } @@ -188,33 +236,21 @@ void Update(GameState *game, Camera2D *cam, float dt) { if (i == 0) continue; // Sort the entities by y position using Insertion Sort int j = i; - while (j > 0 && game->knights[j].position.y < game->knights[j - 1].position.y) { + while (j > 0 && state->knights[j].position.y < state->knights[j - 1].position.y) { // Swap position - Knight temp_k = game->knights[j - 1]; - game->knights[j - 1] = game->knights[j]; - game->knights[j] = temp_k; + Knight temp_k = state->knights[j - 1]; + state->knights[j - 1] = state->knights[j]; + state->knights[j] = temp_k; // Swap animations - SpriteAnimationPlayback temp_a = game->anim_playbacks[j - 1]; - game->anim_playbacks[j - 1] = game->anim_playbacks[j]; - game->anim_playbacks[j] = temp_a; + SpriteAnimationPlayback temp_a = state->anim_playbacks[j - 1]; + state->anim_playbacks[j - 1] = state->anim_playbacks[j]; + state->anim_playbacks[j] = temp_a; j--; } } } -void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { - // BeginDrawing(); - // { - // BeginMode2D(state.camera); - // { - // } - // EndMode2D(); - // } - // EndDrawing(); - (void)cam; - (void)dt; - ClearBackground({100, 149, 237, 255}); - +void Draw2D(GameState *state) { int size = 32; int topx = SCREEN_WIDTH / 2 - size * 32 / 2; int topy = SCREEN_HEIGHT / 2 - size * 32 / 2; @@ -234,15 +270,15 @@ void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { } Vector2 pos = {(f32)(32 * col + topx), (f32)(32 * row + topy)}; Rectangle src_rect = {(f32)(32 * atlas_col), (f32)(32 * atlas_row), 32, 32}; - D_DrawTextureRec(assets.textures[TEX_GROUND], src_rect, pos, WHITE); + D_DrawTextureRec(state->assets.textures[TEX_GROUND], src_rect, pos, WHITE); } } if (state->selected_point.has_value()) { Vector2 marker_pos = state->selected_point.value(); - marker_pos.x -= assets.textures[TEX_TARGET_RETICLE].width / 2; - marker_pos.y -= assets.textures[TEX_TARGET_RETICLE].height / 2; - D_DrawTextureV(assets.textures[TEX_TARGET_RETICLE], marker_pos, WHITE); + marker_pos.x -= state->assets.textures[TEX_TARGET_RETICLE].width / 2; + marker_pos.y -= state->assets.textures[TEX_TARGET_RETICLE].height / 2; + D_DrawTextureV(state->assets.textures[TEX_TARGET_RETICLE], marker_pos, WHITE); } // for (int i = 0; i < game->anim_playbacks_count; i++) { @@ -260,7 +296,7 @@ void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { src_rect.width = -abs((int)src_rect.width); } Rectangle dest_rect = {knight->position.x, knight->position.y, 192, 192}; - Texture2D tex = assets.textures[TEX_KNIGHT]; + Texture2D tex = state->assets.textures[TEX_KNIGHT]; D_DrawTexturePro(tex, src_rect, dest_rect, knight_origin, 0.0f, WHITE); if (knight->selected == true) { Rectangle knight_col_area = { @@ -276,7 +312,7 @@ void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { if (state->selection_mouse_start_pos.has_value()) { Point start_pos = state->selection_mouse_start_pos.value(); - Point current_pos = GetScreenToWorld2D(GetMousePosition(), cam); + Point current_pos = GetScreenToWorld2D(GetMousePosition(), state->camera); if (Vector2DistanceSqr(current_pos, start_pos) >= 100.0f) { f32 width = current_pos.x - start_pos.x; @@ -288,32 +324,41 @@ void Draw(GameState *state, Assets assets, Camera2D cam, float dt) { } } - Vector2 world = GetScreenToWorld2D(GetMousePosition(), cam); + Vector2 world = GetScreenToWorld2D(GetMousePosition(), state->camera); Vector2 pointer_pos = Vector2Subtract(world, {24, 19}); - D_DrawTextureV(assets.textures[TEX_MOUSE_CURSOR], pointer_pos, WHITE); - - DrawRectangle(SCREEN_WIDTH - 106, 4, 88, 30, WHITE); - DrawFPS(SCREEN_WIDTH - 100, 10); + D_DrawTextureV(state->assets.textures[TEX_MOUSE_CURSOR], pointer_pos, WHITE); } extern "C" { - void game_init(GameState* state) { - (void)state; - Init(); + GameState* game_init() { + return Init(); } - void game_update(GameState* state) { - (void)state; - // Your update logic - } - - void game_draw(GameState* state) { - (void)state; - // Your render logic + void game_step(GameState* state) { + Input(state); + Update(state); + BeginDrawing(); + { + ClearBackground({100, 149, 237, 255}); + BeginMode2D(state->camera); + { + Draw2D(state); + } + EndMode2D(); + + DrawRectangle(SCREEN_WIDTH - 106, 4, 88, 30, WHITE); + DrawFPS(SCREEN_WIDTH - 100, 10); + } + EndDrawing(); } void game_cleanup(GameState* state) { - (void)state; - // Cleanup + delete state; + printf("Cleaning Up\n"); + CloseWindow(); + } + + bool window_should_close() { + return WindowShouldClose(); } } diff --git a/game.h b/game.h index 1705ad9..f1ee791 100644 --- a/game.h +++ b/game.h @@ -9,7 +9,7 @@ using namespace std; #define TEXTURES_BUF_SIZE 16 #define TARGET_FPS 60 -#define MAX_KNIGHTS 5000 +#define MAX_KNIGHTS 50 #define SCREEN_WIDTH 1300 #define SCREEN_HEIGHT 1080 @@ -43,9 +43,9 @@ struct Knight { u8 ordered_to_move; }; -typedef struct Assets { +struct Assets { Texture2D *textures; -} Assets; +}; struct GameState { Camera2D camera; @@ -54,17 +54,21 @@ struct GameState { optional selected_point; Knight *knights; - SpriteAnimationPlayback* anim_playbacks; + SpriteAnimationPlayback *anim_playbacks; Knight *selected_knights; optional selection_mouse_start_pos; int entity_count; -}; + Assets assets; -extern "C" { - void game_init(GameState* state); - void game_update(GameState* state); - void game_draw(GameState* state); - void game_cleanup(GameState* state); -} + ~GameState() { + free(knights); + free(anim_playbacks); + for (int i = 0; i < TEXTURES_BUF_SIZE; i++) { + UnloadTexture(assets.textures[i]); + } + free(assets.textures); + printf("I freed the stuff?\n"); + } +}; diff --git a/game.so b/game.so deleted file mode 100755 index a7e616a3d45d5ffee94be15d2961bae38e756a1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 143680 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 VJKDF*xc|c2B>%%fgM-)T{{Y!&tQP

#include -#include "include/raylib.h" -#include "game.h" -#include "game_data.h" +struct GameState; -struct GameAPI { - void* lib_handle; +struct GameApi { + struct GameState *(*init)(); + void (*step) (GameState *state); + void (*finalize) (GameState *state); + void (*reload) (GameState *state); + void (*unload) (GameState *state); + bool (*window_should_close)(); +}; + +struct Game { time_t last_write_time; - - void (*init)(GameState*); - void (*update)(GameState*); - void (*draw)(GameState*); - void (*cleanup)(GameState*); + void *gamelib_handle; + ino_t gamelib_id; + GameApi api; + GameState *state; }; time_t get_file_write_time(const char* path) { @@ -25,88 +30,49 @@ time_t get_file_write_time(const char* path) { return 0; } -bool load_game_api(GameAPI* api) { +bool load_game_api(Game* game) { const char* lib_path = "./game.so"; time_t write_time = get_file_write_time(lib_path); - if (write_time <= api->last_write_time) { - return false; // No changes + if (write_time <= game->last_write_time) { + return false; } - if (api->lib_handle) { - dlclose(api->lib_handle); + if (game->gamelib_handle) { + dlclose(game->gamelib_handle); } - api->lib_handle = dlopen(lib_path, RTLD_NOW); - if (!api->lib_handle) { + game->gamelib_handle = dlopen(lib_path, RTLD_NOW); + + if (!game->gamelib_handle) { printf("Failed to load game.so: %s\n", dlerror()); return false; } - api->init = (void(*)(GameState*))dlsym(api->lib_handle, "game_init"); - api->update = (void(*)(GameState*))dlsym(api->lib_handle, "game_update"); - api->draw = (void(*)(GameState*))dlsym(api->lib_handle, "game_draw"); - api->cleanup = (void(*)(GameState*))dlsym(api->lib_handle, "game_cleanup"); + game->api.init = (GameState*(*)())dlsym(game->gamelib_handle, "game_init"); + game->api.step = (void(*)(GameState*))dlsym(game->gamelib_handle, "game_step"); + game->api.finalize = (void(*)(GameState*))dlsym(game->gamelib_handle, "game_cleanup"); + game->api.window_should_close = (bool(*)())dlsym(game->gamelib_handle, "window_should_close"); - api->last_write_time = write_time; + game->last_write_time = write_time; printf("Reloaded game.so\n"); return true; } int main(void) { - SetTraceLogLevel(4); - InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Tiny Knights"); + Game game; - int monitor = GetCurrentMonitor(); - int monitor_width = GetMonitorWidth(monitor); - int monitor_height = GetMonitorHeight(monitor); - int win_pos_x = monitor_width / 2 - SCREEN_WIDTH / 2; - int win_pos_y = monitor_height / 2 - SCREEN_HEIGHT / 2; - SetWindowPosition(win_pos_x, win_pos_y); + load_game_api(&game); - SetTargetFPS(TARGET_FPS); - - HideCursor(); - - GameAPI api = {}; - GameState state = {}; - - state.camera.zoom = 1.0f; - - api.init(&state); - // Assets assets = api.init(&state); - - GameState game = {}; - game.knights = (Knight*)calloc(MAX_KNIGHTS, sizeof(Knight)); - game.anim_playbacks = (SpriteAnimationPlayback*)calloc(MAX_KNIGHTS, sizeof(SpriteAnimationPlayback)); - const int entities = MAX_KNIGHTS; - for (int i = 0; i < entities; i++) { - - f32 rand_x = GetRandomValue(165, 1130); - f32 rand_y = 100 + ((float)950 / (float)entities) * i; - game.knights[i].position = {rand_x,rand_y}; - - PlayAnimation(ANIM_KNIGHT_IDLE, knight_anims, &game.anim_playbacks[i]); - int rand_frame = GetRandomValue(0, knight_anims[ANIM_KNIGHT_IDLE].total_frames); - game.anim_playbacks[i].current_frame = rand_frame; - } - game.entity_count = entities; - - api.update(&game); - while (!WindowShouldClose()) { - game.frame_count++; + game.state = game.api.init(); + while (!game.api.window_should_close()) { + // game.frame_count++; // float dt = GetFrameTime(); + load_game_api(&game); - api.update(&state); - api.draw(&state); + game.api.step(game.state); } - free(game.knights); - free(game.anim_playbacks); - // for (int i = 0; i < TEXTURES_BUF_SIZE; i++) { - // UnloadTexture(assets.textures[i]); - // } - // free(assets.textures); - CloseWindow(); + game.api.finalize(game.state); return 0; }