Explorar o código

Remove walls, add collision, add Icon entity

jblanked hai 1 ano
pai
achega
2c8e49331b
Modificáronse 4 ficheiros con 185 adicións e 329 borrados
  1. 109 73
      draw/world.c
  2. 4 3
      draw/world.h
  3. 71 239
      game.c
  4. 1 14
      game.h

+ 109 - 73
draw/world.c

@@ -1,103 +1,139 @@
 #include <draw/world.h>
 
-static void draw_bounds(Canvas *canvas)
+void draw_bounds(Canvas *canvas)
 {
     // Draw the outer bounds adjusted by camera offset
     // we draw this last to ensure users can see the bounds
     canvas_draw_frame(canvas, -camera_x, -camera_y, WORLD_WIDTH, WORLD_HEIGHT);
 }
 
-void draw_example_world(Canvas *canvas)
+void draw_example_world(Level *level)
 {
-    // Draw other elements adjusted by camera offset
-    // Static Dot at (72, 40)
-    canvas_draw_dot(canvas, 72 - camera_x, 40 - camera_y);
-
-    // Static Circle at (16, 16) with radius 4
-    canvas_draw_circle(canvas, 16 - camera_x, 16 - camera_y, 4);
-
-    // Static 8x8 Rectangle Frame at (96, 48)
-    canvas_draw_frame(canvas, 96 - camera_x, 48 - camera_y, 8, 8);
-
-    // Static earth icon at (112, 56)
-    canvas_draw_icon(canvas, 112 - camera_x, 56 - camera_y, &I_icon_earth);
-
-    // static home icon at (128, 24)
-    canvas_draw_icon(canvas, 128 - camera_x, 24 - camera_y, &I_icon_home);
-
-    // static menu icon at (144, 24)
-    canvas_draw_icon(canvas, 144 - camera_x, 24 - camera_y, &I_icon_info);
-
-    // static man icon at (160, 56)
-    canvas_draw_icon(canvas, 160 - camera_x, 56 - camera_y, &I_icon_man);
-
-    // static woman icon at (208, 56)
-    canvas_draw_icon(canvas, 168 - camera_x, 56 - camera_y, &I_icon_woman);
-
-    // static plant icon at (168, 32)
-    canvas_draw_icon(canvas, 168 - camera_x, 32 - camera_y, &I_icon_plant);
-
-    // tree world
-    draw_icon_half_world(canvas, true, &I_icon_tree);
-
-    // Draw the bounds
-    draw_bounds(canvas);
+    spawn_icon(level, &I_icon_earth, 112, 56);
+    spawn_icon(level, &I_icon_home, 128, 24);
+    spawn_icon(level, &I_icon_info, 144, 24);
+    spawn_icon(level, &I_icon_man, 160, 56);
+    spawn_icon(level, &I_icon_woman, 168, 56);
+    spawn_icon(level, &I_icon_plant, 168, 32);
 }
 
-void draw_tree_world(Canvas *canvas)
+void draw_tree_world(Level *level)
 {
-    // two full left/up tree lines
+    // Spawn two full left/up tree lines
     for (int i = 0; i < 2; i++)
     {
-        draw_icon_line(canvas, (Vector){5, 2 + i * 17}, 22, true, &I_icon_tree);  // horizontal
-        draw_icon_line(canvas, (Vector){5 + i * 17, 2}, 11, false, &I_icon_tree); // vertical
+        for (int j = 0; j < 22; j++)
+        {
+            spawn_icon(level, &I_icon_tree, 5 + j * 17, 2 + i * 17); // Horizontal lines
+        }
+        for (int j = 0; j < 11; j++)
+        {
+            spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + j * 17); // Vertical lines
+        }
     }
 
-    // two full down tree lines
+    // Spawn two full down tree lines
     for (int i = 9; i < 11; i++)
     {
-        draw_icon_line(canvas, (Vector){5, 2 + i * 17}, 22, true, &I_icon_tree); // horizontal
+        for (int j = 0; j < 22; j++)
+        {
+            spawn_icon(level, &I_icon_tree, 5 + j * 17, 2 + i * 17); // Horizontal lines
+        }
     }
-    // two full right tree lines
+
+    // Spawn two full right tree lines
     for (int i = 20; i < 22; i++)
     {
-        draw_icon_line(canvas, (Vector){5 + i * 17, 50}, 8, false, &I_icon_tree); // vertical
+        for (int j = 0; j < 8; j++)
+        {
+            spawn_icon(level, &I_icon_tree, 5 + i * 17, 50 + j * 17); // Vertical lines
+        }
     }
 
-    // draw labyinth line-by-line
-
-    // third line (14 left, 3 middle, 0 right) - exit line
-    draw_icon_line(canvas, (Vector){5, 2 + 2 * 17}, 14, true, &I_icon_tree);          // 14 left
-    draw_icon_line(canvas, (Vector){5 + 16 * 17, 2 + 2 * 17}, 3, true, &I_icon_tree); // 3 middle
-
-    // fourth line (3 left, 6 middle, 4 right)
-    draw_icon_line(canvas, (Vector){5, 2 + 3 * 17}, 3, true, &I_icon_tree);           // 3 left
-    draw_icon_line(canvas, (Vector){5 + 7 * 17, 2 + 3 * 17}, 6, true, &I_icon_tree);  // 6 middle
-    draw_icon_line(canvas, (Vector){5 + 15 * 17, 2 + 3 * 17}, 4, true, &I_icon_tree); // 4 right
+    // Spawn labyrinth lines
+    // Third line (14 left, 3 middle, 0 right) - exit line
+    for (int i = 0; i < 14; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + 2 * 17);
+    }
+    for (int i = 0; i < 3; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 16 * 17 + i * 17, 2 + 2 * 17);
+    }
 
-    // fifth line (6 left, 7 middle, 0 right)
-    draw_icon_line(canvas, (Vector){5, 2 + 4 * 17}, 6, true, &I_icon_tree);          // 6 left
-    draw_icon_line(canvas, (Vector){5 + 7 * 17, 2 + 4 * 17}, 7, true, &I_icon_tree); // 7 middle
+    // Fourth line (3 left, 6 middle, 4 right)
+    for (int i = 0; i < 3; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + 3 * 17); // 3 left
+    }
+    for (int i = 0; i < 6; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 7 * 17 + i * 17, 2 + 3 * 17); // 6 middle
+    }
+    for (int i = 0; i < 4; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 15 * 17 + i * 17, 2 + 3 * 17); // 4 right
+    }
 
-    // sixth line (5 left, 6 middle, 7 right)
-    draw_icon_line(canvas, (Vector){5, 2 + 5 * 17}, 5, true, &I_icon_tree);           // 5 left
-    draw_icon_line(canvas, (Vector){5 + 7 * 17, 2 + 5 * 17}, 3, true, &I_icon_tree);  // 3 middle
-    draw_icon_line(canvas, (Vector){5 + 15 * 17, 2 + 5 * 17}, 7, true, &I_icon_tree); // 4 right
+    // Fifth line (6 left, 7 middle, 0 right)
+    for (int i = 0; i < 6; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + 4 * 17); // 6 left
+    }
+    for (int i = 0; i < 7; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 7 * 17 + i * 17, 2 + 4 * 17); // 7 middle
+    }
 
-    // seventh line (0 left, 7 middle, 4 right)
-    draw_icon_line(canvas, (Vector){5 + 6 * 17, 2 + 6 * 17}, 7, true, &I_icon_tree);  // 7 middle
-    draw_icon_line(canvas, (Vector){5 + 14 * 17, 2 + 6 * 17}, 4, true, &I_icon_tree); // 4 right
+    // Sixth line (5 left, 6 middle, 7 right)
+    for (int i = 0; i < 5; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + 5 * 17); // 5 left
+    }
+    for (int i = 0; i < 3; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 7 * 17 + i * 17, 2 + 5 * 17); // 3 middle
+    }
+    for (int i = 0; i < 7; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 15 * 17 + i * 17, 2 + 5 * 17); // 7 right
+    }
 
-    // eighth line (4 left, 3 middle, 4 right)
-    draw_icon_line(canvas, (Vector){5, 2 + 7 * 17}, 4, true, &I_icon_tree);           // 4 left
-    draw_icon_line(canvas, (Vector){5 + 7 * 17, 2 + 7 * 17}, 3, true, &I_icon_tree);  // 3 middle
-    draw_icon_line(canvas, (Vector){5 + 15 * 17, 2 + 7 * 17}, 4, true, &I_icon_tree); // 4 right
+    // Seventh line (0 left, 7 middle, 4 right)
+    for (int i = 0; i < 7; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 6 * 17 + i * 17, 2 + 6 * 17); // 7 middle
+    }
+    for (int i = 0; i < 4; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 14 * 17 + i * 17, 2 + 6 * 17); // 4 right
+    }
 
-    // ninth line (3 left, 2 middle, 3 right)
-    draw_icon_line(canvas, (Vector){5, 2 + 8 * 17}, 3, true, &I_icon_tree);           // 3 left
-    draw_icon_line(canvas, (Vector){5 + 5 * 17, 2 + 8 * 17}, 1, true, &I_icon_tree);  // 2 middle
-    draw_icon_line(canvas, (Vector){5 + 11 * 17, 2 + 8 * 17}, 3, true, &I_icon_tree); // 3 right
+    // Eighth line (4 left, 3 middle, 4 right)
+    for (int i = 0; i < 4; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + 7 * 17); // 4 left
+    }
+    for (int i = 0; i < 3; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 7 * 17 + i * 17, 2 + 7 * 17); // 3 middle
+    }
+    for (int i = 0; i < 4; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 15 * 17 + i * 17, 2 + 7 * 17); // 4 right
+    }
 
-    // Draw the bounds
-    draw_bounds(canvas);
+    // Ninth line (3 left, 2 middle, 3 right)
+    for (int i = 0; i < 3; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + i * 17, 2 + 8 * 17); // 3 left
+    }
+    for (int i = 0; i < 1; i++) // 2 middle
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 5 * 17 + i * 17, 2 + 8 * 17);
+    }
+    for (int i = 0; i < 3; i++)
+    {
+        spawn_icon(level, &I_icon_tree, 5 + 11 * 17 + i * 17, 2 + 8 * 17); // 3 right
+    }
 }

+ 4 - 3
draw/world.h

@@ -1,5 +1,6 @@
 #pragma once
 #include <draw/draw.h>
-
-void draw_example_world(Canvas *canvas);
-void draw_tree_world(Canvas *canvas);
+#include <game.h>
+void draw_bounds(Canvas *canvas);
+void draw_example_world(Level *level);
+void draw_tree_world(Level *level);

+ 71 - 239
game.c

@@ -2,43 +2,6 @@
 #include "flip_world.h"
 #include "flip_world_icons.h"
 
-Wall walls[] = {
-    WALL(true, 12, 0, 3),
-    WALL(false, 3, 3, 17),
-    WALL(false, 23, 3, 6),
-    WALL(true, 3, 4, 57),
-    WALL(true, 28, 4, 56),
-    WALL(false, 4, 7, 5),
-    WALL(false, 12, 7, 13),
-    WALL(true, 8, 8, 34),
-    WALL(true, 12, 8, 42),
-    WALL(true, 24, 8, 8),
-    WALL(true, 16, 11, 8),
-    WALL(false, 17, 11, 4),
-    WALL(true, 20, 12, 22),
-    WALL(false, 6, 17, 2),
-    WALL(true, 24, 19, 15),
-    WALL(true, 16, 22, 16),
-    WALL(false, 4, 24, 1),
-    WALL(false, 21, 28, 2),
-    WALL(false, 6, 33, 2),
-    WALL(false, 13, 34, 3),
-    WALL(false, 17, 37, 11),
-    WALL(true, 16, 41, 14),
-    WALL(false, 20, 41, 5),
-    WALL(true, 20, 45, 12),
-    WALL(true, 24, 45, 12),
-    WALL(false, 4, 46, 2),
-    WALL(false, 9, 46, 3),
-    WALL(false, 6, 50, 3),
-    WALL(true, 12, 53, 7),
-    WALL(true, 8, 54, 6),
-    WALL(false, 4, 60, 19),
-    WALL(false, 26, 60, 6),
-};
-
-// Tree World
-
 // Background rendering function
 // TODO: each object needs a collision box so we can detect collisions and prevent movement through walls.
 static void background_render(Canvas *canvas, Vector pos)
@@ -54,8 +17,8 @@ static void background_render(Canvas *canvas, Vector pos)
     camera_x = CLAMP(camera_x, WORLD_WIDTH - SCREEN_WIDTH, 0);
     camera_y = CLAMP(camera_y, WORLD_HEIGHT - SCREEN_HEIGHT, 0);
 
-    // Draw the world
-    draw_tree_world(canvas);
+    // Draw the outer bounds adjusted by camera offset
+    draw_bounds(canvas);
 }
 
 /****** Entities: Player ******/
@@ -91,34 +54,43 @@ static void player_spawn(Level *level, GameManager *manager)
     player_context->sprite = game_manager_sprite_load(manager, "player.fxbm");
 }
 
+// Modify player_update to track direction
 static void player_update(Entity *self, GameManager *manager, void *context)
 {
-    UNUSED(context);
-
-    // Get game input
+    PlayerContext *player = (PlayerContext *)context;
     InputState input = game_manager_input_get(manager);
-
-    // Get player position
     Vector pos = entity_pos_get(self);
 
-    // Control player movement
+    // Reset direction each frame
+    player->dx = 0;
+    player->dy = 0;
+
     if (input.held & GameKeyUp)
+    {
         pos.y -= 2;
+        player->dy = -1;
+    }
     if (input.held & GameKeyDown)
+    {
         pos.y += 2;
+        player->dy = 1;
+    }
     if (input.held & GameKeyLeft)
+    {
         pos.x -= 2;
+        player->dx = -1;
+    }
     if (input.held & GameKeyRight)
+    {
         pos.x += 2;
+        player->dx = 1;
+    }
 
-    // Clamp player position to screen bounds, considering player sprite size (10x10)
     pos.x = CLAMP(pos.x, WORLD_WIDTH - 5, 5);
     pos.y = CLAMP(pos.y, WORLD_HEIGHT - 5, 5);
 
-    // Set new player position
     entity_pos_set(self, pos);
 
-    // Control game exit
     if (input.pressed & GameKeyBack)
     {
         game_manager_game_stop(manager);
@@ -128,6 +100,7 @@ static void player_update(Entity *self, GameManager *manager, void *context)
 static void player_render(Entity *self, GameManager *manager, Canvas *canvas, void *context)
 {
     // Get player context
+    UNUSED(manager);
     PlayerContext *player = context;
 
     // Get player position
@@ -138,13 +111,6 @@ static void player_render(Entity *self, GameManager *manager, Canvas *canvas, vo
 
     // Draw player sprite relative to camera
     canvas_draw_sprite(canvas, player->sprite, pos.x - camera_x - 5, pos.y - camera_y - 5);
-
-    // Get game context
-    GameContext *game_context = game_manager_game_context_get(manager);
-
-    // Draw score (optional)
-    UNUSED(game_context);
-    // canvas_printf(canvas, 0, 7, "Score: %lu", game_context->score);
 }
 
 static const EntityDescription player_desc = {
@@ -157,226 +123,92 @@ static const EntityDescription player_desc = {
     .context_size = sizeof(PlayerContext), // size of entity context, will be automatically allocated and freed
 };
 
-/****** Entities: Target ******/
-
-static Vector random_pos(void)
-{
-    return (Vector){rand() % (SCREEN_WIDTH - 8) + 4, rand() % (SCREEN_HEIGHT - 8) + 4};
-}
+/****** Level ******/
 
-static void target_start(Entity *self, GameManager *manager, void *context)
+static void level_alloc(Level *level, GameManager *manager, void *context)
 {
-    UNUSED(context);
     UNUSED(manager);
-    // Set target position
-    entity_pos_set(self, random_pos());
-    // Add collision circle to target entity
-    // Circle is centered in target x and y, and it's radius is 3
-    entity_collider_add_circle(self, 3);
-}
-
-static void target_render(Entity *self, GameManager *manager, Canvas *canvas, void *context)
-{
     UNUSED(context);
-    UNUSED(manager);
-
-    // Get target position
-    Vector pos = entity_pos_get(self);
 
-    // Draw target relative to the camera
-    canvas_draw_disc(canvas, pos.x - camera_x, pos.y - camera_y, 3);
-}
-
-static void target_collision(Entity *self, Entity *other, GameManager *manager, void *context)
-{
-    UNUSED(context);
-    // Check if target collided with player
-    if (entity_description_get(other) == &player_desc)
-    {
-        // Increase score
-        GameContext *game_context = game_manager_game_context_get(manager);
-        game_context->score++;
+    // Add player entity to the level
+    player_spawn(level, manager);
 
-        // Move target to new random position
-        entity_pos_set(self, random_pos());
-    }
+    draw_tree_world(level);
+    // draw_example_world(level);
 }
 
-static const EntityDescription target_desc = {
-    .start = target_start,         // called when entity is added to the level
-    .stop = NULL,                  // called when entity is removed from the level
-    .update = NULL,                // called every frame
-    .render = target_render,       // called every frame, after update
-    .collision = target_collision, // called when entity collides with another entity
-    .event = NULL,                 // called when entity receives an event
-    .context_size = 0,             // size of entity context, will be automatically allocated and freed
+static const LevelBehaviour level = {
+    .alloc = level_alloc, // called once, when level allocated
+    .free = NULL,         // called once, when level freed
+    .start = NULL,        // called when level is changed to this level
+    .stop = NULL,         // called when level is changed from this level
+    .context_size = 0,    // size of level context, will be automatically allocated and freed
 };
 
-/****** Entities: Wall ******/
-
-static uint8_t wall_index;
-
-static void wall_start(Entity *self, GameManager *manager, void *context);
-
 typedef struct
 {
-    float width;
-    float height;
-} WallContext;
+    const Icon *icon;
+} IconContext;
 
-static void wall_render(Entity *self, GameManager *manager, Canvas *canvas, void *context)
+// Forward declaration of icon_desc
+static const EntityDescription icon_desc;
+
+static void icon_collision(Entity *self, Entity *other, GameManager *manager, void *context)
 {
     UNUSED(manager);
     UNUSED(self);
-    UNUSED(canvas);
-    UNUSED(context);
-
-    // WallContext *wall = context;
-
-    // Vector pos = entity_pos_get(self);
-
-    // Draw the wall relative to the camera
-    // canvas_draw_box(
-    //     canvas,
-    //     pos.x - camera_x - (wall->width / 2),
-    //     pos.y - camera_y - (wall->height / 2),
-    //     wall->width,
-    //     wall->height);
-}
-
-static void wall_collision(Entity *self, Entity *other, GameManager *manager, void *context)
-{
-    WallContext *wall = context;
-
-    // Check if wall collided with player
+    IconContext *icon = (IconContext *)context;
+    UNUSED(icon);
     if (entity_description_get(other) == &player_desc)
     {
-        // Increase score
-        GameContext *game_context = game_manager_game_context_get(manager);
-        game_context->score++;
-
         PlayerContext *player = (PlayerContext *)entity_context_get(other);
         if (player)
         {
-            if (player->dx || player->dy)
-            {
-                Vector pos = entity_pos_get(other);
-
-                // TODO: Based on where we collided, we should still slide across/down the wall.
-                UNUSED(wall);
-
-                if (player->dx)
-                {
-                    FURI_LOG_D(
-                        "Player",
-                        "Player collided with wall, dx: %d.  center:%f,%f",
-                        player->dx,
-                        (double)pos.x,
-                        (double)pos.y);
-                    pos.x -= player->dx;
-                    player->dx = 0;
-                }
-                if (player->dy)
-                {
-                    FURI_LOG_D(
-                        "Player",
-                        "Player collided with wall, dy: %d.  center:%f,%f",
-                        player->dy,
-                        (double)pos.x,
-                        (double)pos.y);
-                    pos.y -= player->dy;
-                    player->dy = 0;
-                }
-                entity_pos_set(other, pos);
-                FURI_LOG_D("Player", "Set to center:%f,%f", (double)pos.x, (double)pos.y);
-            }
-        }
-        else
-        {
-            FURI_LOG_D("Player", "Player collided with wall, but context null.");
+            Vector pos = entity_pos_get(other);
+            // Bounce the player back by 3 units opposite their last movement direction
+            pos.x -= player->dx * 3;
+            pos.y -= player->dy * 3;
+            entity_pos_set(other, pos);
         }
     }
-    else
-    {
-        // HACK: Wall touching other items destroys each other (to help find collider issues)
-        Level *level = game_manager_current_level_get(manager);
-        level_remove_entity(level, self);
-        level_remove_entity(level, other);
-    }
 }
 
-static const EntityDescription wall_desc = {
-    .start = wall_start,         // called when entity is added to the level
-    .stop = NULL,                // called when entity is removed from the level
-    .update = NULL,              // called every frame
-    .render = wall_render,       // called every frame, after update
-    .collision = wall_collision, // called when entity collides with another entity
-    .event = NULL,               // called when entity receives an event
-    .context_size =
-        sizeof(WallContext), // size of entity context, will be automatically allocated and freed
-};
-
-static void wall_start(Entity *self, GameManager *manager, void *context)
+static void icon_render(Entity *self, GameManager *manager, Canvas *canvas, void *context)
 {
     UNUSED(manager);
-
-    WallContext *wall = context;
-
-    // TODO: We can get the current number of items from the level (instead of wall_index).
-
-    if (wall_index < COUNT_OF(walls))
-    {
-        if (walls[wall_index].horizontal)
-        {
-            wall->width = walls[wall_index].length * 2;
-            wall->height = 1 * 2;
-        }
-        else
-        {
-            wall->width = 1 * 2;
-            wall->height = walls[wall_index].length * 2;
-        }
-
-        entity_pos_set(
-            self,
-            (Vector){
-                walls[wall_index].x + wall->width / 2, walls[wall_index].y + wall->height / 2});
-
-        entity_collider_add_rect(self, wall->width, wall->height);
-
-        wall_index++;
-    }
+    IconContext *icon_ctx = (IconContext *)context;
+    Vector pos = entity_pos_get(self);
+    canvas_draw_icon(canvas, pos.x - camera_x - 8, pos.y - camera_y - 8, icon_ctx->icon);
 }
 
-/****** Level ******/
-
-static void level_alloc(Level *level, GameManager *manager, void *context)
+static void icon_start(Entity *self, GameManager *manager, void *context)
 {
     UNUSED(manager);
     UNUSED(context);
-
-    // Add player entity to the level
-    player_spawn(level, manager);
-
-    // Add first target entity to the level
-    level_add_entity(level, &target_desc);
-
-    // Add wall entities to the level
-    wall_index = 0;
-    for (size_t i = 0; i < COUNT_OF(walls); i++)
-    {
-        level_add_entity(level, &wall_desc);
-    }
+    // Just add the collision rectangle for 16x16 icon
+    entity_collider_add_rect(self, 16, 16);
 }
 
-static const LevelBehaviour level = {
-    .alloc = level_alloc, // called once, when level allocated
-    .free = NULL,         // called once, when level freed
-    .start = NULL,        // called when level is changed to this level
-    .stop = NULL,         // called when level is changed from this level
-    .context_size = 0,    // size of level context, will be automatically allocated and freed
+static const EntityDescription icon_desc = {
+    .start = icon_start,
+    .stop = NULL,
+    .update = NULL,
+    .render = icon_render,
+    .collision = icon_collision,
+    .event = NULL,
+    .context_size = sizeof(IconContext),
 };
 
+// Helper function to spawn an icon entity at a given position
+void spawn_icon(Level *level, const Icon *icon, float x, float y)
+{
+    Entity *e = level_add_entity(level, &icon_desc);
+    IconContext *icon_ctx = entity_context_get(e);
+    icon_ctx->icon = icon;
+    // Set the entity position to the center of the icon
+    entity_pos_set(e, (Vector){x + 8, y + 8});
+}
+
 /****** Game ******/
 
 /*

+ 1 - 14
game.h

@@ -2,20 +2,7 @@
 #include "engine/engine.h"
 #include <draw/world.h>
 
-// from https://github.com/jamisonderek/flipper-zero-tutorials/blob/main/vgm/apps/air_labyrinth/walls.h
-typedef struct
-{
-    bool horizontal;
-    int x;
-    int y;
-    int length;
-} Wall;
-
-#define WALL(h, y, x, l)   \
-    (Wall)                 \
-    {                      \
-        h, x * 2, y * 2, l \
-    }
+void spawn_icon(Level *level, const Icon *icon, float x, float y);
 
 typedef struct
 {