Implement run mechanic and level progression with top-left HUD indicator
Run (B + direction): - player_logic.c: while holding B + direction with stamina >= 10, each tile takes 8 frames instead of 16 (move_progress += 2, LERP >>4 unchanged) and costs 10 stamina per tile. DAS_REPEAT_RUN=2 chains tiles fluidly. - Falls back silently to normal walk when stamina < 10. Level progression: - New global 'level' (starts at 1). title->game resets to 1; reaching the hatch (victory/Going Deeper) + START increments before engine_init (new maze); defeat + START resets to 1. - Top-left HUD 'L<n>' via 3 sprites (OAM 23-25) from new level.png asset (glyphs L, 0-9), generated by scripts/generate_level.py and converted with png2asset -keep_duplicate_tiles for predictable tile ordering. - VRAM base aligned to an EVEN index (8x16 hardware ignores tile LSB) and placed after the stamina load claim to avoid the shared BG tile block. - update_level_display() called every frame; hides during game over/title. Docs: README, doc/gameplay.md and the technical report updated.
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include "gameover.h"
|
||||
#include "next_level.h"
|
||||
#include "stamina.h"
|
||||
#include "level.h"
|
||||
#include "title_bg.h"
|
||||
|
||||
/**
|
||||
@@ -96,6 +97,8 @@ void engine_init(void) {
|
||||
set_sprite_data(player_TILE_COUNT + enemy_TILE_COUNT, gameover_TILE_COUNT, gameover_tiles);
|
||||
// Load stamina_tiles AFTER the background tiles to prevent VRAM overlap in the shared block (indices > 127)
|
||||
set_sprite_data(tiles_TILE_COUNT, stamina_TILE_COUNT * 2, stamina_tiles);
|
||||
// Load the level HUD glyph tiles right after stamina (blank, 'L', '0'..'9').
|
||||
set_sprite_data(LEVEL_SPRITE_BASE, level_TILE_COUNT, level_tiles);
|
||||
|
||||
// SPAWN DEL GIOCATORE
|
||||
player_lx = 1;
|
||||
@@ -143,11 +146,13 @@ void engine_init(void) {
|
||||
stamina_recharge_timer = 0;
|
||||
is_jumping = 0;
|
||||
is_moving = 0;
|
||||
is_running = 0;
|
||||
|
||||
// Richiama render.c per forzare un disegno iniziale della scena
|
||||
draw_map(player_lx, player_ly);
|
||||
update_camera();
|
||||
update_player_sprite();
|
||||
update_level_display(); // Mostra l'indicatore livello (top-left)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,6 +161,10 @@ void engine_init(void) {
|
||||
*/
|
||||
void engine_update(uint8_t keys, uint8_t prev_keys) {
|
||||
|
||||
// Indicatore livello: aggiornato ogni frame. Si nasconde da solo quando
|
||||
// `game_over` e' attivo (sconfitta/vittoria) grazie al check interno.
|
||||
update_level_display();
|
||||
|
||||
// --- GESTIONE STATO DI FINE GIOCO (Sconfitta o Vittoria) ---
|
||||
if (game_over) {
|
||||
if (game_over_timer > 0) {
|
||||
@@ -217,6 +226,12 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
|
||||
// Attende la pressione di START per riavviare
|
||||
if ((keys & J_START) && !(prev_keys & J_START)) {
|
||||
// Nasconde la grafica testuale e ricarica tutto l'engine
|
||||
// Vittoria (Going Deeper) -> livello successivo; Sconfitta -> nuova partita dal livello 1.
|
||||
if (game_over == 2) {
|
||||
level++;
|
||||
} else {
|
||||
level = 1;
|
||||
}
|
||||
move_metasprite(gameover_metasprites[0], player_TILE_COUNT + enemy_TILE_COUNT, 8, 0, 0);
|
||||
SHOW_SPRITES;
|
||||
engine_init();
|
||||
|
||||
@@ -18,6 +18,7 @@ uint8_t stairs_ly = 0;
|
||||
|
||||
uint8_t is_moving = 0;
|
||||
uint8_t is_jumping = 0;
|
||||
uint8_t is_running = 0;
|
||||
uint8_t move_progress = 0;
|
||||
int8_t start_lx, start_ly;
|
||||
int8_t target_lx, target_ly;
|
||||
@@ -27,6 +28,8 @@ int16_t target_px, target_py;
|
||||
uint8_t stamina = 100;
|
||||
uint8_t stamina_recharge_timer = 0;
|
||||
|
||||
uint8_t level = 1;
|
||||
|
||||
uint8_t enemy_lx = 0;
|
||||
uint8_t enemy_ly = 0;
|
||||
uint8_t enemy_is_moving = 0;
|
||||
|
||||
+6
-1
@@ -47,6 +47,7 @@ extern uint8_t player_dir; // 0=DR, 1=DL, 2=UL, 3=UR
|
||||
// Shared variables for interpolated movement (walking/jumping)
|
||||
extern uint8_t is_moving;
|
||||
extern uint8_t is_jumping;
|
||||
extern uint8_t is_running; // B+direction: step in 8 frames instead of 16, costs 10 stamina/tile
|
||||
extern uint8_t move_progress; // 0 to 16, tracks the sub-tile animation progress
|
||||
extern int8_t start_lx, start_ly;
|
||||
extern int8_t target_lx, target_ly;
|
||||
@@ -54,10 +55,14 @@ extern int16_t start_px, start_py;
|
||||
extern int16_t target_px, target_py;
|
||||
|
||||
// --- Stamina System ---
|
||||
// Stamina powers the jump mechanic. 100 = full. Recharges over time.
|
||||
// Stamina powers the jump/run mechanic. 100 = full. Recharges over time.
|
||||
extern uint8_t stamina;
|
||||
extern uint8_t stamina_recharge_timer;
|
||||
|
||||
// --- Level Progression ---
|
||||
// Current level (starts at 1, increments each time the hatch is reached).
|
||||
extern uint8_t level;
|
||||
|
||||
// --- Enemy State ---
|
||||
extern uint8_t enemy_lx;
|
||||
extern uint8_t enemy_ly;
|
||||
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
//AUTOGENERATED FILE FROM png2asset
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gbdk/platform.h>
|
||||
#include <gbdk/metasprites.h>
|
||||
|
||||
BANKREF(level)
|
||||
|
||||
const palette_color_t level_palettes[32] = {
|
||||
RGB8(224,248,207), RGB8(134,192,108), RGB8( 48,104, 80), RGB8( 7, 24, 33)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
,
|
||||
RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
|
||||
|
||||
};
|
||||
|
||||
const uint8_t level_tiles[352] = {
|
||||
0x40,0x00,0x40,0x00,
|
||||
0x40,0x00,0x40,0x00,
|
||||
0x40,0x00,0x40,0x00,
|
||||
0x7c,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x38,0x00,0x44,0x00,
|
||||
0x4c,0x00,0x54,0x00,
|
||||
0x64,0x00,0x44,0x00,
|
||||
0x38,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x10,0x00,0x30,0x00,
|
||||
0x10,0x00,0x10,0x00,
|
||||
0x10,0x00,0x10,0x00,
|
||||
0x38,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x38,0x00,0x44,0x00,
|
||||
0x04,0x00,0x08,0x00,
|
||||
0x10,0x00,0x20,0x00,
|
||||
0x7c,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x78,0x00,0x04,0x00,
|
||||
0x04,0x00,0x38,0x00,
|
||||
0x04,0x00,0x04,0x00,
|
||||
0x78,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x08,0x00,0x18,0x00,
|
||||
0x28,0x00,0x48,0x00,
|
||||
0x7c,0x00,0x08,0x00,
|
||||
0x08,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x7c,0x00,0x40,0x00,
|
||||
0x78,0x00,0x04,0x00,
|
||||
0x04,0x00,0x44,0x00,
|
||||
0x38,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x18,0x00,0x20,0x00,
|
||||
0x40,0x00,0x78,0x00,
|
||||
0x44,0x00,0x44,0x00,
|
||||
0x38,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x7c,0x00,0x04,0x00,
|
||||
0x08,0x00,0x10,0x00,
|
||||
0x20,0x00,0x40,0x00,
|
||||
0x40,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x38,0x00,0x44,0x00,
|
||||
0x44,0x00,0x38,0x00,
|
||||
0x44,0x00,0x44,0x00,
|
||||
0x38,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
|
||||
0x38,0x00,0x44,0x00,
|
||||
0x44,0x00,0x3c,0x00,
|
||||
0x04,0x00,0x08,0x00,
|
||||
0x30,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00
|
||||
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite0[] = {
|
||||
METASPR_ITEM(-8, -4, 0, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite1[] = {
|
||||
METASPR_ITEM(-8, -4, 2, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite2[] = {
|
||||
METASPR_ITEM(-8, -4, 4, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite3[] = {
|
||||
METASPR_ITEM(-8, -4, 6, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite4[] = {
|
||||
METASPR_ITEM(-8, -4, 8, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite5[] = {
|
||||
METASPR_ITEM(-8, -4, 10, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite6[] = {
|
||||
METASPR_ITEM(-8, -4, 12, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite7[] = {
|
||||
METASPR_ITEM(-8, -4, 14, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite8[] = {
|
||||
METASPR_ITEM(-8, -4, 16, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite9[] = {
|
||||
METASPR_ITEM(-8, -4, 18, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t level_metasprite10[] = {
|
||||
METASPR_ITEM(-8, -4, 20, S_PAL(0)),
|
||||
METASPR_TERM
|
||||
};
|
||||
|
||||
const metasprite_t* const level_metasprites[11] = {
|
||||
level_metasprite0, level_metasprite1, level_metasprite2, level_metasprite3, level_metasprite4, level_metasprite5, level_metasprite6, level_metasprite7, level_metasprite8, level_metasprite9, level_metasprite10
|
||||
};
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
//AUTOGENERATED FILE FROM png2asset
|
||||
#ifndef METASPRITE_level_H
|
||||
#define METASPRITE_level_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gbdk/platform.h>
|
||||
#include <gbdk/metasprites.h>
|
||||
|
||||
#define level_TILE_ORIGIN 0
|
||||
#define level_TILE_W 8
|
||||
#define level_TILE_H 16
|
||||
#define level_WIDTH 8
|
||||
#define level_HEIGHT 16
|
||||
#define level_TILE_COUNT 22
|
||||
#define level_PALETTE_COUNT 8
|
||||
#define level_COLORS_PER_PALETTE 4
|
||||
#define level_TOTAL_COLORS 32
|
||||
#define level_PIVOT_X 4
|
||||
#define level_PIVOT_Y 8
|
||||
#define level_PIVOT_W 8
|
||||
#define level_PIVOT_H 16
|
||||
extern const metasprite_t* const level_metasprites[11];
|
||||
|
||||
BANKREF_EXTERN(level)
|
||||
|
||||
extern const palette_color_t level_palettes[32];
|
||||
extern const uint8_t level_tiles[352];
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <gb/gb.h>
|
||||
#include "engine.h"
|
||||
#include "globals.h"
|
||||
|
||||
uint8_t app_state = 0; // 0 = title, 1 = game
|
||||
|
||||
@@ -20,6 +21,7 @@ void main(void) {
|
||||
title_update(keys, prev_keys);
|
||||
if ((keys & J_START) && !(prev_keys & J_START)) {
|
||||
app_state = 1;
|
||||
level = 1; // Nuova partita dal livello 1
|
||||
engine_init();
|
||||
}
|
||||
} else {
|
||||
|
||||
+26
-4
@@ -9,6 +9,9 @@ static uint8_t das_timer = 0;
|
||||
static uint8_t das_active = 0;
|
||||
#define DAS_DELAY 12
|
||||
#define DAS_REPEAT 6
|
||||
#define DAS_REPEAT_RUN 2 // DAS piu' rapido mentre si corre (il passo di corsa dura 8 frame)
|
||||
#define RUN_STAMINA_COST 10
|
||||
#define RUN_MIN_STAMINA 10
|
||||
|
||||
/**
|
||||
* Gestisce la logica di movimento del giocatore, i salti e le collisioni.
|
||||
@@ -23,6 +26,10 @@ static uint8_t das_active = 0;
|
||||
* 3. Meccanica del Salto: Premendo A+Direzione, il giocatore può saltare *esattamente* 2 celle
|
||||
* più in là. Il codice verifica se la cella intermedia (+1) è un ostacolo (0) e se
|
||||
* la cella di atterraggio (+2) è calpestabile. Consuma 60 di stamina per bilanciare il vantaggio tattico.
|
||||
* 4. Meccanica della Corsa: Premendo B+Direzione (con stamina >= 10) il giocatore si mette a correre:
|
||||
* il passo dura 8 frame invece di 16 (move_progress incrementato di 2) e consuma 10 stamina per tile.
|
||||
* Il DAS diventa piu' rapido (DAS_REPEAT_RUN) per incatenare i tile fluidamente. Se la stamina
|
||||
* non basta, ripiega silenziosamente su camminata normale senza consumo.
|
||||
*/
|
||||
void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
// --- Gestione della Stamina ---
|
||||
@@ -39,7 +46,9 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
// --- State Machine: Transizione Animazione ---
|
||||
// Se siamo nel mezzo di uno spostamento tra tile, calcoliamo i pixel interpolati
|
||||
if (is_moving) {
|
||||
move_progress++;
|
||||
// Corsa: il passo dura 8 frame (incremento 2) invece di 16 (incremento 1).
|
||||
// La formula LERP resta a punto fisso (>>4 == /16): move_progress raggiunge 16 in meta' tempo.
|
||||
move_progress += is_running ? 2 : 1;
|
||||
|
||||
// Interpolazione lineare (LERP) da start a target
|
||||
int16_t px = start_px + (((target_px - start_px) * (int16_t)move_progress) >> 4); // >> 4 equivale a / 16
|
||||
@@ -62,6 +71,7 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
if (move_progress == 16) {
|
||||
is_moving = 0;
|
||||
is_jumping = 0;
|
||||
is_running = 0;
|
||||
player_lx = target_lx;
|
||||
player_ly = target_ly;
|
||||
|
||||
@@ -91,9 +101,11 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
|
||||
// --- Lettura Controlli (Polling) con DAS ---
|
||||
uint8_t keys_pressed = keys & ~prev_keys; // Tasti premuti ESATTAMENTE in questo frame
|
||||
// La corsa (B tenuto + stamina) usa un DAS piu' corto per incatenare i tile fluidamente.
|
||||
uint8_t wants_run = (keys & J_B) && (stamina >= RUN_MIN_STAMINA);
|
||||
|
||||
if (keys_pressed) {
|
||||
das_timer = DAS_DELAY;
|
||||
das_timer = wants_run ? DAS_REPEAT_RUN : DAS_DELAY;
|
||||
das_active = 1;
|
||||
} else if (keys && das_active) {
|
||||
// Se si tiene premuto un tasto...
|
||||
@@ -102,7 +114,7 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
}
|
||||
// Se il timer arriva a 0, emuliamo una pressione ripetuta
|
||||
if (das_timer == 0 && !is_moving) {
|
||||
das_timer = DAS_REPEAT;
|
||||
das_timer = wants_run ? DAS_REPEAT_RUN : DAS_REPEAT;
|
||||
keys_pressed = keys;
|
||||
}
|
||||
} else {
|
||||
@@ -168,7 +180,7 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
// Se le condizioni di salto falliscono, aggiorna semplicemente il frame per far girare il personaggio
|
||||
update_player_sprite();
|
||||
}
|
||||
// 2. Movimento standard (Camminata)
|
||||
// 2. Movimento standard (Camminata o Corsa)
|
||||
else {
|
||||
int8_t new_lx = player_lx + move_lx;
|
||||
int8_t new_ly = player_ly + move_ly;
|
||||
@@ -178,6 +190,16 @@ void update_player_movement(uint8_t keys, uint8_t prev_keys) {
|
||||
if (maze[new_ly][new_lx] == 1 || maze[new_ly][new_lx] == 2) {
|
||||
is_moving = 1;
|
||||
move_progress = 0;
|
||||
// Corsa: B + direzione con stamina sufficiente. Il passo dura 8 frame
|
||||
// (vedi l'incremento di move_progress sopra) e costa 10 stamina per tile.
|
||||
// Se la stamina non basta, ripiega silenziosamente su camminata normale.
|
||||
if ((keys & J_B) && stamina >= RUN_MIN_STAMINA) {
|
||||
is_running = 1;
|
||||
stamina -= RUN_STAMINA_COST; // 10 stamina per tile (guardia sopra: stamina >= 10)
|
||||
update_stamina_display();
|
||||
} else {
|
||||
is_running = 0;
|
||||
}
|
||||
start_lx = player_lx;
|
||||
start_ly = player_ly;
|
||||
target_lx = new_lx;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "enemy.h"
|
||||
#include "gameover.h"
|
||||
#include "stamina.h"
|
||||
#include "level.h"
|
||||
#include "maze.h"
|
||||
|
||||
uint8_t get_tile_state(int8_t cx, int8_t cy, int8_t lx, int8_t ly) {
|
||||
@@ -77,6 +78,54 @@ void update_stamina_display(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna l'indicatore del livello (HUD in alto a sinistra).
|
||||
*
|
||||
* Sviluppo & Scelte Architetturali:
|
||||
* 1. Come la barra stamina, usiamo sprite hardware (ID 23..25) perche' il background
|
||||
* e' scrollato isometricamente e non e' adatto a un HUD fisso. Gli sprite sono
|
||||
* coordinate-schermo fisse, indipendenti dallo scroll.
|
||||
* 2. L'asset `level.png` contiene 12 glifi 8x16 (blank, 'L', '0'..'9'), caricati in
|
||||
* VRAM sprite subito dopo i tile della stamina (base = tiles_TILE_COUNT +
|
||||
* stamina_TILE_COUNT) per evitare sovrapposizioni con i tile del background
|
||||
* (stesso workaround del commit 93deb35 per la VRAM condivisa).
|
||||
* 3. Si mostrano 3 sprite: 'L', decine (blank se livello < 10), unita'.
|
||||
* Viene nascosto durante il game over (sconfitta/vittoria) e sul titolo.
|
||||
*/
|
||||
#define LEVEL_HUD_SPRITE 23 // primo OAM ID del livello (dopo stamina 18..22)
|
||||
|
||||
void update_level_display(void) {
|
||||
// Nascondi durante il game over (sconfitta o vittoria/Going Deeper).
|
||||
if (game_over) {
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
move_sprite(LEVEL_HUD_SPRITE + i, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t base = LEVEL_SPRITE_BASE;
|
||||
uint8_t tens = (level / 10) % 10;
|
||||
uint8_t ones = level % 10;
|
||||
|
||||
// Mappatura glifi in level.png (11 glifi, ognuno 8x16 = 2 tile, in ordine grazie
|
||||
// a -keep_duplicate_tiles). Indice di ordine i -> tile (base + 2*i):
|
||||
// 0 = 'L', 1..10 = '0'..'9'. Quindi la cifra d -> indice (1+d) -> tile base + (1+d)*2.
|
||||
set_sprite_tile(LEVEL_HUD_SPRITE + 0, base + 0 * 2); // 'L' (ordine 0)
|
||||
set_sprite_tile(LEVEL_HUD_SPRITE + 2, base + (1 + ones) * 2); // unita' (cifra ones)
|
||||
|
||||
// Posizionamento in alto a sinistra (offset hardware +8 x, +16 y).
|
||||
move_sprite(LEVEL_HUD_SPRITE + 0, 8, 16); // 'L' a screen x=0
|
||||
move_sprite(LEVEL_HUD_SPRITE + 2, 24, 16); // unita' a screen x=16
|
||||
|
||||
// Decine: mostrate solo se livello >= 10 (altrimenti sprite nascosto offscreen).
|
||||
if (level >= 10) {
|
||||
set_sprite_tile(LEVEL_HUD_SPRITE + 1, base + (1 + tens) * 2); // decine (cifra tens)
|
||||
move_sprite(LEVEL_HUD_SPRITE + 1, 16, 16); // screen x=8
|
||||
} else {
|
||||
move_sprite(LEVEL_HUD_SPRITE + 1, 0, 0); // nascondi decine
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disegna la porzione visibile del labirinto e applica il sistema "Fog of War".
|
||||
*
|
||||
|
||||
@@ -20,6 +20,15 @@ void update_camera(void);
|
||||
// Update stamina bar graphics
|
||||
void update_stamina_display(void);
|
||||
|
||||
// Update the level indicator (top-left HUD)
|
||||
void update_level_display(void);
|
||||
|
||||
// Base VRAM sprite tile index for the level HUD glyphs. Placed after the full stamina
|
||||
// load claim and aligned UP to an EVEN tile index: in 8x16 sprite mode the hardware
|
||||
// ignores the tile-index LSB, so the base must be even for base + 2*i to land on the
|
||||
// glyph's top tile. Disjoint from BG tile block and stamina (same rationale as 93deb35).
|
||||
#define LEVEL_SPRITE_BASE ((uint8_t)(((tiles_TILE_COUNT + (uint8_t)(stamina_TILE_COUNT * 2)) + 1) & (uint8_t)0xFEu))
|
||||
|
||||
// Update the player sprite (animation frames, jumping height offset)
|
||||
void update_player_sprite(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user