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.
This commit is contained in:
@@ -76,6 +76,7 @@ void engine_init(void) {
|
|||||||
// Mostra le istruzioni SOLO la prima volta che si gioca il livello 1
|
// Mostra le istruzioni SOLO la prima volta che si gioca il livello 1
|
||||||
if (level == 1 && !hint_shown_once) hint_active = 1;
|
if (level == 1 && !hint_shown_once) hint_active = 1;
|
||||||
descend_offset = 0; // reset animazione discesa
|
descend_offset = 0; // reset animazione discesa
|
||||||
|
fall_offset = 0; // reset animazione caduta
|
||||||
|
|
||||||
// Carica il font testuale di sistema (IBM)
|
// Carica il font testuale di sistema (IBM)
|
||||||
font_init();
|
font_init();
|
||||||
@@ -262,6 +263,11 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
|
|||||||
descend_offset++;
|
descend_offset++;
|
||||||
update_player_sprite(); // aggiorna lo sprite che scende
|
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...
|
// Quando scade il timer drammatico...
|
||||||
if (game_over_timer == 0) {
|
if (game_over_timer == 0) {
|
||||||
if (game_over == 1) {
|
if (game_over == 1) {
|
||||||
|
|||||||
@@ -49,5 +49,6 @@ volatile uint8_t hint_active = 0;
|
|||||||
volatile uint8_t hint_displayed = 0;
|
volatile uint8_t hint_displayed = 0;
|
||||||
volatile uint8_t hint_shown_once = 0;
|
volatile uint8_t hint_shown_once = 0;
|
||||||
volatile uint8_t descend_offset = 0;
|
volatile uint8_t descend_offset = 0;
|
||||||
|
volatile uint8_t fall_offset = 0;
|
||||||
volatile uint8_t credits_active = 0;
|
volatile uint8_t credits_active = 0;
|
||||||
volatile uint8_t intro_active = 0;
|
volatile uint8_t intro_active = 0;
|
||||||
|
|||||||
@@ -90,6 +90,11 @@ extern volatile uint8_t hint_shown_once;
|
|||||||
// (aumenta di 1 ogni frame; a 32 il giocatore e' sparito del tutto)
|
// (aumenta di 1 ogni frame; a 32 il giocatore e' sparito del tutto)
|
||||||
extern volatile uint8_t descend_offset;
|
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 Screen ---
|
||||||
// credits_active: 1 = mostra la schermata crediti (SELECT nel menu titolo)
|
// credits_active: 1 = mostra la schermata crediti (SELECT nel menu titolo)
|
||||||
extern volatile uint8_t credits_active;
|
extern volatile uint8_t credits_active;
|
||||||
|
|||||||
+33
-4
@@ -76,6 +76,13 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
|||||||
player_lx = target_lx;
|
player_lx = target_lx;
|
||||||
player_ly = target_ly;
|
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
|
// Snap matematico alla destinazione per prevenire derive dovute ad arrotondamenti
|
||||||
int16_t final_px = (player_lx - player_ly) * 16 + 96;
|
int16_t final_px = (player_lx - player_ly) * 16 + 96;
|
||||||
int16_t final_py = (player_lx + player_ly) * 8 + 16;
|
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)
|
// 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)
|
// b) La cella di arrivo DEVE essere un pavimento o vittoria (maze == 1 o 2)
|
||||||
// c) Devi avere abbastanza stamina (>= 60)
|
// 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_moving = 1;
|
||||||
is_jumping = 1; // Questo attiva l'arco parabolico in render.c
|
is_jumping = 1;
|
||||||
move_progress = 0;
|
move_progress = 0;
|
||||||
|
// Consuma tutta la stamina disponibile (min 60 se possibile)
|
||||||
|
if (stamina >= 60) {
|
||||||
stamina -= 60;
|
stamina -= 60;
|
||||||
|
} else {
|
||||||
|
stamina = 0;
|
||||||
|
}
|
||||||
|
|
||||||
start_lx = player_lx;
|
start_lx = player_lx;
|
||||||
start_ly = player_ly;
|
start_ly = player_ly;
|
||||||
target_lx = land_lx;
|
target_lx = will_fall ? (player_lx + move_lx) : land_lx;
|
||||||
target_ly = land_ly;
|
target_ly = will_fall ? (player_ly + move_ly) : land_ly;
|
||||||
|
|
||||||
start_px = (start_lx - start_ly) * 16 + 96;
|
start_px = (start_lx - start_ly) * 16 + 96;
|
||||||
start_py = (start_lx + start_ly) * 8 + 16;
|
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_stamina_display();
|
||||||
update_player_sprite();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,6 +300,10 @@ void update_player_sprite(void) {
|
|||||||
if (descend_offset > 0) {
|
if (descend_offset > 0) {
|
||||||
y_offset = (uint8_t)(-(int8_t)(descend_offset >> 1)); // discesa graduale
|
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
|
// 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.
|
// Il giocatore e' sempre fisso al centro dello schermo (88, 88). E' il mondo (sfondo) a muoversi.
|
||||||
|
|||||||
Reference in New Issue
Block a user