From 30111d6316ca91232e50aa738f1077ea5592cb6a Mon Sep 17 00:00:00 2001 From: Matteo Benedetto Date: Fri, 26 Jun 2026 12:49:08 +0200 Subject: [PATCH] Aggiungi salto rischioso: stamina < 60 = rischio caduta nel vuoto Ultima meccanica di gameplay: se hai meno di 60 stamina puoi comunque tentare il salto, ma rischi di cadere nell'abisso. La probabilita' di caduta e' proporzionale a quanto stamina ti manca da 60: - 60 stamina: 0% caduta (salto sicuro) - 30 stamina: 50% caduta - 0 stamina: 100% caduta Se cadi: il giocatore salta verso la cella intermedia (vuoto) invece di quella di atterraggio, poi cade velocemente verso il basso (animazione fall_offset, 2x pixel per frame) e game over con la schermata di morte. Differenza chiave: il salto sicuro atterra a distanza 2; il salto fallito si ferma a distanza 1 (sopra l'abisso) e cade. --- src/engine.c | 6 ++++++ src/globals.c | 1 + src/globals.h | 5 +++++ src/player_logic.c | 39 ++++++++++++++++++++++++++++++++++----- src/render.c | 4 ++++ 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/engine.c b/src/engine.c index 3cc8f5e..18a2149 100644 --- a/src/engine.c +++ b/src/engine.c @@ -76,6 +76,7 @@ void engine_init(void) { // Mostra le istruzioni SOLO la prima volta che si gioca il livello 1 if (level == 1 && !hint_shown_once) hint_active = 1; descend_offset = 0; // reset animazione discesa + fall_offset = 0; // reset animazione caduta // Carica il font testuale di sistema (IBM) font_init(); @@ -262,6 +263,11 @@ void engine_update(uint8_t keys, uint8_t prev_keys) { descend_offset++; update_player_sprite(); // aggiorna lo sprite che scende } + // Animazione di caduta nel vuoto (sconfitta per salto fallito) + if (game_over == 1 && fall_offset > 0 && fall_offset < 32) { + fall_offset++; + update_player_sprite(); // il giocatore cade + } // Quando scade il timer drammatico... if (game_over_timer == 0) { if (game_over == 1) { diff --git a/src/globals.c b/src/globals.c index a388325..97eae28 100644 --- a/src/globals.c +++ b/src/globals.c @@ -49,5 +49,6 @@ volatile uint8_t hint_active = 0; volatile uint8_t hint_displayed = 0; volatile uint8_t hint_shown_once = 0; volatile uint8_t descend_offset = 0; +volatile uint8_t fall_offset = 0; volatile uint8_t credits_active = 0; volatile uint8_t intro_active = 0; diff --git a/src/globals.h b/src/globals.h index a78b7a2..66372e5 100644 --- a/src/globals.h +++ b/src/globals.h @@ -90,6 +90,11 @@ extern volatile uint8_t hint_shown_once; // (aumenta di 1 ogni frame; a 32 il giocatore e' sparito del tutto) extern volatile uint8_t descend_offset; +// --- Animazione caduta nel vuoto --- +// fall_offset: 0 = normale, >0 = il giocatore sta cadendo nell'abisso +// (aumenta di 1 ogni frame; il giocatore scende e scompare) +extern volatile uint8_t fall_offset; + // --- Credits Screen --- // credits_active: 1 = mostra la schermata crediti (SELECT nel menu titolo) extern volatile uint8_t credits_active; diff --git a/src/player_logic.c b/src/player_logic.c index 0a174c3..dcf512a 100644 --- a/src/player_logic.c +++ b/src/player_logic.c @@ -76,6 +76,13 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) { player_lx = target_lx; player_ly = target_ly; + // Se stava cadendo nel vuoto, game over con animazione + if (fall_offset > 0) { + game_over = 1; // sconfitta + game_over_timer = 30; // timer per animazione di caduta + return; + } + // Snap matematico alla destinazione per prevenire derive dovute ad arrotondamenti int16_t final_px = (player_lx - player_ly) * 16 + 96; int16_t final_py = (player_lx + player_ly) * 8 + 16; @@ -150,16 +157,32 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) { // a) La cella intermedia DEVE essere un muro (maze == 0) // b) La cella di arrivo DEVE essere un pavimento o vittoria (maze == 1 o 2) // c) Devi avere abbastanza stamina (>= 60) - if (maze[player_ly + move_ly][player_lx + move_lx] == 0 && (maze[land_ly][land_lx] == 1 || maze[land_ly][land_lx] == 2) && stamina >= 60) { + if (maze[player_ly + move_ly][player_lx + move_lx] == 0 && (maze[land_ly][land_lx] == 1 || maze[land_ly][land_lx] == 2)) { + // Il salto costa 60 stamina. Se ne hai meno, puoi tentare comunque + // ma rischi di cadere nel vuoto. La probabilita' di caduta e' + // proporzionale a quanti punti ti mancano da 60. + // (es: 30 stamina -> 50% caduta; 0 stamina -> 100% caduta) + uint8_t fall_chance = 0; + if (stamina < 60) { + fall_chance = (uint8_t)(((60 - stamina) * 255) / 60); + } + uint8_t roll = (uint8_t)rand(); + uint8_t will_fall = (roll < fall_chance); + is_moving = 1; - is_jumping = 1; // Questo attiva l'arco parabolico in render.c + is_jumping = 1; move_progress = 0; - stamina -= 60; + // Consuma tutta la stamina disponibile (min 60 se possibile) + if (stamina >= 60) { + stamina -= 60; + } else { + stamina = 0; + } start_lx = player_lx; start_ly = player_ly; - target_lx = land_lx; - target_ly = land_ly; + target_lx = will_fall ? (player_lx + move_lx) : land_lx; + target_ly = will_fall ? (player_ly + move_ly) : land_ly; start_px = (start_lx - start_ly) * 16 + 96; start_py = (start_lx + start_ly) * 8 + 16; @@ -175,6 +198,12 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) { update_stamina_display(); update_player_sprite(); + + // Se cade nel vuoto, attiva l'animazione di caduta + if (will_fall) { + fall_offset = 1; + // Il giocatore cadra' nell'abisso: game_over dopo l'animazione + } return; } } diff --git a/src/render.c b/src/render.c index 765f609..d286a4a 100644 --- a/src/render.c +++ b/src/render.c @@ -300,6 +300,10 @@ void update_player_sprite(void) { if (descend_offset > 0) { y_offset = (uint8_t)(-(int8_t)(descend_offset >> 1)); // discesa graduale } + // Animazione caduta nel vuoto: il giocatore cade velocemente verso il basso + if (fall_offset > 0) { + y_offset = (uint8_t)(-(int8_t)(fall_offset << 1)); // caduta rapida (2x pixel) + } // move_metasprite e' fornito da png2asset e posiziona multipli sprite hardware insieme // Il giocatore e' sempre fisso al centro dello schermo (88, 88). E' il mondo (sfondo) a muoversi.