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

Update!

Added barriers and enemy projectiles to mimic the real space invaders.
daggy 1 год назад
Родитель
Сommit
f102420fc5
1 измененных файлов с 197 добавлено и 19 удалено
  1. 197 19
      space.c

+ 197 - 19
space.c

@@ -8,12 +8,21 @@
 #include <yapinvaders_icons.h>
 
 #define PROJECTILES_MAX 10
-#define ENEMIES_MAX 10
+#define ENEMIES_MAX 12
+#define BARRIERS_MAX 5
+#define BARRIER_WIDTH 10
+#define BARRIER_HEIGHT 3
+#define PROJECTILE_WIDTH 4
+#define PROJECTILE_HEIGHT 8
+#define ENEMY_PROJECTILE_SPEED .5 
+#define ENEMY_PROJECTILES_MAX 10
 
 int enemy_movement_direction = 1;
 int move_down_step = 0;
 int enemy_move_counter = 0;
 int enemy_move_threshold = 20;
+bool leftKeyPressed = false;
+bool rightKeyPressed = false;
 
 typedef struct { int x, y; } Point;
 
@@ -31,6 +40,11 @@ typedef struct {
     bool active;
 } Enemy;
 
+typedef struct {
+    Point position;
+    bool active;
+} Barrier;
+
 typedef struct {
     Player player;
     Projectile projectiles[PROJECTILES_MAX];
@@ -41,18 +55,36 @@ typedef struct {
     bool waiting_for_restart;
     bool running;
     int score; 
+    Barrier barriers[BARRIERS_MAX];
+    Projectile enemy_projectiles[ENEMY_PROJECTILES_MAX];
+    int enemy_projectiles_count;
 } GameState;
 
 GameState game_state;
+void deactivate_all_enemies(GameState* state);
 
 void game_state_init(GameState* state) {
-    state->player.position = (Point){64, 54};
+    state->player.position = (Point){64, 55};
     state->projectiles_count = 0;
     for(int i = 0; i < PROJECTILES_MAX; ++i) {
         state->projectiles[i].active = false;
     }
-    state->running = true; 
-    state->game_over = false; 
+        for(int i = 0; i < BARRIERS_MAX; ++i) {
+        state->barriers[i].position.x = 7 + i * (128 / BARRIERS_MAX);
+        state->barriers[i].position.y = 50;
+        state->barriers[i].active = true;
+    }
+    for(int p = 0; p < ENEMY_PROJECTILES_MAX; ++p) {
+        if(state->enemy_projectiles[p].active) {
+            state->enemy_projectiles[p].position.y += ENEMY_PROJECTILE_SPEED;
+            if(state->enemy_projectiles[p].position.y > 128) { 
+                state->enemy_projectiles[p].active = false;
+                state->enemy_projectiles_count--;
+            }
+        }
+    }
+    state->running = true;
+    state->game_over = false;
     state->current_wave = 0;
     state->waiting_for_restart = false;
     state->score = 0;
@@ -91,9 +123,8 @@ void handle_input(GameState* state, InputEvent* input_event) {
 void initialize_enemies(GameState* state) {
     int rows = 2;
     int cols = ENEMIES_MAX / rows;
-
-    int horizontalSpacing = 128 / cols; 
-    int verticalSpacing = 10; 
+    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);
@@ -115,7 +146,7 @@ void update_enemy_positions(GameState* state) {
                 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; 
+                    newDirection *= -1;
                     break;
                 }
             }
@@ -143,13 +174,35 @@ void update_enemy_positions(GameState* state) {
     }
 }
 
+void enemy_shoot(GameState* state) {
+    int activeEnemies[ENEMIES_MAX];
+    int activeCount = 0;
+    for(int e = 0; e < ENEMIES_MAX; ++e) {
+        if(state->enemies[e].active) {
+            activeEnemies[activeCount++] = e;
+        }
+    }
+    if(activeCount > 0) {
+        int chosenOne = activeEnemies[rand() % activeCount];
+        for(int p = 0; p < ENEMY_PROJECTILES_MAX; ++p) {
+            if(!state->enemy_projectiles[p].active) {
+                state->enemy_projectiles[p].position = (Point){state->enemies[chosenOne].position.x + 5, state->enemies[chosenOne].position.y + 10}; // Assuming enemy size for adjustment
+                state->enemy_projectiles[p].active = true;
+                state->enemy_projectiles_count++;
+                break;
+            }
+        }
+    }
+}
+
 void handle_collisions(GameState* state) {
+    int playerHitboxMargin = 2;
     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) {
+                    if(abs(state->projectiles[p].position.x - state->enemies[e].position.x) < 10 / 2 + 1 &&
+                       abs(state->projectiles[p].position.y - state->enemies[e].position.y) < 10 / 2 + 1) {
                         state->projectiles[p].active = false;
                         state->enemies[e].active = false;
                         state->projectiles_count--;
@@ -160,7 +213,61 @@ void handle_collisions(GameState* state) {
             }
         }
     }
-}
+    for(int p = 0; p < PROJECTILES_MAX; ++p) {
+        if(state->projectiles[p].active) {
+            for(int b = 0; b < BARRIERS_MAX; ++b) {
+                if(state->barriers[b].active && 
+                   abs(state->projectiles[p].position.x - state->barriers[b].position.x) < 3 &&
+                   abs(state->projectiles[p].position.y - state->barriers[b].position.y) < 3) {
+                    state->projectiles[p].active = false;
+                    state->barriers[b].active = false;
+                    break;
+                }
+            }
+        }
+    }
+    for(int e = 0; e < ENEMIES_MAX; ++e) {
+        if(state->enemies[e].active) {
+            for(int b = 0; b < BARRIERS_MAX; ++b) {
+                if(state->barriers[b].active &&
+                   abs(state->enemies[e].position.x - state->barriers[b].position.x) < 10 &&
+                   abs(state->enemies[e].position.y - state->barriers[b].position.y) < 10) {
+                    state->enemies[e].active = false;
+                    state->barriers[b].active = false;
+                    break;
+                }
+            }
+        }
+    }
+    for(int p = 0; p < ENEMY_PROJECTILES_MAX; ++p) {
+        if(state->enemy_projectiles[p].active) {
+            int projectileCenterX = state->enemy_projectiles[p].position.x + 2;
+            int projectileCenterY = state->enemy_projectiles[p].position.y + 4;
+            int playerCenterX = state->player.position.x + 5;
+            int playerCenterY = state->player.position.y + 5;
+            
+            if(abs(projectileCenterX - playerCenterX) < (5 - playerHitboxMargin) && 
+            abs(projectileCenterY - playerCenterY) < (5 - playerHitboxMargin)) {
+                deactivate_all_enemies(&game_state);
+                state->game_over = true;
+                state->enemy_projectiles[p].active = false;
+            }
+        }
+    }
+    for(int p = 0; p < ENEMY_PROJECTILES_MAX; ++p) {
+        if(state->enemy_projectiles[p].active) {
+            for(int b = 0; b < BARRIERS_MAX; ++b) {
+                if(state->barriers[b].active &&
+                abs(state->enemy_projectiles[p].position.x - state->barriers[b].position.x) < (BARRIER_WIDTH / 2 + PROJECTILE_WIDTH / 2) &&
+                (state->enemy_projectiles[p].position.y + PROJECTILE_HEIGHT >= state->barriers[b].position.y) &&
+                (state->enemy_projectiles[p].position.y <= state->barriers[b].position.y + BARRIER_HEIGHT)) {
+                    state->enemy_projectiles[p].active = false;
+                    break;
+                }
+            }
+        }
+    }
+}    
 
 bool all_enemies_destroyed(GameState* state) {
     for(int i = 0; i < ENEMIES_MAX; ++i) {
@@ -183,7 +290,14 @@ void render_game_over_screen(Canvas* canvas, GameState* state) {
     canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, "Press OK to restart");
 }
 
+void deactivate_all_enemies(GameState* state) {
+    for(int i = 0; i < ENEMIES_MAX; ++i) {
+        state->enemies[i].active = false;
+    }
+}
+
 void update_game_state(GameState* state) {
+    static int shoot_counter = 0; 
     for(int i = 0; i < PROJECTILES_MAX; ++i) {
         if(state->projectiles[i].active) {
             state->projectiles[i].position.y -= 2;
@@ -194,10 +308,29 @@ void update_game_state(GameState* state) {
         }
     }
 
+    if(++shoot_counter >= 30) {
+        enemy_shoot(state);
+        shoot_counter = 0;
+    }
+
     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(state->enemies[i].active) {
+            if(abs(state->enemies[i].position.x - state->player.position.x) < 10 && 
+               abs(state->enemies[i].position.y - state->player.position.y) < 10) {
+                deactivate_all_enemies(state);
+                state->game_over = true;
+                return;
+            }
+        }
+    }
+
+    for(int p = 0; p < ENEMY_PROJECTILES_MAX; ++p) {
+    if(state->enemy_projectiles[p].active) {
+        state->enemy_projectiles[p].position.y += 2;
+        if(state->enemy_projectiles[p].position.y > 128) { 
+            state->enemy_projectiles[p].active = false;
+            state->enemy_projectiles_count--;
+            }
         }
     }
     
@@ -205,15 +338,15 @@ void update_game_state(GameState* state) {
         initialize_enemies(state);
     }
 
-    update_enemy_positions(state); 
-    handle_collisions(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, state); 
+        render_game_over_screen(canvas, state);
     } else {
     canvas_clear(canvas);
     char score_text[30];
@@ -232,7 +365,17 @@ void render_callback(Canvas* const canvas, void* ctx) {
             canvas_draw_icon(canvas, state->enemies[i].position.x, state->enemies[i].position.y, &I_yap);
         }
     }
-}
+    for(int i = 0; i < BARRIERS_MAX; ++i) {
+        if(state->barriers[i].active) {
+            canvas_draw_rbox(canvas, state->barriers[i].position.x, state->barriers[i].position.y, 10, 3, 1);
+        }
+    }
+    for(int p = 0; p < ENEMY_PROJECTILES_MAX; ++p) {
+        if(state->enemy_projectiles[p].active) {
+            canvas_draw_rbox(canvas, state->enemy_projectiles[p].position.x - 1, state->enemy_projectiles[p].position.y - 4, 4, 8, 1);
+        }
+    }
+} 
 
 static void input_callback(InputEvent* input_event, void* ctx) {
     GameState* state = (GameState*)ctx;
@@ -247,11 +390,45 @@ static void input_callback(InputEvent* input_event, void* ctx) {
         if (input_event->key == InputKeyOk && input_event->type == InputTypeShort) {
             game_state_init(state);
             initialize_enemies(state);
-            state->game_over = false; 
+            state->game_over = false;
         }
     } else {
         handle_input(state, input_event);
     }
+    if (input_event->type == InputTypePress) {
+        switch(input_event->key) {
+            case InputKeyLeft:
+                leftKeyPressed = true;
+                break;
+            case InputKeyRight:
+                rightKeyPressed = true;
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (input_event->type == InputTypeRelease) {
+        switch(input_event->key) {
+            case InputKeyLeft:
+                leftKeyPressed = false;
+                break;
+            case InputKeyRight:
+                rightKeyPressed = false;
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+void update_player_position(GameState* state) {
+    if(leftKeyPressed) {
+        state->player.position.x = (state->player.position.x - 1) > 0 ? state->player.position.x - 1 : 0;
+    }
+    if(rightKeyPressed) {
+        state->player.position.x = (state->player.position.x + 1) < 124 ? state->player.position.x + 1 : 124;
+    }
 }
 
 int32_t yapinvaders_app(void) {
@@ -272,6 +449,7 @@ int32_t yapinvaders_app(void) {
                 game_state.waiting_for_restart = false;
             }
         } else {
+            update_player_position(&game_state);
             update_game_state(&game_state);
             view_port_update(view_port);
         }