Fix game over restart logic and update README

This commit is contained in:
2026-06-23 00:09:42 +02:00
parent e07e8c6e56
commit c0c217f4f6
25 changed files with 1355 additions and 47 deletions
+13 -3
View File
@@ -2,15 +2,25 @@ GBDK_HOME = /home/enne2/.local/gbdk
LCC = $(GBDK_HOME)/bin/lcc LCC = $(GBDK_HOME)/bin/lcc
PNG2ASSET = $(GBDK_HOME)/bin/png2asset PNG2ASSET = $(GBDK_HOME)/bin/png2asset
all: hello_iso.gb all: hello_iso.gb test_gameover.gb
assets: generate_assets.py assets: generate_assets.py
python3 generate_assets.py python3 generate_assets.py
$(PNG2ASSET) tiles.png -c tiles.c -map -bpp 2 -noflip -keep_palette_order $(PNG2ASSET) tiles.png -c tiles.c -map -bpp 2 -noflip -keep_palette_order
$(PNG2ASSET) player.png -c player.c -sw 16 -sh 16 -bpp 2 -noflip -keep_palette_order $(PNG2ASSET) player.png -c player.c -sw 16 -sh 16 -bpp 2 -noflip -keep_palette_order
$(PNG2ASSET) gameover.png -c gameover.c -bpp 2 -noflip -keep_palette_order
$(PNG2ASSET) stamina.png -c stamina.c -bpp 2 -noflip -keep_palette_order
$(PNG2ASSET) title_bg.png -c title_bg.c -map -bpp 2 -noflip -keep_palette_order
hello_iso.gb: assets main.c engine.c hello_iso.gb: assets main.c engine.c
$(LCC) -Wa-l -Wl-m -Wl-j -o hello_iso.gb main.c engine.c tiles.c player.c $(LCC) -Wa-l -Wl-m -Wl-j -o hello_iso.gb main.c engine.c tiles.c player.c gameover.c stamina.c title_bg.c
test_gameover.gb: assets test_gameover_render.c
$(LCC) -Wa-l -Wl-m -Wl-j -o test_gameover.gb test_gameover_render.c player.c gameover.c stamina.c
clean: clean:
rm -f *.o *.lst *.map *.gb *.ihx *.sym *.cdb *.adb *.asm rm -f *.o *.lst *.map *.gb *.ihx *.sym *.cdb *.adb *.asm gameover.c gameover.h gameover.png player.png tiles.png player.c player.h tiles.c tiles.h test_gameover_render.o player.o gameover.o stamina.c stamina.h stamina.png stamina.o title_bg.c title_bg.h title_bg.o
+14 -3
View File
@@ -12,9 +12,20 @@ Un motore isometrico sperimentale per Game Boy (DMG/CGB) scritto in C con **GBDK
* **Delayed Auto Shift (DAS)**: Controlli reattivi e confortevoli con delay iniziale di 12 frame e ripetizione ogni 6 frame per il movimento continuo tenendo premuto il D-Pad. * **Delayed Auto Shift (DAS)**: Controlli reattivi e confortevoli con delay iniziale di 12 frame e ripetizione ogni 6 frame per il movimento continuo tenendo premuto il D-Pad.
* **Autotiling Intelligente**: Calcolo dei vicini (maschera a 4 bit) per selezionare automaticamente il bordo e gli angoli di ciascuna tessera del pavimento (16 varianti per ognuno dei 2 stili di pavimento alternati a scacchiera). * **Autotiling Intelligente**: Calcolo dei vicini (maschera a 4 bit) per selezionare automaticamente il bordo e gli angoli di ciascuna tessera del pavimento (16 varianti per ognuno dei 2 stili di pavimento alternati a scacchiera).
* **Pipeline di Asset Ottimizzata**: Generazione procedurale di tile e sprite da script Python (`generate_assets.py`) e compilazione in C tramite `png2asset`. * **Pipeline di Asset Ottimizzata**: Generazione procedurale di tile e sprite da script Python (`generate_assets.py`) e compilazione in C tramite `png2asset`.
* **Test Headless & Computer Vision**: - Animazione completa dei movimenti del giocatore.
* Simulazione dell'input e verifica dello stato direttamente leggendo i registri WRAM del Game Boy in esecuzione. - Transizione al Game Over alla collisione.
* Rilevamento di glitch grafici (pixel neri o spazi vuoti non allineati) sulla ROM renderizzata usando filtri morfologici di **OpenCV**. - Menu Iniziale con copertina d'arte a 2-bit nativa per hardware Game Boy.
### Soundtrack
Il gioco implementa la musica generata proceduralmente manipolando i registri audio hardware del Game Boy in `engine.c`.
1. **Title Theme:** Una solenne e misteriosa melodia composta da 32 battute basata sugli accordi La minore, Sol, Fa e Mi, che accompagna la schermata d'avvio a schermo intero.
2. **Gameplay Theme:** Un battito ritmico ansioso che accelera progressivamente l'intensità all'inseguimento del fantasma, aumentando la pressione psicologica sul giocatore.
3. **Game Over Theme:** Un concerto tragico polifonico di 128 note con percussioni sinfoniche, basso virtuoso e drammatica discesa melodica, per sottolineare la sconfitta del giocatore.
## Compilazione
Assicurati di aver installato [GBDK-2020](https://github.com/gbdk-2020/gbdk-2020).
--- ---
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 991 KiB

+488 -18
View File
@@ -1,4 +1,5 @@
#include <gb/gb.h> #include <gb/gb.h>
#include <gbdk/font.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <rand.h> #include <rand.h>
@@ -7,6 +8,254 @@
// Generated by png2asset // Generated by png2asset
#include "tiles.h" #include "tiles.h"
#include "player.h" #include "player.h"
#include "gameover.h"
#include "stamina.h"
#include "title_bg.h"
// Music variables
static volatile uint8_t music_timer = 0;
static volatile uint8_t music_step = 0;
volatile uint8_t game_over = 0;
volatile uint8_t game_over_timer = 0;
// Game Over creepy melody variables
static volatile uint8_t gameover_music_timer = 0;
static volatile uint8_t gameover_music_step = 0;
// Notes frequencies
#define R 0
#define N_E2 458
#define N_F2 547
#define N_G2 742
#define N_A2 857
#define N_AS2 907
#define N_B2 961
#define N_C3 1046
#define N_CS3 1103
#define N_D3 1155
#define N_E3 1253
#define N_F3 1298
#define N_FS3 1340
#define N_G3 1380
#define N_GS3 1417
#define N_A3 1453
#define N_AS3 1486
#define N_B3 1517
#define N_C4 1547
#define N_CS4 1575
#define N_D4 1602
#define N_E4 1651
#define N_F4 1673
#define N_FS4 1694
#define N_G4 1714
#define N_GS4 1732
#define N_A4 1751
#define N_AS4 1767
#define N_B4 1783
#define N_C5 1798
#define N_CS5 1812
#define N_D5 1825
#define N_E5 1849
#define N_F5 1860
#define N_FS5 1871
#define N_G5 1881
#define N_GS5 1890
#define N_A5 1899
const uint16_t ch1_seq[128] = {
// 1 Dm
N_D3, N_A3, N_D4, N_A3, N_D3, N_A3, N_D4, N_A3,
// 2 A/C#
N_CS3, N_A3, N_CS4, N_A3, N_CS3, N_A3, N_CS4, N_A3,
// 3 F/C
N_C3, N_A3, N_C4, N_A3, N_C3, N_A3, N_C4, N_A3,
// 4 G/B
N_B2, N_G3, N_B3, N_G3, N_B2, N_G3, N_B3, N_G3,
// 5 Bb
N_AS2, N_F3, N_AS3, N_F3, N_AS2, N_F3, N_AS3, N_F3,
// 6 F/A
N_A2, N_F3, N_A3, N_F3, N_A2, N_F3, N_A3, N_F3,
// 7 Gm
N_G2, N_D3, N_G3, N_D3, N_G2, N_D3, N_G3, N_D3,
// 8 A7
N_A2, N_E3, N_A3, N_CS4, N_A2, N_E3, N_A3, N_CS4,
// 9 Dm (intensifies: higher arpeggio)
N_D3, N_D4, N_F4, N_A4, N_D3, N_D4, N_F4, N_A4,
// 10 A/C#
N_CS3, N_CS4, N_E4, N_A4, N_CS3, N_CS4, N_E4, N_A4,
// 11 F/C
N_C3, N_C4, N_F4, N_A4, N_C3, N_C4, N_F4, N_A4,
// 12 G/B
N_B2, N_B3, N_D4, N_G4, N_B2, N_B3, N_D4, N_G4,
// 13 Bb
N_AS2, N_AS3, N_D4, N_F4, N_AS2, N_AS3, N_D4, N_F4,
// 14 F/A
N_A2, N_A3, N_C4, N_F4, N_A2, N_A3, N_C4, N_F4,
// 15 Gm
N_G2, N_G3, N_AS3, N_D4, N_G2, N_G3, N_AS3, N_D4,
// 16 A7 -> Dm resolution
N_A2, N_A3, N_CS4, N_E4, N_A2, R, N_D3, R
};
const uint16_t ch2_seq[128] = {
// 1 Dm
N_F4, R, R, R, N_E4, R, R, R,
// 2 A/C#
N_E4, R, R, R, N_D4, R, R, R,
// 3 F/C
N_C4, R, R, R, N_D4, R, N_E4, R,
// 4 G/B
N_D4, R, R, R, N_F4, R, R, R,
// 5 Bb
N_D4, R, R, R, N_C4, R, R, R,
// 6 F/A
N_C4, R, R, R, N_AS3, R, R, R,
// 7 Gm
N_AS3, R, N_A3, N_AS3, N_C4, R, N_AS3, R,
// 8 A7
N_A3, R, R, R, R, R, R, R,
// 9 Dm
N_A4, R, R, R, N_G4, R, N_F4, N_E4,
// 10 A/C#
N_G4, R, R, R, N_F4, R, N_E4, N_D4,
// 11 F/C
N_F4, R, R, R, N_E4, R, N_C4, R,
// 12 G/B
N_D4, R, R, R, N_G4, R, R, R,
// 13 Bb
N_F4, R, R, R, N_E4, R, N_D4, N_CS4,
// 14 F/A
N_E4, R, R, R, N_D4, R, N_C4, N_B3,
// 15 Gm
N_D4, R, R, R, N_C4, R, N_AS3, R,
// 16 A7 -> Dm resolution
N_A3, R, R, R, R, R, N_D4, R
};
// Eerie pulse note frequencies (96-note sequence for normal gameplay)
const uint16_t eerie_reg_vals[] = {
// Pattern 1 (A minor)
1453, 1546, 1650, 1733, 1754, 1733, 1650, 1546,
1453, 1546, 1650, 1733, 1754, 1733, 1650, 1546,
1453, 1546, 1650, 1733, 1754, 1733, 1650, 1546,
1453, 1546, 1650, 1733, 1754, 1733, 1650, 1546,
// Pattern 2 (D minor)
1303, 1453, 1546, 1650, 1678, 1650, 1546, 1453,
1303, 1453, 1546, 1650, 1678, 1650, 1546, 1453,
1303, 1453, 1546, 1650, 1678, 1650, 1546, 1453,
1303, 1453, 1546, 1650, 1678, 1650, 1546, 1453,
// Pattern 3 (E7 tension)
1369, 1497, 1589, 1709, 1733, 1709, 1589, 1497,
1369, 1497, 1589, 1709, 1733, 1709, 1589, 1497,
1369, 1497, 1589, 1709, 1733, 1709, 1589, 1497,
1369, 1497, 1589, 1709, 1733, 1709, 1589, 1497
};
// Title Music Variables
static volatile uint8_t title_music_timer = 0;
static volatile uint8_t title_music_step = 0;
const uint16_t title_melody[32] = {
N_A2, N_E3, N_A3, N_E3, N_C4, N_A3, N_E3, N_A2, // Am
N_G2, N_D3, N_G3, N_D3, N_B3, N_G3, N_D3, N_G2, // G
N_F2, N_C3, N_F3, N_C3, N_A3, N_F3, N_C3, N_F2, // F
N_E2, N_B2, N_E3, N_B2, N_GS3, N_E3, N_B2, N_E2 // E
};
static void play_note(uint16_t reg_val) {
NR21_REG = 0x80; // 50% duty cycle
NR22_REG = 0x73; // volume 7, fade envelope
NR23_REG = reg_val & 0xFF;
NR24_REG = (reg_val >> 8) | 0x80; // trigger note
}
static void play_gameover_step(uint8_t step) {
if (step < 128) {
uint16_t n1 = ch1_seq[step];
if (n1 != R) {
NR10_REG = 0x00; // No sweep
NR11_REG = 0x80; // 50% duty
NR12_REG = 0x73; // volume 7, fast fade for arpeggio pluck
NR13_REG = n1 & 0xFF;
NR14_REG = (n1 >> 8) | 0x80;
}
uint16_t n2 = ch2_seq[step];
if (n2 != R) {
NR21_REG = 0x80; // 50% duty
NR22_REG = 0xA7; // volume 10, long fade for melody sustain
NR23_REG = n2 & 0xFF;
NR24_REG = (n2 >> 8) | 0x80;
}
// Add dramatic percussion on the first beat of each chord (every 8 steps)
if (step % 8 == 0) {
NR41_REG = 0x01;
NR42_REG = 0xB2; // Volume 11, quick fade
// step < 64 gets a lower tympani, step >= 64 gets a crash
if (step < 64) {
NR43_REG = 0x68; // Low thud
} else {
NR43_REG = 0x42; // Crash
}
NR44_REG = 0x80;
}
}
}
static void play_music_tick(void) {
if (app_state == 0) {
title_music_timer++;
if (title_music_timer >= 30) { // 30 frames per note
title_music_timer = 0;
uint16_t n = title_melody[title_music_step];
NR10_REG = 0;
NR11_REG = 0x80;
NR12_REG = 0x63; // soft fade
NR13_REG = n & 0xFF;
NR14_REG = (n >> 8) | 0x80;
// Add a slow bass note every 4 steps
if (title_music_step % 4 == 0) {
NR21_REG = 0x80;
NR22_REG = 0x77;
uint16_t bn = n / 2; // Octave lower
NR23_REG = bn & 0xFF;
NR24_REG = (bn >> 8) | 0x80;
}
title_music_step++;
if (title_music_step >= 32) title_music_step = 0;
}
return;
}
if (game_over) {
if (game_over_timer == 0) {
gameover_music_timer++;
if (gameover_music_timer >= 10) { // 10 frames per note (~6 notes/sec)
gameover_music_timer = 0;
if (gameover_music_step < 128) {
play_gameover_step(gameover_music_step);
gameover_music_step++;
}
}
}
return;
}
music_timer++;
if (music_timer >= 20) {
music_timer = 0;
play_note(eerie_reg_vals[music_step]);
music_step++;
if (music_step >= 96) {
music_step = 0;
}
}
}
#define MAP_SIZE 7 #define MAP_SIZE 7
@@ -21,6 +270,9 @@ uint8_t scroll_y = 0;
// Movement transition variables // Movement transition variables
uint8_t is_moving = 0; uint8_t is_moving = 0;
uint8_t is_jumping = 0;
uint8_t stamina = 100;
uint8_t stamina_recharge_timer = 0;
uint8_t move_progress = 0; uint8_t move_progress = 0;
int8_t start_lx, start_ly; int8_t start_lx, start_ly;
int8_t target_lx, target_ly; int8_t target_lx, target_ly;
@@ -43,8 +295,8 @@ int8_t enemy_target_lx, enemy_target_ly;
int16_t enemy_start_px, enemy_start_py; int16_t enemy_start_px, enemy_start_py;
int16_t enemy_target_px, enemy_target_py; int16_t enemy_target_px, enemy_target_py;
uint8_t enemy_cooldown = 0; uint8_t enemy_cooldown = 0;
uint8_t game_over = 0;
uint8_t game_over_timer = 0;
const metasprite_t enemy_metasprite[] = { const metasprite_t enemy_metasprite[] = {
METASPR_ITEM(-8, -8, 0, S_PALETTE), METASPR_ITEM(-8, -8, 0, S_PALETTE),
@@ -132,6 +384,44 @@ static void generate_maze(void) {
} }
} }
static void update_stamina_display(void) {
if (game_over) {
// Hide the 5 stamina bar sprites when game is over
for (uint8_t i = 0; i < 5; i++) {
move_sprite(18 + i, 0, 0);
}
return;
}
// Position 5 sprites at top-right of the screen (fixed, completely ignores scroll)
move_sprite(18, (uint8_t)(112 + 8), 16);
move_sprite(19, (uint8_t)(120 + 8), 16);
move_sprite(20, (uint8_t)(128 + 8), 16);
move_sprite(21, (uint8_t)(136 + 8), 16);
move_sprite(22, (uint8_t)(144 + 8), 16);
uint16_t temp = (uint16_t)stamina * 40;
uint8_t num_pixels = temp / 100;
uint8_t base_tile = player_TILE_COUNT + gameover_TILE_COUNT; // 44
for (uint8_t i = 0; i < 5; i++) {
uint8_t tile_idx;
if (i == 0) {
tile_idx = (num_pixels >= 8) ? 11 : 9; // Left Cap full (11) or empty (9)
} else if (i == 4) {
tile_idx = (num_pixels >= 40) ? 12 : 10; // Right Cap full (12) or empty (10)
} else {
int8_t seg_px = (int8_t)num_pixels - (i * 8);
if (seg_px < 0) seg_px = 0;
if (seg_px > 8) seg_px = 8;
tile_idx = seg_px; // middle segments (0..8 px)
}
set_sprite_tile(18 + i, base_tile + tile_idx * 2);
}
}
static void draw_map(uint8_t center_x, uint8_t center_y) { static void draw_map(uint8_t center_x, uint8_t center_y) {
// Fill entire map with tile index 0 (completely black empty tile) // Fill entire map with tile index 0 (completely black empty tile)
memset(map_buffer, 0, sizeof(map_buffer)); memset(map_buffer, 0, sizeof(map_buffer));
@@ -198,7 +488,9 @@ static void draw_map(uint8_t center_x, uint8_t center_y) {
} }
} }
set_bkg_tiles(0, 0, 32, 32, map_buffer); update_stamina_display();
// Optimize: only write rows 2 to 17 (16 rows total) which contain the active isometric map, avoiding full 1024-byte copy lags
set_bkg_tiles(0, 2, 32, 16, &map_buffer[2 * 32]);
} }
static void update_camera(void) { static void update_camera(void) {
@@ -214,12 +506,66 @@ static void update_camera(void) {
static void update_player_sprite(void) { static void update_player_sprite(void) {
uint8_t frame_offset = is_moving ? ((move_progress >> 2) & 1) : 0; uint8_t frame_offset = is_moving ? ((move_progress >> 2) & 1) : 0;
move_metasprite(player_metasprites[player_dir * 2 + frame_offset], 0, 0, 88, 88); uint8_t y_offset = 0;
if (is_jumping) {
// Parabolic arc for the jump height: peak is 16 pixels at frame 8
y_offset = (move_progress * (16 - move_progress)) >> 2;
}
move_metasprite(player_metasprites[player_dir * 2 + frame_offset], 0, 0, 88, 88 - y_offset);
}
void title_init(void) {
// Hide all sprites
for (uint8_t i = 0; i < 40; i++) move_sprite(i, 0, 0);
// Load title background tiles
set_bkg_data(0, title_bg_TILE_COUNT, title_bg_tiles);
// Draw title map
set_bkg_tiles(0, 0, title_bg_WIDTH / 8, title_bg_HEIGHT / 8, title_bg_map);
// Set standard palette
BGP_REG = 0xE4;
// Center screen
move_bkg(0, 0);
// Initialize sound registers
NR52_REG = 0x80; // Turn on sound
NR50_REG = 0x77; // Max master volume
NR51_REG = 0xFF; // Enable all sound channels
// Start title music
title_music_timer = 0;
title_music_step = 0;
remove_VBL(play_music_tick);
add_VBL(play_music_tick);
}
void title_update(uint8_t keys, uint8_t prev_keys) {
// Only handling music and waiting for start, which is handled in main.c and play_music_tick
} }
void engine_init(void) { void engine_init(void) {
SPRITES_8x16; SPRITES_8x16;
// Initialize sound registers
NR52_REG = 0x80; // Turn on sound
NR50_REG = 0x77; // Max master volume
NR51_REG = 0xFF; // Enable all sound channels
// Load native GBDK IBM font (loads starting at VRAM index 0x80)
font_init();
font_t ibm_font = font_load(font_ibm);
font_set(ibm_font);
// Reset music step counters
music_timer = 0;
music_step = 0;
gameover_music_timer = 0;
gameover_music_step = 0;
remove_VBL(play_music_tick);
add_VBL(play_music_tick);
// Seed random number generator with hardware divider register // Seed random number generator with hardware divider register
initrand(DIV_REG); initrand(DIV_REG);
@@ -238,18 +584,38 @@ void engine_init(void) {
// Load tiles // Load tiles
set_bkg_data(0, tiles_TILE_COUNT, tiles_tiles); set_bkg_data(0, tiles_TILE_COUNT, tiles_tiles);
set_sprite_data(0, player_TILE_COUNT, player_tiles); set_sprite_data(0, player_TILE_COUNT, player_tiles);
set_sprite_data(player_TILE_COUNT, gameover_TILE_COUNT, gameover_tiles);
set_sprite_data(player_TILE_COUNT + gameover_TILE_COUNT, stamina_TILE_COUNT * 2, stamina_tiles);
// Spawn enemy at a random path tile sufficiently far from the player player_lx = 1;
player_ly = 1;
// Safety check: if (1,1) is somehow a wall, scan the maze and start at the first path tile
if (maze[player_ly][player_lx] == 0) {
uint8_t found = 0;
for (uint8_t y = 1; y < MAP_SIZE - 1; y++) {
for (uint8_t x = 1; x < MAP_SIZE - 1; x++) {
if (maze[y][x] == 1) {
player_lx = x;
player_ly = y;
found = 1;
break;
}
}
if (found) break;
}
}
// Spawn enemy at a random path tile sufficiently far from the player (Chebyshev distance >= 3)
while (1) { while (1) {
uint8_t rx = rand() % MAP_SIZE; uint8_t rx = rand() % MAP_SIZE;
uint8_t ry = rand() % MAP_SIZE; uint8_t ry = rand() % MAP_SIZE;
if (maze[ry][rx] == 1) { if (maze[ry][rx] == 1) {
// Distance (Manhattan) to player start (1, 1) int8_t dx = (int8_t)rx - (int8_t)player_lx;
int8_t dx = rx - 1; int8_t dy = (int8_t)ry - (int8_t)player_ly;
int8_t dy = ry - 1;
if (dx < 0) dx = -dx; if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy; if (dy < 0) dy = -dy;
if ((dx + dy) >= 5) { int8_t dist = (dx > dy) ? dx : dy;
if (dist >= 3) {
enemy_lx = rx; enemy_lx = rx;
enemy_ly = ry; enemy_ly = ry;
break; break;
@@ -257,8 +623,11 @@ void engine_init(void) {
} }
} }
enemy_is_moving = 0; enemy_is_moving = 0;
enemy_cooldown = 30; enemy_cooldown = 60;
game_over = 0; game_over = 0;
stamina = 100;
stamina_recharge_timer = 0;
is_jumping = 0;
draw_map(player_lx, player_ly); draw_map(player_lx, player_ly);
update_camera(); update_camera();
@@ -270,11 +639,65 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
if (game_over_timer > 0) { if (game_over_timer > 0) {
game_over_timer--; game_over_timer--;
if (game_over_timer == 0) { if (game_over_timer == 0) {
BGP_REG = 0xFF; // Set screen to all black to signify Game Over // Clear map_buffer to 0 (completely black/empty)
memset(map_buffer, 0, sizeof(map_buffer));
set_bkg_tiles(0, 0, 32, 32, map_buffer);
// Initialize gameover music step variables
gameover_music_timer = 45;
gameover_music_step = 0;
// Play a sad defeat melody / note on Channel 2
NR21_REG = 0x80;
NR22_REG = 0xF3; // volume 15, fade
NR23_REG = 0x2C; // low frequency
NR24_REG = 0x84; // trigger note
}
} else {
// Render the "GAME OVER" metasprite centered horizontally (88, due to sprite X-offset) and below player (120)
move_metasprite(gameover_metasprites[0], player_TILE_COUNT, 8, 88, 120);
// Keep the player sprite visible at center screen (88, 88)
update_player_sprite();
// Render enemy sprite at its final screen coordinate relative to camera scroll
int16_t enemy_px = (enemy_lx - enemy_ly) * 16 + 96;
int16_t enemy_py = (enemy_lx + enemy_ly) * 8 + 16;
int16_t enemy_screen_x = ((enemy_px - scroll_x) & 255) + 24;
int16_t enemy_screen_y = ((enemy_py - scroll_y) & 255) + 16;
int8_t edx = (int8_t)player_lx - (int8_t)enemy_lx;
int8_t edy = (int8_t)player_ly - (int8_t)enemy_ly;
if (edx < 0) edx = -edx;
if (edy < 0) edy = -edy;
uint8_t ep_dist = (edx > edy) ? edx : edy;
if (ep_dist <= 2 && enemy_screen_x >= -8 && enemy_screen_x <= 168 && enemy_screen_y >= -8 && enemy_screen_y <= 152) {
move_metasprite(enemy_metasprite, 0, 4, enemy_screen_x, enemy_screen_y);
} else {
move_metasprite(enemy_metasprite, 0, 4, 0, 0);
}
// Check for restart via J_START
if ((keys & J_START) && !(prev_keys & J_START)) {
// Hide game over metasprite by moving offscreen
move_metasprite(gameover_metasprites[0], player_TILE_COUNT, 8, 0, 0);
engine_init();
} }
} }
return; return;
} }
// Stamina recharge: 1 point per second (every 60 frames)
stamina_recharge_timer++;
if (stamina_recharge_timer >= 60) {
stamina_recharge_timer = 0;
if (stamina < 100) {
stamina++;
update_stamina_display();
}
}
if (is_moving) { if (is_moving) {
move_progress++; move_progress++;
@@ -297,6 +720,7 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
if (move_progress == 16) { if (move_progress == 16) {
is_moving = 0; is_moving = 0;
is_jumping = 0;
player_lx = target_lx; player_lx = target_lx;
player_ly = target_ly; player_ly = target_ly;
@@ -322,7 +746,7 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
enemy_is_moving = 0; enemy_is_moving = 0;
enemy_lx = enemy_target_lx; enemy_lx = enemy_target_lx;
enemy_ly = enemy_target_ly; enemy_ly = enemy_target_ly;
enemy_cooldown = 24; // Delay between steps to make the enemy move slower than the player enemy_cooldown = 60; // Delay between steps to make the enemy move slower than the player
} }
} }
@@ -340,7 +764,7 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
int8_t abs_dy = (dy < 0) ? -dy : dy; int8_t abs_dy = (dy < 0) ? -dy : dy;
int8_t dist = (abs_dx > abs_dy) ? abs_dx : abs_dy; int8_t dist = (abs_dx > abs_dy) ? abs_dx : abs_dy;
if (dist <= 4) { if (dist <= 2) {
int8_t best_nx = enemy_lx; int8_t best_nx = enemy_lx;
int8_t best_ny = enemy_ly; int8_t best_ny = enemy_ly;
// Initialize with current squared distance so we only move if we get strictly closer // Initialize with current squared distance so we only move if we get strictly closer
@@ -413,8 +837,8 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
if (edy < 0) edy = -edy; if (edy < 0) edy = -edy;
uint8_t ep_dist = (edx > edy) ? edx : edy; uint8_t ep_dist = (edx > edy) ? edx : edy;
// Render only if within range (<= 3) to let player see the ghost coming from the edge of fog of war // Render only if within range (<= 2) to let player see the ghost when visible in fog of war
if (ep_dist <= 3 && enemy_screen_x >= -8 && enemy_screen_x <= 168 && enemy_screen_y >= -8 && enemy_screen_y <= 152) { if (ep_dist <= 2 && enemy_screen_x >= -8 && enemy_screen_x <= 168 && enemy_screen_y >= -8 && enemy_screen_y <= 152) {
move_metasprite(enemy_metasprite, 0, 4, enemy_screen_x, enemy_screen_y); // Sprite index offset 4 move_metasprite(enemy_metasprite, 0, 4, enemy_screen_x, enemy_screen_y); // Sprite index offset 4
} else { } else {
move_metasprite(enemy_metasprite, 0, 4, 0, 0); // Hide offscreen move_metasprite(enemy_metasprite, 0, 4, 0, 0); // Hide offscreen
@@ -432,7 +856,14 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
if (dx_collision < 12 && dy_collision < 6) { if (dx_collision < 12 && dy_collision < 6) {
game_over = 1; game_over = 1;
game_over_timer = 30; // 30 frames delay (0.5 seconds) to allow player to see the overlap game_over_timer = 45; // 45 frames delay
update_stamina_display(); // Hide stamina immediately
// Play defeat sweep SFX on Channel 1 (slide pitch down)
NR10_REG = 0x1E; // sweep register: shift down
NR11_REG = 0x10; // 25% duty cycle
NR12_REG = 0xF3; // initial volume 15, envelope decrease
NR13_REG = 0x00; // low frequency bits
NR14_REG = 0xC6; // trigger note, frequency high bits
} }
uint8_t keys_pressed = keys & ~prev_keys; uint8_t keys_pressed = keys & ~prev_keys;
@@ -470,6 +901,46 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
} }
if (move_lx != 0 || move_ly != 0) { if (move_lx != 0 || move_ly != 0) {
// If J_A is held down, attempt to jump over a wall
if (keys & J_A) {
int8_t land_lx = player_lx + move_lx * 2;
int8_t land_ly = player_ly + move_ly * 2;
// Bounds check for intermediate and landing tiles
if (land_lx >= 0 && land_lx < MAP_SIZE && land_ly >= 0 && land_ly < MAP_SIZE) {
// intermediate tile must be a wall (0), landing tile must be a path (1), and we need >= 60 stamina
if (maze[player_ly + move_ly][player_lx + move_lx] == 0 && maze[land_ly][land_lx] == 1 && stamina >= 60) {
is_moving = 1;
is_jumping = 1;
move_progress = 0;
stamina -= 60;
start_lx = player_lx;
start_ly = player_ly;
target_lx = land_lx;
target_ly = land_ly;
start_px = (start_lx - start_ly) * 16 + 96;
start_py = (start_lx + start_ly) * 8 + 16;
target_px = (target_lx - target_ly) * 16 + 96;
target_py = (target_lx + target_ly) * 8 + 16;
// Play jump SFX (sweep up on Channel 1)
NR10_REG = 0x15; // sweep up
NR11_REG = 0x80; // 50% duty cycle
NR12_REG = 0xF3; // volume 15, fade
NR13_REG = 0x00; // low frequency bits
NR14_REG = 0xC3; // trigger note, frequency high bits
update_stamina_display();
update_player_sprite();
return;
}
}
// If jump checks fail, just face direction
update_player_sprite();
} else {
// Normal walk
int8_t new_lx = player_lx + move_lx; int8_t new_lx = player_lx + move_lx;
int8_t new_ly = player_ly + move_ly; int8_t new_ly = player_ly + move_ly;
@@ -490,12 +961,11 @@ void engine_update(uint8_t keys, uint8_t prev_keys) {
update_player_sprite(); update_player_sprite();
} else { } else {
// If collision blocks, just update direction look frame
update_player_sprite(); update_player_sprite();
} }
} else { } else {
// Out of bounds: update direction look frame
update_player_sprite(); update_player_sprite();
} }
} }
} }
}
+4
View File
@@ -3,7 +3,11 @@
#include <stdint.h> #include <stdint.h>
void title_init(void);
void title_update(uint8_t keys, uint8_t prev_keys);
void engine_init(void); void engine_init(void);
void engine_update(uint8_t keys, uint8_t prev_keys); void engine_update(uint8_t keys, uint8_t prev_keys);
extern uint8_t app_state;
#endif #endif
+60
View File
@@ -0,0 +1,60 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: gameover.png -c gameover.c -bpp 2 -noflip -keep_palette_order
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
BANKREF(gameover)
const palette_color_t gameover_palettes[32] = {
RGB8(255,255,255), RGB8(170,170,170), RGB8( 85, 85, 85), 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), RGB8( 0, 0, 0)
};
const uint8_t gameover_tiles[320] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfc,0xfe,0xf8,0xfc,0xf8,0xfd,0xf8,0xfd,
0xf8,0xfd,0xf8,0xfc,0xfc,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x1e,0xff,0x0c,0x1e,0x08,0xfd,0xf8,0xfd,0x88,0xfc,
0x88,0xdd,0x08,0xdd,0x08,0x1d,0x19,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x79,0xff,0x38,0x7d,0x18,0xbc,0x18,0xbd,0x18,0x3d,
0x18,0xbd,0x18,0xbd,0x18,0xbd,0x99,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x98,0xff,0x18,0xbc,0x18,0x3d,0x18,0xbc,0x18,0xbd,
0x18,0xbd,0x18,0xbc,0x18,0xbf,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xff,0x0f,0x1f,0x0f,0xff,0x1f,0x3f,0x0f,0xff,
0xff,0xff,0x0f,0x1f,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,0xf8,0xfc,0xf8,0xfd,0xf8,0xfd,0xf8,0xfd,
0xf8,0xfd,0xf8,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x39,0xff,0x18,0x3d,0x18,0xbd,0x18,0xbd,0x18,0xbd,
0x18,0xbd,0x1c,0x3e,0x3e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x98,0xff,0x18,0xbc,0x18,0xbd,0x18,0xbc,0x18,0xbd,
0x18,0xbd,0x38,0x7c,0x78,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x18,0xff,0x08,0x1c,0x08,0xfd,0x18,0x3c,0x08,0xfd,
0xf8,0xfd,0x08,0x1d,0x19,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0x1f,0x3f,0x1f,0xbf,0x3f,0x7f,0x1f,0xbf,
0x1f,0xbf,0x1f,0xbf,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
};
const metasprite_t gameover_metasprite0[] = {
METASPR_ITEM(-8, -40, 0, S_PAL(0)),
METASPR_ITEM(0, 8, 2, S_PAL(0)),
METASPR_ITEM(0, 8, 4, S_PAL(0)),
METASPR_ITEM(0, 8, 6, S_PAL(0)),
METASPR_ITEM(0, 8, 8, S_PAL(0)),
METASPR_ITEM(0, 8, 10, S_PAL(0)),
METASPR_ITEM(0, 8, 12, S_PAL(0)),
METASPR_ITEM(0, 8, 14, S_PAL(0)),
METASPR_ITEM(0, 8, 16, S_PAL(0)),
METASPR_ITEM(0, 8, 18, S_PAL(0)),
METASPR_TERM
};
const metasprite_t* const gameover_metasprites[1] = {
gameover_metasprite0
};
+31
View File
@@ -0,0 +1,31 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: gameover.png -c gameover.c -bpp 2 -noflip -keep_palette_order
#ifndef METASPRITE_gameover_H
#define METASPRITE_gameover_H
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
#define gameover_TILE_ORIGIN 0
#define gameover_TILE_W 8
#define gameover_TILE_H 16
#define gameover_WIDTH 80
#define gameover_HEIGHT 16
#define gameover_TILE_COUNT 20
#define gameover_PALETTE_COUNT 8
#define gameover_COLORS_PER_PALETTE 4
#define gameover_TOTAL_COLORS 32
#define gameover_PIVOT_X 40
#define gameover_PIVOT_Y 8
#define gameover_PIVOT_W 80
#define gameover_PIVOT_H 16
extern const metasprite_t* const gameover_metasprites[1];
BANKREF_EXTERN(gameover)
extern const palette_color_t gameover_palettes[32];
extern const uint8_t gameover_tiles[320];
#endif
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+212 -1
View File
@@ -101,6 +101,47 @@ def generate_tiles():
img.save("tiles.png") img.save("tiles.png")
def generate_stamina():
# 13 variants of 8x16 tiles = 104x16 pixels
img = Image.new("P", (104, 16), 0) # Fill with 0 (transparent)
img.putpalette(PALETTE)
def draw_sprite_bar_tile(x_off, filled_px, cap=None):
for y in range(8):
for x in range(8):
color = 3 # black inside
if y == 0 or y == 7:
color = 3 # black border
elif y == 1 or y == 6:
color = 2 # dark gray inner border
else:
if x < filled_px:
color = 1 # light gray (filled)
else:
color = 3 # black (empty)
if cap == 'L' and x == 0:
color = 2 # left border
elif cap == 'R' and x == 7:
color = 2 # right border
img.putpixel((x_off + x, y), color)
# Also fill bottom 8 rows with transparent color 0
for y in range(8, 16):
for x in range(104):
img.putpixel((x, y), 0)
for i in range(9):
draw_sprite_bar_tile(i * 8, i)
draw_sprite_bar_tile(9 * 8, 0, 'L')
draw_sprite_bar_tile(10 * 8, 0, 'R')
draw_sprite_bar_tile(11 * 8, 8, 'L')
draw_sprite_bar_tile(12 * 8, 8, 'R')
img.save("stamina.png")
# Grids for player frames # Grids for player frames
# 0 = White, 1 = Light Gray, 2 = Dark Gray, 3 = Black # 0 = White, 1 = Light Gray, 2 = Dark Gray, 3 = Black
@@ -227,7 +268,177 @@ def generate_player():
player_img.save("player.png") player_img.save("player.png")
def generate_gameover():
# 80x16 pixels
img = Image.new("P", (80, 16), 3)
img.putpalette(PALETTE)
# We can design each letter on an 8x16 grid
# Let's specify the pixel grids (16 rows of 8 chars)
# 0: White (text body), 2: Dark Gray (text outline/shadow), 3: Black (background)
grids = {
'G': [
"33322223",
"33200002",
"32002222",
"32023333",
"32023222",
"32023202",
"32002202",
"33200002",
"33322223",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
'A': [
"33322333",
"33200233",
"32022023",
"32022023",
"32000023",
"32022023",
"32022023",
"32022023",
"32233223",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
'M': [
"32233223",
"32022023",
"32000023",
"32022023",
"32022023",
"32022023",
"32022023",
"32022023",
"32233223",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
'E': [
"32222223",
"32000002",
"32022222",
"32000023",
"32022222",
"32023333",
"32000002",
"32222223",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
' ': [
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
'O': [
"33222233",
"32000023",
"32022023",
"32022023",
"32022023",
"32022023",
"32000023",
"33222233",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
'V': [
"32233223",
"32022023",
"32022023",
"32022023",
"32022023",
"32022023",
"33200233",
"33322333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
],
'R': [
"32222233",
"32000023",
"32022023",
"32000233",
"32022023",
"32022023",
"32022023",
"32233223",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333",
"33333333"
]
}
text = "GAME OVER"
for i, char in enumerate(text):
grid = grids[char]
for y in range(16):
for x in range(8):
val = int(grid[y][x])
target_x = i * 8 + x + 4
target_y = y + 3
if target_x < 80 and target_y < 16:
img.putpixel((target_x, target_y), val)
img.save("gameover.png")
if __name__ == "__main__": if __name__ == "__main__":
generate_tiles() generate_tiles()
generate_player() generate_player()
print("PNG assets generated (32x520 tiles, 8-frame player animation set created).") generate_gameover()
generate_stamina()
print("PNG assets generated (tiles, player, gameover, and stamina).")
+13 -1
View File
@@ -1,8 +1,10 @@
#include <gb/gb.h> #include <gb/gb.h>
#include "engine.h" #include "engine.h"
uint8_t app_state = 0; // 0 = title, 1 = game
void main(void) { void main(void) {
engine_init(); title_init();
SHOW_BKG; SHOW_BKG;
SHOW_SPRITES; SHOW_SPRITES;
@@ -13,7 +15,17 @@ void main(void) {
while (1) { while (1) {
wait_vbl_done(); wait_vbl_done();
uint8_t keys = joypad(); uint8_t keys = joypad();
if (app_state == 0) {
title_update(keys, prev_keys);
if ((keys & J_START) && !(prev_keys & J_START)) {
app_state = 1;
engine_init();
}
} else {
engine_update(keys, prev_keys); engine_update(keys, prev_keys);
}
prev_keys = keys; prev_keys = keys;
} }
} }
+22
View File
@@ -0,0 +1,22 @@
from PIL import Image
# Open the new cover image
img = Image.open('bg.png')
# Resize to 128x128 to ensure maximum 256 unique tiles
img = img.resize((128, 128), Image.Resampling.LANCZOS)
# Create a black 160x144 background
bg = Image.new('L', (160, 144), color=0)
# Paste the resized image in the center
bg.paste(img, (16, 8))
# Quantize to 4 colors (indexed mode 'P') for png2asset
final_img = bg.quantize(colors=4)
# Save the resulting image
final_img.save('title_bg.png')
print("title_bg.png created successfully (160x144, indexed).")
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+69
View File
@@ -0,0 +1,69 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: stamina.png -c stamina.c -bpp 2 -noflip -keep_palette_order
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
BANKREF(stamina)
const palette_color_t stamina_palettes[32] = {
RGB8(255,255,255), RGB8(170,170,170), RGB8( 85, 85, 85), 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), RGB8( 0, 0, 0)
};
const uint8_t stamina_tiles[416] = {
0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0x7f,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x1f,0xff,0x1f,0xff,0x1f,0xff,0x1f,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x0f,0xff,0x0f,0xff,0x0f,0xff,0x0f,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x03,0xff,0x03,0xff,0x03,0xff,0x03,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x01,0xff,0x01,0xff,0x01,0xff,0x01,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x7f,0xff,0x00,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0x00,0xff,0x7f,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xfe,0xff,0x00,0xff,0xfe,0xff,0xfe,0xff,0xfe,0xff,0xfe,0xff,0x00,0xff,0xfe,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x7f,0xff,0x00,0xff,0x7f,0x80,0x7f,0x80,0x7f,0x80,0x7f,0x80,0x00,0xff,0x7f,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xfe,0xff,0x00,0xff,0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01,0x00,0xff,0xfe,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
const metasprite_t stamina_metasprite0[] = {
METASPR_ITEM(-8, -52, 0, S_PAL(0)),
METASPR_ITEM(0, 8, 2, S_PAL(0)),
METASPR_ITEM(0, 8, 4, S_PAL(0)),
METASPR_ITEM(0, 8, 6, S_PAL(0)),
METASPR_ITEM(0, 8, 8, S_PAL(0)),
METASPR_ITEM(0, 8, 10, S_PAL(0)),
METASPR_ITEM(0, 8, 12, S_PAL(0)),
METASPR_ITEM(0, 8, 14, S_PAL(0)),
METASPR_ITEM(0, 8, 16, S_PAL(0)),
METASPR_ITEM(0, 8, 18, S_PAL(0)),
METASPR_ITEM(0, 8, 20, S_PAL(0)),
METASPR_ITEM(0, 8, 22, S_PAL(0)),
METASPR_ITEM(0, 8, 24, S_PAL(0)),
METASPR_TERM
};
const metasprite_t* const stamina_metasprites[1] = {
stamina_metasprite0
};
+31
View File
@@ -0,0 +1,31 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: stamina.png -c stamina.c -bpp 2 -noflip -keep_palette_order
#ifndef METASPRITE_stamina_H
#define METASPRITE_stamina_H
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
#define stamina_TILE_ORIGIN 0
#define stamina_TILE_W 8
#define stamina_TILE_H 16
#define stamina_WIDTH 104
#define stamina_HEIGHT 16
#define stamina_TILE_COUNT 26
#define stamina_PALETTE_COUNT 8
#define stamina_COLORS_PER_PALETTE 4
#define stamina_TOTAL_COLORS 32
#define stamina_PIVOT_X 52
#define stamina_PIVOT_Y 8
#define stamina_PIVOT_W 104
#define stamina_PIVOT_H 16
extern const metasprite_t* const stamina_metasprites[1];
BANKREF_EXTERN(stamina)
extern const palette_color_t stamina_palettes[32];
extern const uint8_t stamina_tiles[416];
#endif
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

+18
View File
@@ -0,0 +1,18 @@
from pyboy import PyBoy
import sys
def take_screenshot():
# Initialize PyBoy in headless mode to not block or require X11
pyboy = PyBoy('hello_iso.gb', window_type="headless")
# Run for 300 frames to let the PyBoy boot screen finish and the title screen render fully
for _ in range(300):
pyboy.tick()
# Take screenshot
pyboy.screen.image.save('screenshot.png')
print("Screenshot saved to screenshot.png")
pyboy.stop()
if __name__ == "__main__":
take_screenshot()
+75
View File
@@ -0,0 +1,75 @@
import cv2
import numpy as np
from pyboy import PyBoy
def main():
# Load PyBoy with the test gameover ROM
pyboy = PyBoy('test_gameover.gb', window='null', cgb=False)
# Tick for 120 frames to let the game boot and sprites render
for _ in range(120):
pyboy.tick()
# Grab screen buffer and convert it to OpenCV format
screen_image = pyboy.screen.image
# screen_image is a PIL Image. Convert to numpy array (RGB)
img_np = np.array(screen_image)
# Convert RGB to BGR for OpenCV
img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
# Save the screenshot
cv2.imwrite('gameover_rendering.png', img_bgr)
print("Screenshot saved to gameover_rendering.png")
# Analyze alignment using OpenCV
gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
h, w = gray.shape
print(f"Screen size: {w}x{h}")
# The background is white/light (value 255). The text has black/dark pixels.
# We use BINARY_INV to detect dark objects.
_, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
# Find all contours in the thresholded image
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Find the bounding box of elements in the lower half of the screen (y > 100) where "GAME OVER" is rendered
gameover_boxes = []
player_boxes = []
for cnt in contours:
x, y, rw, rh = cv2.boundingRect(cnt)
if y > 80:
gameover_boxes.append((x, y, rw, rh))
else:
player_boxes.append((x, y, rw, rh))
# Combine bounding boxes of GAME OVER parts
if len(gameover_boxes) > 0:
min_x = min(box[0] for box in gameover_boxes)
max_x = max(box[0] + box[2] for box in gameover_boxes)
min_y = min(box[1] for box in gameover_boxes)
max_y = max(box[1] + box[3] for box in gameover_boxes)
text_width = max_x - min_x
text_height = max_y - min_y
center_x = min_x + text_width / 2.0
print("\n--- OpenCV Alignment Verification ---")
print(f"GAME OVER text bounding box: x={min_x}, y={min_y}, w={text_width}, h={text_height}")
print(f"GAME OVER text horizontal center: {center_x}")
print(f"Target screen center: {w / 2.0}")
# Verify alignment within 2 pixels tolerance
offset = abs(center_x - (w / 2.0))
print(f"Alignment offset: {offset} pixels")
if offset <= 2.0:
print("SUCCESS: The GAME OVER text is absolutely aligned (perfectly centered)!")
else:
print(f"WARNING: The GAME OVER text is off-center by {offset} pixels.")
else:
print("Error: Could not detect the GAME OVER text in the lower half of the screen.")
pyboy.stop()
if __name__ == '__main__':
main()
+41
View File
@@ -0,0 +1,41 @@
#include <gb/gb.h>
#include <stdint.h>
#include <string.h>
#include "player.h"
#include "gameover.h"
// Define dummy / simple map buffer to clear the screen
static uint8_t map_buffer[32 * 32];
void main(void) {
SPRITES_8x16;
// Set standard palettes
OBP0_REG = 0xE4;
OBP1_REG = 0x1B;
BGP_REG = 0xE4;
// Clear background (completely black empty tiles)
memset(map_buffer, 0, sizeof(map_buffer));
set_bkg_tiles(0, 0, 32, 32, map_buffer);
// Load player and gameover sprite data
set_sprite_data(0, player_TILE_COUNT, player_tiles);
set_sprite_data(player_TILE_COUNT, gameover_TILE_COUNT, gameover_tiles);
// Render player sprite at center screen (88, 88)
move_metasprite(player_metasprites[0], 0, 0, 88, 88);
// Render gameover metasprite centered horizontally (88, due to sprite X-offset) and below player (120)
move_metasprite(gameover_metasprites[0], player_TILE_COUNT, 8, 88, 120);
SHOW_SPRITES;
SHOW_BKG;
DISPLAY_ON;
// Loop forever
while (1) {
wait_vbl_done();
}
}
+1
View File
@@ -0,0 +1 @@
# Music script generator
+213
View File
@@ -0,0 +1,213 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: title_bg.png -c title_bg.c -map -bpp 2 -noflip -keep_palette_order
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
BANKREF(title_bg)
const palette_color_t title_bg_palettes[4] = {
RGB8(161,161,161), RGB8( 74, 74, 74), RGB8( 11, 11, 11), RGB8( 0, 0, 0)
};
const uint8_t title_bg_tiles[2816] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0x7f,0xbf,0x7f,0xbf,0x7f,0x3f,0x1f,0x3f,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xe7,0xe1,0xc3,0xc7,0xc9,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xc6,0x83,0xc0,0xc0,0x99,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0x1c,0x0e,0x04,0x26,0x02,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0x16,0xef,0x0e,0x06,0x64,0x0e,
0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xf3,0x7f,0xff,0x73,0x79,0x73,0x3b,0x71,
0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xdf,0xef,0xee,0xdf,0xcf,0x9f,0x8f,0x9f,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc3,0x3c,0x82,0x00,0x38,0x82,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xde,0x3f,0x1e,0x0c,0x48,0x04,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xf9,0x1b,0x13,0x09,0xd1,0x08,
0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xf7,0xef,0xdf,0xef,0xef,0xcf,0x9f,0xcf,
0xff,0xfe,0xfc,0xfe,0xfe,0xfc,0xfe,0xfc,0xfe,0xfc,0xfd,0xf0,0xed,0xf0,0xf8,0xfd,
0x3f,0x1f,0xcf,0x1f,0x4f,0x9f,0xdf,0x8f,0x1f,0x0f,0xa7,0x4f,0xc7,0xef,0xff,0xe7,
0x9b,0xcd,0xd7,0x8d,0x85,0xc3,0xd0,0xe1,0x35,0xf8,0xe9,0x3c,0x7d,0xb8,0xb0,0x99,
0x3d,0x99,0x9a,0x3d,0x3d,0x3f,0x7e,0x3f,0x3e,0x3f,0x9f,0x3f,0x3b,0x9d,0x8f,0x99,
0x26,0x32,0x26,0x32,0x82,0x26,0x86,0x0e,0x8a,0x06,0xf2,0x26,0xe2,0x36,0xf0,0x36,
0xf6,0x6c,0x75,0x0c,0x20,0x1d,0xfd,0x19,0xbc,0x58,0xc1,0x70,0xfb,0x61,0x09,0x63,
0x78,0x31,0x98,0x30,0xb8,0x12,0xba,0x12,0x18,0x13,0xc9,0x13,0xc9,0xd3,0x71,0xcb,
0x0f,0x9f,0x0f,0x1f,0x4f,0x1f,0x8f,0x5f,0x0f,0xdf,0x8f,0xdf,0x8f,0xdf,0x8f,0xdf,
0xb4,0x1a,0x3c,0x82,0x0f,0x86,0x3f,0x86,0x0f,0xb6,0x27,0x9e,0x1f,0xbe,0x1f,0xbe,
0x4c,0x61,0x4d,0x61,0x25,0x49,0x1d,0x09,0x05,0x09,0xe8,0x45,0xcd,0x64,0xfe,0x64,
0xd8,0xc8,0xe0,0xc8,0xe3,0xc8,0xea,0xc9,0xeb,0xc9,0xdb,0xc9,0x8b,0xd9,0x5f,0x99,
0xdf,0x8f,0x9f,0x0f,0x6f,0x0f,0x2f,0x4f,0xef,0x4f,0xef,0xcf,0xef,0xcf,0xef,0xcf,
0xf8,0xfd,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xe7,0xef,0xf7,0xff,0xf7,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x91,0xc3,0xdb,0xe7,0xff,0xff,0xff,0xff,0xfe,0xf9,0xfc,0xf8,0xfd,0xf8,0xff,0xf9,
0x8d,0xc3,0xcf,0xe7,0xff,0xff,0xff,0xff,0x64,0xff,0x4d,0x00,0x2c,0x01,0x7c,0x21,
0xfb,0x34,0x3b,0xf7,0xfb,0xf7,0xff,0xff,0xc1,0xff,0x91,0xc8,0x9c,0xc8,0x9c,0xc9,
0x09,0x03,0xe9,0x87,0xe7,0xff,0xff,0xff,0xde,0xff,0x9d,0x1e,0xbe,0x1f,0xff,0x9f,
0xe1,0xcb,0xdd,0xeb,0xf9,0xef,0xef,0xff,0x1f,0xff,0x17,0x0f,0x87,0x03,0x93,0x21,
0x8f,0xdf,0xbf,0xdf,0x9f,0xff,0xef,0xdf,0xec,0xdf,0x8e,0xdc,0xde,0x8c,0x1c,0x8e,
0x3f,0xbe,0x3e,0xbf,0xdf,0xbf,0x9f,0xff,0x3f,0xff,0x2b,0x1c,0x05,0x08,0xac,0x41,
0xff,0x66,0x77,0xef,0xf7,0xef,0xff,0xff,0xff,0x9f,0xdf,0x9f,0xdf,0x9f,0xdf,0x9f,
0x1f,0x39,0xfb,0x3d,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xcf,0xff,0xcf,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0x3f,0xff,
0xf9,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc5,0xff,
0x68,0x35,0x61,0x3c,0xfc,0x38,0xf9,0x30,0xfd,0x30,0xf1,0x3c,0xf9,0x3c,0xfd,0x3c,
0xdc,0xc9,0xdc,0x08,0x1d,0x08,0xd5,0x09,0xcd,0xd9,0x8d,0xd9,0x8c,0xd9,0x88,0xd0,
0xbf,0x5f,0x1f,0x7f,0x3f,0x7f,0xbf,0x7f,0x1f,0xff,0xbf,0xdf,0xff,0x9f,0xbf,0x1f,
0x9b,0x31,0x3b,0x91,0x38,0x93,0x38,0x93,0x3a,0x90,0x82,0x30,0x32,0xa6,0xee,0x86,
0x84,0x0e,0x4c,0x26,0x66,0x26,0x60,0x06,0x33,0x06,0x77,0x72,0xff,0x72,0xf1,0x7a,
0xcd,0x61,0xe4,0x49,0x5d,0x08,0x1d,0x08,0x85,0x49,0xe4,0x49,0xc8,0x65,0x76,0xed,
0x9f,0x9f,0xbf,0x1f,0x7f,0x3f,0x3f,0x1f,0x9f,0x1f,0xff,0x9f,0xff,0x9f,0xff,0x9f,
0xfe,0xff,0xfb,0xff,0xfb,0xff,0xfc,0xff,0xea,0xf1,0xe0,0xf8,0xff,0xfe,0xff,0xff,
0xff,0xff,0xff,0xff,0xdf,0xfc,0x1e,0xfc,0x17,0xfc,0x9f,0x70,0x06,0x38,0x3d,0x84,
0xe5,0xdb,0x9b,0xf7,0xf7,0x2f,0xbf,0x4f,0xff,0x9f,0x7f,0x3f,0xff,0x7f,0xff,0xff,
0xff,0x3c,0x7c,0xbf,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x81,0xde,0x8f,0xdf,0xef,0xdf,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x0f,0x1f,0xad,0xde,0xfb,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x5f,0x8e,0xdf,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x7c,0xfb,0xfd,0xfb,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x76,0xed,0xf4,0xef,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0x9f,0xff,0x9f,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xbf,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,
0xfe,0xff,0xfe,0xff,0xfc,0xff,0xfe,0xfd,0xcf,0xfc,0xcf,0xfc,0xf7,0xcc,0xe7,0xc0,
0xff,0xf1,0x31,0xe3,0xaf,0x41,0xeb,0x19,0x1b,0x79,0x3d,0x7b,0x39,0x7f,0x3a,0x7d,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x3f,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb9,0x7f,
0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x7f,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0x3f,0xff,0x3f,0xff,0xff,0xff,0x3f,0xff,
0xff,0xff,0xff,0xff,0xdf,0xff,0x5f,0xff,0xbf,0x7f,0xbf,0x7f,0xbf,0x7f,0x9f,0x7f,
0xda,0xf0,0xc7,0xfe,0xc7,0xfc,0xf6,0xf8,0xe8,0xfc,0xf4,0xf8,0xe0,0xf0,0xf0,0xc0,
0x12,0x79,0xa7,0x58,0xbc,0x48,0x34,0x48,0x24,0x78,0x1b,0x64,0x20,0x40,0x20,0x40,
0x8f,0x1f,0x9f,0x0f,0x39,0x0f,0x35,0x0b,0x9d,0x03,0x1e,0x01,0x16,0x01,0x07,0x03,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xf7,0x33,0xf7,0x27,0xb7,
0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x7b,0xff,0x5a,0xbd,0xdf,0x39,0x7f,0xff,0x93,0xfd,0xf7,0x81,0xf3,0xff,0xff,0xdd,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,
0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x7f,0xbf,0x7f,0xbf,0x7f,0xbf,
0xfe,0xff,0xfe,0xff,0xfe,0xff,0xfe,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0x5f,0x7f,0xff,0xbf,0x7f,0xdf,0x3f,0xcf,0x3f,0xbf,0x4f,0x7f,0x8f,0x7f,0x8f,
0xf0,0xc0,0xf0,0xc0,0x90,0xc0,0xdc,0xf8,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xe0,
0x60,0x00,0x60,0x00,0x40,0x00,0x80,0x40,0x40,0x80,0x40,0x00,0x40,0x00,0x40,0x00,
0x03,0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x01,0x01,0x01,0x01,0x03,0x01,0x01,0x01,
0xdf,0x3f,0x9f,0x3f,0x9f,0x3f,0x9f,0x3e,0x9a,0x3c,0xcc,0x39,0x19,0xf2,0xf6,0x18,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9f,0xdf,0x3f,0xff,0x7f,0x3f,0xdf,0x47,0x0f,
0x37,0xbf,0xbe,0x7f,0x3f,0x7f,0xbf,0x7f,0xff,0x9f,0xcf,0x9f,0xdf,0xff,0xff,0xff,
0xff,0xff,0xbf,0xdf,0x9f,0xdf,0xff,0x9f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xdd,0xc1,0xdf,0xe3,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xfe,0xf3,0xff,0xe4,0xc2,0xed,0xef,0x89,0x8b,0xb9,0xf3,0xbb,0xf9,0xfe,0xfd,0xfe,
0x7f,0xff,0xff,0xff,0xbf,0xff,0xbf,0xff,0x3f,0xff,0x2f,0x5f,0x8f,0x5f,0x9f,0xff,
0x7f,0xbf,0xef,0xdf,0xef,0x9f,0x7f,0xbf,0x7f,0xbf,0x3f,0xff,0x3f,0xff,0x3f,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,
0xff,0x0f,0xff,0x0f,0xff,0x0f,0x6f,0x9f,0xff,0xff,0xdf,0x3f,0x9f,0x3f,0x1f,0xbf,
0xf0,0xe0,0xe0,0xc0,0xf0,0xc0,0xf0,0xc0,0xc0,0xe0,0xfc,0xe0,0xc7,0xf0,0xa0,0xc0,
0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x59,0x00,0x87,0x78,0x7b,0xc0,0x7f,0x40,
0x01,0x01,0x01,0x01,0x03,0x01,0x27,0x03,0x1f,0x27,0xe3,0x1f,0x2f,0x93,0x6b,0x97,
0xf7,0x18,0xf1,0x1e,0xfc,0x18,0xfe,0x18,0xfe,0x1c,0x1e,0xfe,0x7f,0x98,0x41,0xb0,
0xcf,0x27,0x7f,0x09,0x2b,0x05,0x25,0x47,0x47,0x27,0xbf,0x67,0xa9,0x1f,0x5e,0x39,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xeb,0xf7,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
0x3f,0xff,0x3f,0xff,0x5f,0xbf,0xdf,0xbf,0xff,0xff,0x5f,0xbf,0x5f,0xbf,0x3f,0xff,
0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xff,0xff,0xdf,0xff,
0xf2,0xe0,0xf6,0xe0,0xfe,0xe0,0xff,0xe0,0xfc,0xfb,0xff,0xff,0xff,0xff,0xf8,0xfe,
0x0a,0x77,0x37,0x7b,0x33,0x7f,0x3f,0x7f,0x37,0x79,0x83,0x7f,0xcf,0xff,0xcf,0x7f,
0xbf,0xdf,0x5f,0xa7,0xa5,0x07,0xbf,0x07,0xb3,0x19,0xc8,0x98,0x98,0xfc,0xf9,0xee,
0x03,0xe0,0xa2,0xc0,0xdb,0xc0,0x19,0x8c,0x94,0x0c,0x84,0x1e,0xee,0x1f,0xff,0x3f,
0xb0,0xfd,0xa7,0x01,0x47,0x03,0xeb,0x37,0xdb,0x26,0x1b,0x74,0x6e,0x91,0x3f,0xc1,
0xe0,0xff,0xfd,0xfa,0xfa,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
0x7f,0xff,0xcf,0xff,0xff,0xff,0x5f,0xbf,0xdf,0xbf,0x9f,0xef,0xa7,0xcf,0xc7,0xe7,
0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0xff,0xff,0x9f,0xff,
0x3f,0xcf,0xef,0x7f,0xbf,0x7f,0xbf,0x7f,0xbf,0x7f,0x3f,0xff,0xff,0xff,0xff,0xff,
0xf8,0xe0,0xfc,0xe0,0xe0,0xfc,0xff,0xf0,0xee,0xf1,0xed,0xf3,0xed,0xf3,0xf7,0xfb,
0x3f,0x7f,0x3f,0x7f,0x3f,0x7f,0x3f,0x7f,0xff,0x7f,0xbf,0x7f,0xbf,0x7f,0xbf,0x7f,
0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x7e,0xa3,0x6f,0x9f,0xeb,0xc7,0xa3,0xff,0xfe,0xf1,0x7d,0xb3,0xbf,0x0f,0x1b,0x07,
0x7f,0xff,0x7f,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xf7,0xe3,0xc2,0xe1,0xe1,0xc0,0xd9,0xc0,0xea,0xd9,0xf7,0xfb,0xff,0xff,0xff,0xff,
0x7f,0x9f,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,0x3f,0xff,
0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0x9f,0xff,0x4f,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xcf,0xff,0xef,0xdf,0xcf,0xff,0xcf,0xff,0xde,0xff,0xf3,0xfc,0xff,0xe1,0xff,0xe9,
0xff,0x7f,0xdf,0x3f,0xff,0x1f,0xcf,0xdf,0x3f,0xcf,0xf7,0x0f,0xef,0x17,0x8f,0x53,
0xff,0xfe,0xfc,0xfe,0xfe,0xfc,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfc,0xfe,0xfc,
0x13,0x0f,0x6f,0x07,0x59,0xef,0xf9,0x3f,0x2f,0x1f,0x6f,0x1f,0x6f,0x1f,0xff,0x3f,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfe,
0x3f,0xff,0xbf,0x7f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,
0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xf5,0x1b,0xd3,0x0d,0x9f,0x40,0xf3,0x46,0xe5,0x4b,0xef,0x09,0x97,0x6c,0x7f,0xe6,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x3f,0xaf,0xdf,0x67,0xdf,0xf0,0x7f,
0xfe,0xfc,0xf6,0xfc,0xf5,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xd7,0xef,0x7e,0x81,
0x5f,0x3f,0xbf,0x7f,0xff,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xfd,0x07,0xf8,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x40,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xdf,0xbf,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xfc,0xfe,0xfd,0xfa,0xfd,0xf4,0xfb,0xfe,0xf1,0xe3,0xe4,0xc5,0xc8,0x8c,0xd1,
0xbf,0xff,0x9f,0xff,0x7f,0xff,0xbf,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xfc,0xfe,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdd,0x3e,0x0d,0x1e,
0xfa,0xf7,0xf4,0xfb,0xe7,0xf8,0xbf,0xc0,0x7f,0x80,0xf8,0xe7,0xf0,0x00,0xc0,0x00,
0x9d,0xfe,0x63,0x9c,0xae,0x40,0x9c,0x60,0x00,0x01,0xa5,0x03,0xdb,0x3c,0x08,0x10,
0xfe,0x01,0x36,0xf9,0x78,0x00,0xc7,0x00,0x00,0x00,0x80,0x00,0xff,0x00,0x01,0x01,
0x6f,0x9c,0x9c,0x3f,0xfe,0x7c,0x4e,0x3c,0x34,0x3e,0xf6,0x0e,0x36,0x0f,0xff,0xff,
0xe4,0x1f,0xb1,0x6e,0x38,0x07,0xdf,0x3f,0xf7,0x0f,0x5f,0x3f,0x7f,0xff,0xff,0xff,
0x87,0xff,0x3f,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,0xe0,0xff,
0x8f,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0x4f,0xff,0x72,0xff,
0xff,0xff,0xff,0xff,0xfc,0xff,0x1c,0xff,0xbf,0x3f,0xff,0x3f,0xff,0x3f,0x3f,0xff,
0xff,0xff,0xf7,0xff,0x7f,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xfe,0xff,0xfc,0xfe,0xfe,0xf9,0xf1,0xf3,0xfb,0xc7,0xce,0xff,0xff,0xfe,
0x57,0xa9,0xbb,0x43,0x35,0x53,0x0f,0xb7,0x28,0x87,0x5c,0x8f,0xfe,0x1f,0xbe,0x7f,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0x7f,0xbf,
0xfe,0xff,0xfd,0xfe,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x0f,0x3f,0xbc,0x7f,0xf0,0xff,0xf4,0xff,0xfa,0xf9,0xf7,0xf8,0xff,0xfe,0xff,0xff,
0xfe,0x00,0x80,0x00,0x83,0x01,0x6f,0xc6,0x12,0xec,0x17,0xf8,0x33,0xfc,0xfe,0xff,
0x01,0x20,0xb0,0x40,0xc0,0x80,0xff,0x00,0x01,0x00,0xfc,0x00,0xf7,0x08,0x73,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0xfc,0xc0,0x00,0xbf,0x98,0xff,0xff,
0xff,0x7f,0x4f,0x3f,0x7f,0x3f,0x2c,0x52,0x19,0x00,0x68,0x1f,0xbf,0x00,0x81,0xff,
0xff,0xff,0xc8,0xf0,0xc0,0x80,0x01,0x00,0xff,0x73,0xdf,0xe0,0x60,0xc0,0xdf,0xff,
0xcf,0x80,0x7e,0x00,0xc7,0x00,0x3d,0x03,0x78,0xff,0xd0,0x38,0x4b,0x37,0xff,0xff,
0x61,0xc2,0x59,0x87,0xc0,0x9f,0xcc,0x83,0x03,0xff,0x1f,0x0f,0xff,0xff,0xff,0xff,
0x3c,0x3f,0xac,0xc7,0x67,0x9f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xef,0xff,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xfe,0xff,0xf9,0xfe,0xfb,0xf0,0xfd,0xe3,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xfe,0xbe,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xef,0x1f,0x4f,0xbf,0x3f,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xcf,0xff,0xa7,0xcf,0xfe,0x87,0xce,0x86,0xee,0x97,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0x0d,0x20,0xf0,0x00,0x25,0x00,0x87,0x3f,0x3f,0xff,0xff,0xff,
0xff,0xff,0xfc,0xfd,0x2c,0x9c,0x0c,0x1d,0xac,0x1c,0x9e,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xfc,0xfe,0xdc,0x2e,0x8c,0x2e,0xcd,0x0e,0x9f,0xcf,0x9f,0xff,0xff,0xff,
0xff,0xff,0xbf,0x39,0x2d,0x00,0x21,0x85,0x69,0x84,0xec,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x3f,0x16,0x20,0xe1,0x20,0x14,0xa0,0x96,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xe7,0x74,0xe2,0xfc,0x60,0xf6,0x60,0xf6,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xd3,0x08,0x2c,0x10,0xd9,0x00,0x49,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xed,0x00,0xe8,0x00,0x4d,0x20,0x6c,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xe7,0xef,0x66,0xe0,0x60,0xe8,0xe6,0xe8,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xeb,0x74,0xe1,0x70,0xeb,0x70,0x7f,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfe,0x27,0x4e,0x6f,0x06,0x67,0x0e,0x4f,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x7f,0x4d,0x20,0xda,0x01,0x67,0x01,0x67,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xfd,0xfb,0x21,0x93,0x8f,0x01,0x31,0x83,0x93,0xff,0xff,0xff,0xff,0xff
};
const unsigned char title_bg_map[360] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x00,0x39,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x3a,0x3b,0x3c,0x3d,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x3f,0x40,0x00,0x00,0x00,
0x00,0x00,0x00,0x41,0x42,0x43,0x44,0x45,0x00,0x46,0x47,0x48,0x49,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,
0x00,0x00,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x00,0x00,0x57,0x00,0x00,0x00,
0x00,0x00,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x00,0x00,0x00,0x00,0x00,0x61,0x00,0x00,0x00,
0x00,0x00,0x00,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x00,0x00,0x00,0x00,0x00,0x6a,0x00,0x00,0x00,
0x00,0x00,0x3f,0x6b,0x6c,0x6d,0x6e,0x25,0x6f,0x70,0x71,0x00,0x00,0x00,0x00,0x00,0x72,0x00,0x00,0x00,
0x00,0x00,0x73,0x74,0x75,0x76,0x00,0x77,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0x7a,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x00,0x00,0x83,0x84,0x85,0x00,0x00,0x00,
0x00,0x00,0x00,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x00,0x00,0x00,
0x00,0x00,0x00,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0x00,0x00,0x00,
0x00,0x00,0x00,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
+29
View File
@@ -0,0 +1,29 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: title_bg.png -c title_bg.c -map -bpp 2 -noflip -keep_palette_order
#ifndef METASPRITE_title_bg_H
#define METASPRITE_title_bg_H
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
#define title_bg_TILE_ORIGIN 0
#define title_bg_TILE_W 8
#define title_bg_TILE_H 8
#define title_bg_WIDTH 160
#define title_bg_HEIGHT 144
#define title_bg_TILE_COUNT 176
#define title_bg_PALETTE_COUNT 1
#define title_bg_COLORS_PER_PALETTE 4
#define title_bg_TOTAL_COLORS 4
#define title_bg_MAP_ATTRIBUTES 0
extern const unsigned char title_bg_map[360];
#define title_bg_map_attributes title_bg_map
BANKREF_EXTERN(title_bg)
extern const palette_color_t title_bg_palettes[4];
extern const uint8_t title_bg_tiles[2816];
#endif
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB