Ivan Barsukov 1 год назад
Родитель
Сommit
6724da8894

+ 85 - 0
src/levels/level_menu/blinking_sprite.c

@@ -0,0 +1,85 @@
+#include "blinking_sprite.h"
+
+#include "../../engine/game_manager.h"
+
+#include "../../game.h"
+
+void
+blinking_sprite_init(Entity* entity,
+                     GameManager* manager,
+                     Vector pos,
+                     float delay,
+                     float show_duration,
+                     float hide_duration,
+                     const char* sprite_name)
+{
+    BlinkingSpriteContext* entity_context = entity_context_get(entity);
+    entity_pos_set(entity, pos);
+    entity_context->delay = delay;
+    entity_context->show_duration = show_duration;
+    entity_context->hide_duration = hide_duration;
+    entity_context->time = 0;
+    entity_context->sprite = game_manager_sprite_load(manager, sprite_name);
+}
+
+static void
+blinking_sprite_update(Entity* self,
+                       GameManager* manager,
+                       void* _entity_context)
+{
+    UNUSED(self);
+    UNUSED(manager);
+
+    BlinkingSpriteContext* entity_context = _entity_context;
+
+    entity_context->time += 1.0f;
+
+    if (entity_context->delay + entity_context->show_duration +
+          entity_context->hide_duration <
+        entity_context->time) {
+        entity_context->time = entity_context->delay;
+    }
+}
+
+static void
+blinking_sprite_render(Entity* self,
+                       GameManager* manager,
+                       Canvas* canvas,
+                       void* _entity_context)
+{
+    UNUSED(manager);
+    BlinkingSpriteContext* entity_context = _entity_context;
+
+    if (entity_context->sprite &&
+        entity_context->delay <= entity_context->time &&
+        entity_context->time <
+          entity_context->delay + entity_context->show_duration) {
+        Vector pos = entity_pos_get(self);
+        canvas_draw_sprite(canvas, entity_context->sprite, pos.x, pos.y);
+    }
+}
+
+static void
+blinking_sprite_event(Entity* self,
+                      GameManager* manager,
+                      EntityEvent event,
+                      void* _entity_context)
+{
+    UNUSED(self);
+    UNUSED(manager);
+
+    BlinkingSpriteContext* entity_context = _entity_context;
+    if (event.type == GameEventStopAnimation) {
+        entity_context->time = entity_context->delay;
+    }
+}
+
+const EntityDescription blinking_sprite_description = {
+    .start = NULL,
+    .stop = NULL,
+    .update = blinking_sprite_update,
+    .render = blinking_sprite_render,
+    .collision = NULL,
+    .event = blinking_sprite_event,
+    .context_size = sizeof(BlinkingSpriteContext),
+};

+ 25 - 0
src/levels/level_menu/blinking_sprite.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../../engine/entity.h"
+
+typedef struct Sprite Sprite;
+
+typedef struct
+{
+    Sprite* sprite;
+    float delay;
+    float show_duration;
+    float hide_duration;
+    float time;
+} BlinkingSpriteContext;
+
+void
+blinking_sprite_init(Entity* entity,
+                     GameManager* manager,
+                     Vector pos,
+                     float delay,
+                     float show_duration,
+                     float hide_duration,
+                     const char* sprite_name);
+
+extern const EntityDescription blinking_sprite_description;

+ 71 - 0
src/levels/level_menu/delayed_sprite.c

@@ -0,0 +1,71 @@
+#include "delayed_sprite.h"
+
+#include "../../engine/game_manager.h"
+
+#include "../../game.h"
+
+void
+delayed_sprite_init(Entity* entity,
+                    GameManager* manager,
+                    Vector pos,
+                    float delay,
+                    const char* sprite_name)
+{
+    DelayedSpriteContext* entity_context = entity_context_get(entity);
+    entity_pos_set(entity, pos);
+    entity_context->delay = delay;
+    entity_context->time = 0;
+    entity_context->sprite = game_manager_sprite_load(manager, sprite_name);
+}
+
+static void
+delayed_sprite_update(Entity* self, GameManager* manager, void* _entity_context)
+{
+    UNUSED(self);
+    UNUSED(manager);
+    DelayedSpriteContext* entity_context = _entity_context;
+
+    if (entity_context->time < entity_context->delay) {
+        entity_context->time += 1.0f;
+    }
+}
+
+static void
+delayed_sprite_render(Entity* self,
+                      GameManager* manager,
+                      Canvas* canvas,
+                      void* _entity_context)
+{
+    UNUSED(manager);
+    DelayedSpriteContext* entity_context = _entity_context;
+
+    if (entity_context->time >= entity_context->delay) {
+        Vector pos = entity_pos_get(self);
+        canvas_draw_sprite(canvas, entity_context->sprite, pos.x, pos.y);
+    }
+}
+
+static void
+delayed_sprite_event(Entity* self,
+                     GameManager* manager,
+                     EntityEvent event,
+                     void* _entity_context)
+{
+    UNUSED(self);
+    UNUSED(manager);
+
+    DelayedSpriteContext* entity_context = _entity_context;
+    if (event.type == GameEventStopAnimation) {
+        entity_context->time = entity_context->delay;
+    }
+}
+
+const EntityDescription delayed_sprite_description = {
+    .start = NULL,
+    .stop = NULL,
+    .update = delayed_sprite_update,
+    .render = delayed_sprite_render,
+    .collision = NULL,
+    .event = delayed_sprite_event,
+    .context_size = sizeof(DelayedSpriteContext),
+};

+ 21 - 0
src/levels/level_menu/delayed_sprite.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "../../engine/entity.h"
+
+typedef struct Sprite Sprite;
+
+typedef struct
+{
+    Sprite* sprite;
+    float delay;
+    float time;
+} DelayedSpriteContext;
+
+void
+delayed_sprite_init(Entity* entity,
+                    GameManager* manager,
+                    Vector pos,
+                    float delay,
+                    const char* sprite_name);
+
+extern const EntityDescription delayed_sprite_description;

+ 89 - 0
src/levels/level_menu/level_menu.c

@@ -0,0 +1,89 @@
+#include "level_menu.h"
+
+#include <stddef.h>
+
+#include "../../engine/vector.h"
+
+#include "../../game.h"
+
+#include "blinking_sprite.h"
+#include "delayed_sprite.h"
+#include "menu_entity.h"
+#include "moving_sprite.h"
+
+typedef struct
+{
+    Entity* quadrastic_logo;
+    Entity* press_ok;
+    Entity* left_button;
+    Entity* right_button;
+
+} LevelMenuContext;
+
+static void
+level_menu_alloc(Level* level, GameManager* manager, void* context)
+{
+    LevelMenuContext* menu_context = context;
+
+    static const float initial_amimation_duration = 45.0f;
+
+    // Quadrastic logo
+    menu_context->quadrastic_logo =
+      level_add_entity(level, &moving_sprite_description);
+    moving_sprite_init(menu_context->quadrastic_logo,
+                       manager,
+                       (Vector){ .x = 9, .y = 64 },
+                       (Vector){ .x = 9, .y = 2 },
+                       initial_amimation_duration,
+                       "quadrastic.fxbm");
+
+    // Press ok logo
+    menu_context->press_ok =
+      level_add_entity(level, &blinking_sprite_description);
+    blinking_sprite_init(menu_context->press_ok,
+                         manager,
+                         (Vector){ .x = 31, .y = 33 },
+                         initial_amimation_duration,
+                         15.0f,
+                         7.0f,
+                         "press_ok.fxbm");
+
+    // Settings button
+    menu_context->left_button =
+      level_add_entity(level, &delayed_sprite_description);
+    delayed_sprite_init(menu_context->left_button,
+                        manager,
+                        (Vector){ .x = 0, .y = 57 },
+                        initial_amimation_duration,
+                        "left_button.fxbm");
+
+    // About button
+    menu_context->right_button =
+      level_add_entity(level, &delayed_sprite_description);
+    delayed_sprite_init(menu_context->right_button,
+                        manager,
+                        (Vector){ .x = 115, .y = 57 },
+                        initial_amimation_duration,
+                        "right_button.fxbm");
+
+    // Menu
+    level_add_entity(level, &menu_description);
+}
+
+static void
+level_menu_start(Level* level, GameManager* manager, void* context)
+{
+    UNUSED(level);
+    UNUSED(manager);
+    UNUSED(context);
+
+    FURI_LOG_D(GAME_NAME, "Menu level started");
+}
+
+const LevelBehaviour level_menu = {
+    .alloc = level_menu_alloc,
+    .free = NULL,
+    .start = level_menu_start,
+    .stop = NULL,
+    .context_size = sizeof(LevelMenuContext),
+};

+ 5 - 0
src/levels/level_menu/level_menu.h

@@ -0,0 +1,5 @@
+#pragma once
+
+#include "../../engine/level.h"
+
+extern const LevelBehaviour level_menu;

+ 42 - 0
src/levels/level_menu/menu_entity.c

@@ -0,0 +1,42 @@
+#include "../../engine/entity.h"
+#include "../../engine/game_manager.h"
+#include "../../engine/level.h"
+
+#include "../../game.h"
+
+static void
+menu_update(Entity* self, GameManager* manager, void* _entity_context)
+{
+    UNUSED(self);
+    UNUSED(_entity_context);
+
+    GameContext* game_context = game_manager_game_context_get(manager);
+    Level* level = game_manager_current_level_get(manager);
+
+    InputState input = game_manager_input_get(manager);
+    if (input.pressed & GameKeyBack) {
+        game_manager_game_stop(manager);
+    } else if (input.pressed & GameKeyOk) {
+        game_manager_next_level_set(manager, game_context->levels.game);
+        level_send_event(
+          level, self, NULL, GameEventStopAnimation, (EntityEventValue){ 0 });
+    } else if (input.pressed & GameKeyLeft) {
+        game_manager_next_level_set(manager, game_context->levels.settings);
+        level_send_event(
+          level, self, NULL, GameEventStopAnimation, (EntityEventValue){ 0 });
+    } else if (input.pressed & GameKeyRight) {
+        game_manager_next_level_set(manager, game_context->levels.about);
+        level_send_event(
+          level, self, NULL, GameEventStopAnimation, (EntityEventValue){ 0 });
+    }
+}
+
+const EntityDescription menu_description = {
+    .start = NULL,
+    .stop = NULL,
+    .update = menu_update,
+    .render = NULL,
+    .collision = NULL,
+    .event = NULL,
+    .context_size = 0,
+};

+ 5 - 0
src/levels/level_menu/menu_entity.h

@@ -0,0 +1,5 @@
+#pragma once
+
+#include "../../engine/entity.h"
+
+extern const EntityDescription menu_description;

+ 84 - 0
src/levels/level_menu/moving_sprite.c

@@ -0,0 +1,84 @@
+#include "moving_sprite.h"
+
+#include "../../engine/entity.h"
+#include "../../engine/game_manager.h"
+
+#include "../../game.h"
+
+void
+moving_sprite_init(Entity* entity,
+                   GameManager* manager,
+                   Vector pos_start,
+                   Vector pos_end,
+                   float duration,
+                   const char* sprite_name)
+{
+    MovingSpriteContext* entity_context = entity_context_get(entity);
+    entity_context->pos_start = pos_start;
+    entity_context->pos_end = pos_end;
+    entity_context->duration = duration;
+    entity_context->time = 0;
+    entity_context->sprite = game_manager_sprite_load(manager, sprite_name);
+}
+
+static void
+moving_sprite_update(Entity* self, GameManager* manager, void* _entity_context)
+{
+    UNUSED(manager);
+    MovingSpriteContext* entity_context = _entity_context;
+
+    // lerp position between start and end for duration
+    if (entity_context->time < entity_context->duration) {
+        Vector dir =
+          vector_sub(entity_context->pos_end, entity_context->pos_start);
+        Vector len =
+          vector_mulf(dir, entity_context->time / entity_context->duration);
+        Vector pos = vector_add(entity_context->pos_start, len);
+
+        entity_pos_set(self, pos);
+        entity_context->time += 1.0f;
+    } else {
+        entity_pos_set(self, entity_context->pos_end);
+    }
+}
+
+static void
+moving_sprite_render(Entity* self,
+                     GameManager* manager,
+                     Canvas* canvas,
+                     void* _entity_context)
+{
+    UNUSED(manager);
+    MovingSpriteContext* entity_context = _entity_context;
+
+    if (entity_context->sprite) {
+        Vector pos = entity_pos_get(self);
+        canvas_draw_sprite(canvas, entity_context->sprite, pos.x, pos.y);
+    }
+}
+
+static void
+moving_sprite_event(Entity* self,
+                    GameManager* manager,
+                    EntityEvent event,
+                    void* _entity_context)
+{
+    UNUSED(self);
+    UNUSED(manager);
+    UNUSED(event);
+
+    MovingSpriteContext* entity_context = _entity_context;
+    if (event.type == GameEventStopAnimation) {
+        entity_context->time = entity_context->duration;
+    }
+}
+
+const EntityDescription moving_sprite_description = {
+    .start = NULL,
+    .stop = NULL,
+    .update = moving_sprite_update,
+    .render = moving_sprite_render,
+    .collision = NULL,
+    .event = moving_sprite_event,
+    .context_size = sizeof(MovingSpriteContext),
+};

+ 25 - 0
src/levels/level_menu/moving_sprite.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../../engine/entity.h"
+#include "../../engine/vector.h"
+
+typedef struct Sprite Sprite;
+
+typedef struct
+{
+    Sprite* sprite;
+    Vector pos_start;
+    Vector pos_end;
+    float duration;
+    float time;
+} MovingSpriteContext;
+
+void
+moving_sprite_init(Entity* entity,
+                   GameManager* manager,
+                   Vector pos_start,
+                   Vector pos_end,
+                   float duration,
+                   const char* sprite_name);
+
+extern const EntityDescription moving_sprite_description;