daggy 1 gadu atpakaļ
vecāks
revīzija
1c1692e870
5 mainītis faili ar 299 papildinājumiem un 0 dzēšanām
  1. 15 0
      application.fam
  2. BIN
      assets/yap.png
  3. BIN
      assets/yapinvader.png
  4. 284 0
      space.c
  5. BIN
      yapinvader.png

+ 15 - 0
application.fam

@@ -0,0 +1,15 @@
+App(
+    appid="yapinvaders",
+    name="Yappy Invaders",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="yapinvaders_app",
+    requires=["gui"],
+    stack_size=1 * 1024,
+    order=90,
+    fap_icon="yapinvader.png",
+    fap_category="Games",
+    fap_icon_assets="assets",
+    fap_author="@dagnazty",
+    fap_version="1.0",
+    fap_description="Yappy version of Space Invaders.",
+)

BIN
assets/yap.png


BIN
assets/yapinvader.png


+ 284 - 0
space.c

@@ -0,0 +1,284 @@
+#include <furi.h>
+#include <gui/gui.h>
+#include <input/input.h>
+#include <stdlib.h>
+#include <gui/elements.h>
+#include <furi_hal.h>
+#include <math.h>
+#include <yapinvaders_icons.h> 
+
+#define PROJECTILES_MAX 10
+#define ENEMIES_MAX 10
+
+int enemy_movement_direction = 1;
+int move_down_step = 0;
+int enemy_move_counter = 0;
+int enemy_move_threshold = 20;
+
+typedef struct { int x, y; } Point;
+
+typedef struct { 
+    Point position; 
+} Player;
+
+typedef struct { 
+    Point position; 
+    bool active; 
+} Projectile;
+
+
+typedef struct {
+    Point position;
+    bool active;
+} Enemy;
+
+typedef struct {
+    Player player;
+    Projectile projectiles[PROJECTILES_MAX];
+    int projectiles_count;
+    bool game_over;
+    Enemy enemies[ENEMIES_MAX];
+    int current_wave;
+    bool waiting_for_restart;
+    bool running;
+    int score; 
+} GameState;
+
+GameState game_state;
+
+void game_state_init(GameState* state) {
+    state->player.position = (Point){64, 54};
+    state->projectiles_count = 0;
+    for(int i = 0; i < PROJECTILES_MAX; ++i) {
+        state->projectiles[i].active = false;
+    }
+    state->running = true; 
+    state->game_over = false; 
+    state->current_wave = 0;
+    state->waiting_for_restart = false;
+    state->score = 0;
+}
+
+void handle_input(GameState* state, InputEvent* input_event) {
+    if(input_event->type == InputTypeShort) {
+        switch(input_event->key) {
+            case InputKeyLeft:
+                state->player.position.x = (state->player.position.x - 1) < 0 ? 0 : state->player.position.x - 1;
+                break;
+            case InputKeyRight:
+                state->player.position.x = (state->player.position.x + 1) > 124 ? 124 : state->player.position.x + 1;
+                break;
+            case InputKeyOk:
+                if(state->projectiles_count < PROJECTILES_MAX) {
+                    for(int i = 0; i < PROJECTILES_MAX; ++i) {
+                        if(!state->projectiles[i].active) {
+                            state->projectiles[i].position = (Point){state->player.position.x, state->player.position.y};
+                            state->projectiles[i].active = true;
+                            state->projectiles_count++;
+                            break;
+                        }
+                    }
+                }
+                break;
+            case InputKeyBack:
+                state->game_over = true;
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+void initialize_enemies(GameState* state) {
+    int rows = 2;
+    int cols = ENEMIES_MAX / rows;
+
+
+    int horizontalSpacing = 128 / cols;
+    int verticalSpacing = 10;
+
+    for(int i = 0; i < ENEMIES_MAX; ++i) {
+        state->enemies[i].position.x = (i % cols) * horizontalSpacing + (horizontalSpacing / 2); 
+        state->enemies[i].position.y = (i / cols) * verticalSpacing + 10;
+        state->enemies[i].active = true;
+    }
+
+    state->current_wave++;
+}
+
+void update_enemy_positions(GameState* state) {
+    enemy_move_counter++;
+    if(enemy_move_counter >= enemy_move_threshold) {
+        bool changeDirection = false;
+        int newDirection = enemy_movement_direction;
+
+        for(int i = 0; i < ENEMIES_MAX; ++i) {
+            if(state->enemies[i].active) {
+                if ((state->enemies[i].position.x <= 0 && enemy_movement_direction < 0) ||
+                    (state->enemies[i].position.x >= 124 && enemy_movement_direction > 0)) {
+                    changeDirection = true;
+                    newDirection *= -1; 
+                    break; 
+                }
+            }
+        }
+
+        for(int i = 0; i < ENEMIES_MAX; ++i) {
+            if(state->enemies[i].active) {
+                if (!changeDirection) {
+                    state->enemies[i].position.x += enemy_movement_direction;
+                }
+            }
+        }
+
+        if (changeDirection) {
+            for(int i = 0; i < ENEMIES_MAX; ++i) {
+                if(state->enemies[i].active) {
+                    state->enemies[i].position.x += newDirection;
+                    state->enemies[i].position.y += 5;
+                }
+            }
+            enemy_movement_direction = newDirection;
+        }
+
+        enemy_move_counter = 0;
+    }
+}
+
+void handle_collisions(GameState* state) {
+    for(int p = 0; p < PROJECTILES_MAX; ++p) {
+        if(state->projectiles[p].active) {
+            for(int e = 0; e < ENEMIES_MAX; ++e) {
+                if(state->enemies[e].active) {
+                    if(abs(state->projectiles[p].position.x - state->enemies[e].position.x) < 5 &&
+                       abs(state->projectiles[p].position.y - state->enemies[e].position.y) < 5) {
+                        state->projectiles[p].active = false;
+                        state->enemies[e].active = false;
+                        state->projectiles_count--;
+                        state->score += 10; 
+                        break; 
+                    }
+                }
+            }
+        }
+    }
+}
+
+bool all_enemies_destroyed(GameState* state) {
+    for(int i = 0; i < ENEMIES_MAX; ++i) {
+        if(state->enemies[i].active) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void render_game_over_screen(Canvas* canvas) {
+    canvas_clear(canvas);
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignCenter, "Game Over!");
+    canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, "Press OK to restart");
+}
+
+void update_game_state(GameState* state) {
+    for(int i = 0; i < PROJECTILES_MAX; ++i) {
+        if(state->projectiles[i].active) {
+            state->projectiles[i].position.y -= 2;
+            if(state->projectiles[i].position.y < 0) {
+                state->projectiles[i].active = false;
+                state->projectiles_count--;
+            }
+        }
+    }
+
+    for(int i = 0; i < ENEMIES_MAX; ++i) {
+        if(state->enemies[i].active && state->enemies[i].position.y >= state->player.position.y) {
+            state->game_over = true; 
+            break;
+        }
+    }
+    
+    if(all_enemies_destroyed(state)) {
+        initialize_enemies(state);
+    }
+
+    update_enemy_positions(state); 
+    handle_collisions(state); 
+}
+
+void render_callback(Canvas* const canvas, void* ctx) {
+    GameState* state = (GameState*)ctx;
+    if (!canvas || !state) return; 
+    if(state->game_over) {
+        render_game_over_screen(canvas); 
+    } else {
+    canvas_clear(canvas);
+    char score_text[30];
+    snprintf(score_text, sizeof(score_text), "Score: %d", state->score);
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, score_text);
+    canvas_draw_icon(canvas, state->player.position.x, state->player.position.y, &I_yapinvader);
+    for(int i = 0; i < PROJECTILES_MAX; ++i) {
+        if(state->projectiles[i].active) {
+            canvas_draw_circle(canvas, state->projectiles[i].position.x, state->projectiles[i].position.y, 1);
+            }
+        }
+    }
+    for(int i = 0; i < ENEMIES_MAX; ++i) {
+        if(state->enemies[i].active) {
+            canvas_draw_icon(canvas, state->enemies[i].position.x, state->enemies[i].position.y, &I_yap);
+        }
+    }
+}
+
+static void input_callback(InputEvent* input_event, void* ctx) {
+    GameState* state = (GameState*)ctx;
+    if (!state) return;
+
+    if (input_event->key == InputKeyBack && input_event->type == InputTypeShort) {
+        state->running = false;
+        return;
+    }
+    
+    if (state->game_over) {
+        if (input_event->key == InputKeyOk && input_event->type == InputTypeShort) {
+            game_state_init(state);  
+            initialize_enemies(state); 
+            state->game_over = false; 
+        }
+    } else {
+        handle_input(state, input_event);
+    }
+}
+
+int32_t yapinvaders_app(void) {
+    Gui* gui = furi_record_open(RECORD_GUI);
+    ViewPort* view_port = view_port_alloc();
+    view_port_draw_callback_set(view_port, render_callback, &game_state);
+    view_port_input_callback_set(view_port, input_callback, &game_state);
+    gui_add_view_port(gui, view_port, GuiLayerFullscreen);
+
+    game_state_init(&game_state);
+    initialize_enemies(&game_state);
+
+    while (game_state.running) {
+        if (game_state.game_over) {
+            if (game_state.waiting_for_restart) {
+                game_state_init(&game_state);
+                initialize_enemies(&game_state);
+                game_state.waiting_for_restart = false;
+            }
+        } else {
+            update_game_state(&game_state);
+            view_port_update(view_port);
+        }
+
+        furi_delay_ms(30); 
+    }
+
+    gui_remove_view_port(gui, view_port);
+    view_port_free(view_port);
+    furi_record_close(RECORD_GUI);
+
+    return 0;
+}

BIN
yapinvader.png