Browse Source

Initial commit of isometric Game Boy adventure prototype

main
Matteo Benedetto 9 hours ago
commit
20a5d8604b
  1. 16
      .gitignore
  2. 16
      Makefile
  3. 225
      engine.c
  4. 9
      engine.h
  5. 197
      generate_assets.py
  6. BIN
      hello_iso_gb.png
  7. 19
      main.c
  8. 56
      opencv_analyze_tiles.py
  9. 30
      opencv_check_centering.py
  10. 102
      player.c
  11. 31
      player.h
  12. BIN
      player.png
  13. 59
      test_movement.py
  14. 14
      test_pyboy.py
  15. 124
      tiles.c
  16. 29
      tiles.h
  17. BIN
      tiles.png

16
.gitignore vendored

@ -0,0 +1,16 @@
# GBDK build artifacts
*.o
*.lst
*.map
*.sym
*.cdb
*.ihx
*.noi
*.asm
# Compiled ROMs
*.gb
# Python caches
__pycache__/
*.pyc

16
Makefile

@ -0,0 +1,16 @@
GBDK_HOME = /home/enne2/.local/gbdk
LCC = $(GBDK_HOME)/bin/lcc
PNG2ASSET = $(GBDK_HOME)/bin/png2asset
all: hello_iso.gb
assets: generate_assets.py
python3 generate_assets.py
$(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
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
clean:
rm -f *.o *.lst *.map *.gb *.ihx *.sym *.cdb *.adb *.asm

225
engine.c

@ -0,0 +1,225 @@
#include <gb/gb.h>
#include <stdint.h>
#include <string.h>
#include <rand.h>
#include "engine.h"
// Generated by png2asset
#include "tiles.h"
#include "player.h"
#define MAP_SIZE 7
uint8_t maze[MAP_SIZE][MAP_SIZE];
static uint8_t map_buffer[32 * 32];
uint8_t player_lx = 1;
uint8_t player_ly = 1;
uint8_t player_dir = 0; // 0=DR, 1=DL, 2=UL, 3=UR
uint8_t walk_timer = 0;
uint8_t scroll_x = 0;
uint8_t scroll_y = 0;
// DAS variables
uint8_t das_timer = 0;
uint8_t das_active = 0;
#define DAS_DELAY 12
#define DAS_REPEAT 6
static void generate_maze(void) {
// Clear maze (all 0/walls)
memset(maze, 0, sizeof(maze));
// Stack for backtracking (3x3 grid has 9 odd cells max)
uint8_t stack_x[9];
uint8_t stack_y[9];
uint8_t stack_ptr = 0;
// Start at (1, 1)
uint8_t cx = 1;
uint8_t cy = 1;
maze[cy][cx] = 1;
while (1) {
// Find unvisited neighbors at distance 2
// Up: (cx, cy-2), Down: (cx, cy+2), Left: (cx-2, cy), Right: (cx+2, cy)
uint8_t nx[4];
uint8_t ny[4];
uint8_t count = 0;
// Up
if (cy >= 3 && maze[cy - 2][cx] == 0) {
nx[count] = cx; ny[count] = cy - 2; count++;
}
// Down
if (cy <= 3 && maze[cy + 2][cx] == 0) {
nx[count] = cx; ny[count] = cy + 2; count++;
}
// Left
if (cx >= 3 && maze[cy][cx - 2] == 0) {
nx[count] = cx - 2; ny[count] = cy; count++;
}
// Right
if (cx <= 3 && maze[cy][cx + 2] == 0) {
nx[count] = cx + 2; ny[count] = cy; count++;
}
if (count > 0) {
// Choose a random neighbor
uint8_t dir = rand() % count;
// Push current cell to stack
stack_x[stack_ptr] = cx;
stack_y[stack_ptr] = cy;
stack_ptr++;
// Remove wall between current cell and chosen neighbor
maze[(cy + ny[dir]) / 2][(cx + nx[dir]) / 2] = 1;
// Move to neighbor
cx = nx[dir];
cy = ny[dir];
maze[cy][cx] = 1;
} else if (stack_ptr > 0) {
// Pop from stack
stack_ptr--;
cx = stack_x[stack_ptr];
cy = stack_y[stack_ptr];
} else {
break;
}
}
}
static void draw_map(void) {
// Fill entire map with tile index 0 (completely black empty tile)
memset(map_buffer, 0, sizeof(map_buffer));
// Draw logical map path tiles
for (int8_t ly = 0; ly < MAP_SIZE; ly++) {
for (int8_t lx = 0; lx < MAP_SIZE; lx++) {
if (maze[ly][lx] == 1) {
// Centering math for 7x7 map on 32x32 background map
int8_t iso_x = (lx - ly) * 2 + 12;
int8_t iso_y = (lx + ly) * 1 + 2;
// Alternate colors (checkerboard)
uint8_t is_alt = ((lx + ly) % 2 == 0);
// Calculate neighbor mask
uint8_t has_tl = (lx > 0 && maze[ly][lx - 1] == 1);
uint8_t has_tr = (ly > 0 && maze[ly - 1][lx] == 1);
uint8_t has_bl = (ly < MAP_SIZE - 1 && maze[ly + 1][lx] == 1);
uint8_t has_br = (lx < MAP_SIZE - 1 && maze[ly][lx + 1] == 1);
uint8_t mask = (has_tl ? 1 : 0) | (has_tr ? 2 : 0) | (has_bl ? 4 : 0) | (has_br ? 8 : 0);
uint8_t v = is_alt ? (16 + mask) : mask;
for (uint8_t y = 0; y < 2; y++) {
for (uint8_t x = 0; x < 4; x++) {
uint8_t target_x = (iso_x + x) & 31;
uint8_t target_y = (iso_y + y) & 31;
uint8_t src_tile = tiles_map[4 + v * 8 + y * 4 + x];
map_buffer[target_y * 32 + target_x] = src_tile;
}
}
}
}
}
set_bkg_tiles(0, 0, 32, 32, map_buffer);
}
static void update_camera(void) {
// Center the camera on the player's logical tile coordinates
int16_t px = (player_lx - player_ly) * 16 + 96;
int16_t py = (player_lx + player_ly) * 8 + 16;
scroll_x = px - 64;
scroll_y = py - 72;
move_bkg(scroll_x, scroll_y);
}
static void update_player_sprite(void) {
uint8_t frame_offset = (walk_timer > 0) ? ((walk_timer >> 2) & 1) : 0;
move_metasprite(player_metasprites[player_dir * 2 + frame_offset], 0, 0, 88, 88);
}
void engine_init(void) {
SPRITES_8x16;
// Seed random number generator with hardware divider register
initrand(DIV_REG);
// Generate maze path cells
generate_maze();
// Explicitly initialize DMG palette registers
OBP0_REG = 0xE4; // 11 10 01 00 (Black, Dark Gray, Light Gray, White)
BGP_REG = 0xE4;
// Initialize GBC palettes (safe on DMG, does nothing)
set_bkg_palette(0, 8, tiles_palettes);
set_sprite_palette(0, 8, player_palettes);
// Load tiles
set_bkg_data(0, tiles_TILE_COUNT, tiles_tiles);
set_sprite_data(0, player_TILE_COUNT, player_tiles);
draw_map();
update_camera();
update_player_sprite();
}
void engine_update(uint8_t keys, uint8_t prev_keys) {
if (walk_timer > 0) {
walk_timer--;
update_player_sprite();
}
uint8_t keys_pressed = keys & ~prev_keys;
int8_t move_lx = 0;
int8_t move_ly = 0;
if (keys_pressed) {
das_timer = DAS_DELAY;
das_active = 1;
} else if (keys && das_active) {
das_timer--;
if (das_timer == 0) {
das_timer = DAS_REPEAT;
keys_pressed = keys; // trigger move
}
} else {
das_active = 0;
}
if (keys_pressed & J_RIGHT) {
move_lx = 1; player_dir = 0; // DR
} else if (keys_pressed & J_LEFT) {
move_lx = -1; player_dir = 2; // UL
} else if (keys_pressed & J_DOWN) {
move_ly = 1; player_dir = 1; // DL
} else if (keys_pressed & J_UP) {
move_ly = -1; player_dir = 3; // UR
}
if (move_lx != 0 || move_ly != 0) {
int8_t new_lx = player_lx + move_lx;
int8_t new_ly = player_ly + move_ly;
// Bounds check & wall/empty area collision check
if (new_lx >= 0 && new_lx < MAP_SIZE && new_ly >= 0 && new_ly < MAP_SIZE) {
if (maze[new_ly][new_lx] == 1) {
player_lx = new_lx;
player_ly = new_ly;
walk_timer = 12; // 12 frames of walk cycle
}
}
update_player_sprite();
update_camera();
}
}

9
engine.h

@ -0,0 +1,9 @@
#ifndef ENGINE_H
#define ENGINE_H
#include <stdint.h>
void engine_init(void);
void engine_update(uint8_t keys, uint8_t prev_keys);
#endif

197
generate_assets.py

@ -0,0 +1,197 @@
import os
from PIL import Image, ImageDraw
# Standard Game Boy palette
# 0: White, 1: Light Gray, 2: Dark Gray, 3: Black
PALETTE = [
255, 255, 255, # 0
170, 170, 170, # 1
85, 85, 85, # 2
0, 0, 0 # 3
] + [0] * (256 * 3 - 12)
def draw_autotile(draw, y_offset, is_alt, mask):
# Determine the neighbor fill color
# Tile 1 (Normal, is_alt=False) neighbors should match Tile 2 (Alt) body color: 1 (Light Gray)
# Tile 2 (Alt, is_alt=True) neighbors should match Tile 1 (Normal) body color: 0 (White)
neighbor_color = 0 if is_alt else 1
# 4 corners
# Bit 0 (1): Top-Left
# Bit 1 (2): Top-Right
# Bit 2 (4): Bottom-Left
# Bit 3 (8): Bottom-Right
tl_color = neighbor_color if (mask & 1) else 3
tr_color = neighbor_color if (mask & 2) else 3
dl_color = neighbor_color if (mask & 4) else 3
dr_color = neighbor_color if (mask & 8) else 3
# Draw corners
draw.polygon([(0, y_offset), (15, y_offset), (0, y_offset + 7)], fill=tl_color)
draw.polygon([(16, y_offset), (31, y_offset), (31, y_offset + 7)], fill=tr_color)
draw.polygon([(0, y_offset + 8), (0, y_offset + 15), (15, y_offset + 15)], fill=dl_color)
draw.polygon([(31, y_offset + 8), (31, y_offset + 15), (16, y_offset + 15)], fill=dr_color)
# Draw the main diamond shape on top
points = [(15, y_offset), (31, y_offset + 7), (16, y_offset + 15), (0, y_offset + 8)]
inner = [(15, y_offset + 4), (27, y_offset + 7), (16, y_offset + 11), (4, y_offset + 8)]
if not is_alt:
# Tile 1: Normal floor (body is White, inner is Light Gray)
draw.polygon(points, fill=0, outline=2)
draw.polygon(inner, fill=1, outline=2)
else:
# Tile 2: Alt floor (body is Light Gray, inner is White)
draw.polygon(points, fill=1, outline=2)
draw.polygon(inner, fill=0, outline=2)
def generate_tiles():
# 32 variants total:
# 0..15: Tile 1 (Normal Floor) with masks 0..15
# 16..31: Tile 2 (Alt Floor) with masks 0..15
# Height is 8 pixels (black spacer) + 32 variants * 16 pixels = 520 pixels
img = Image.new("P", (32, 520), 3)
img.putpalette(PALETTE)
draw = ImageDraw.Draw(img)
# Draw Tile 1 variants (start at y=8)
for mask in range(16):
draw_autotile(draw, 8 + mask * 16, False, mask)
# Draw Tile 2 variants (start at y=8 + 256 = 264)
for mask in range(16):
draw_autotile(draw, 264 + mask * 16, True, mask)
img.save("tiles.png")
# Grids for player frames
# 0 = White, 1 = Light Gray, 2 = Dark Gray, 3 = Black
# Down-Right Stand (Frame 0)
GRID_DR_STAND = [
"0000000000000000",
"0000003333000000",
"0000031111300000",
"0000311111130000",
"0000311313130000", # Eyes facing right/down
"0000031111300000",
"0000003333000000",
"0000032222300000",
"0000312222130000",
"0000312222130000",
"0000032222300000",
"0000003333000000",
"0000033003300000",
"0000033003300000",
"0000333003330000",
"0000000000000000"
]
# Down-Right Walk (Frame 1)
GRID_DR_WALK = [
"0000000000000000",
"0000003333000000",
"0000031111300000",
"0000311111130000",
"0000311313130000",
"0000031111300000",
"0000003333000000",
"0000032222300000",
"0000312222130000",
"0000312222130000",
"0000032222300000",
"0000003333000000",
"0000033000030000", # Left leg forward, right leg back
"0000330000033000",
"0003330000033300",
"0000000000000000"
]
# Up-Right Stand (Frame 4 in final list)
GRID_UR_STAND = [
"0000000000000000",
"0000003333000000",
"0000031111300000",
"0000311111130000",
"0000311111130000", # Back of head (no eyes)
"0000031111300000",
"0000003333000000",
"0000032222300000",
"0000312222130000",
"0000312222130000",
"0000032222300000",
"0000003333000000",
"0000033003300000",
"0000033003300000",
"0000333003330000",
"0000000000000000"
]
# Up-Right Walk (Frame 5 in final list)
GRID_UR_WALK = [
"0000000000000000",
"0000003333000000",
"0000031111300000",
"0000311111130000",
"0000311111130000",
"0000031111300000",
"0000003333000000",
"0000032222300000",
"0000312222130000",
"0000312222130000",
"0000032222300000",
"0000003333000000",
"0000033000030000",
"0000330000033000",
"0003330000033300",
"0000000000000000"
]
def draw_frame(draw, grid, x_off):
for y in range(16):
for x in range(16):
val = int(grid[y][x])
draw.point((x_off + x, y), fill=val)
def generate_player():
# 8 frames in total (128x16 pixels)
player_img = Image.new("P", (128, 16), 0)
player_img.putpalette(PALETTE)
dr_stand = Image.new("P", (16, 16), 0)
dr_stand.putpalette(PALETTE)
draw_frame(ImageDraw.Draw(dr_stand), GRID_DR_STAND, 0)
dr_walk = Image.new("P", (16, 16), 0)
dr_walk.putpalette(PALETTE)
draw_frame(ImageDraw.Draw(dr_walk), GRID_DR_WALK, 0)
ur_stand = Image.new("P", (16, 16), 0)
ur_stand.putpalette(PALETTE)
draw_frame(ImageDraw.Draw(ur_stand), GRID_UR_STAND, 0)
ur_walk = Image.new("P", (16, 16), 0)
ur_walk.putpalette(PALETTE)
draw_frame(ImageDraw.Draw(ur_walk), GRID_UR_WALK, 0)
dl_stand = dr_stand.transpose(Image.FLIP_LEFT_RIGHT)
dl_walk = dr_walk.transpose(Image.FLIP_LEFT_RIGHT)
ul_stand = ur_stand.transpose(Image.FLIP_LEFT_RIGHT)
ul_walk = ur_walk.transpose(Image.FLIP_LEFT_RIGHT)
player_img.paste(dr_stand, (0 * 16, 0))
player_img.paste(dr_walk, (1 * 16, 0))
player_img.paste(dl_stand, (2 * 16, 0))
player_img.paste(dl_walk, (3 * 16, 0))
player_img.paste(ul_stand, (4 * 16, 0))
player_img.paste(ul_walk, (5 * 16, 0))
player_img.paste(ur_stand, (6 * 16, 0))
player_img.paste(ur_walk, (7 * 16, 0))
player_img.save("player.png")
if __name__ == "__main__":
generate_tiles()
generate_player()
print("PNG assets generated (32x520 tiles, 8-frame player animation set created).")

BIN
hello_iso_gb.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

19
main.c

@ -0,0 +1,19 @@
#include <gb/gb.h>
#include "engine.h"
void main(void) {
engine_init();
SHOW_BKG;
SHOW_SPRITES;
DISPLAY_ON;
uint8_t prev_keys = 0;
while (1) {
wait_vbl_done();
uint8_t keys = joypad();
engine_update(keys, prev_keys);
prev_keys = keys;
}
}

56
opencv_analyze_tiles.py

@ -0,0 +1,56 @@
import cv2
import numpy as np
def main():
img = cv2.imread('hello_iso_gb.png')
if img is None:
print("Error: Could not load hello_iso_gb.png")
return
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h, w = gray.shape
# Create a markup copy of the image
markup = img.copy()
# We want to detect the rendering glitches (black V-shapes or gaps cutting into the floor tiles)
# The floor tiles are White (255) and Light Gray (153) with Dark Gray (85) lines.
# The empty background is Black (0).
# Inside the walkable path, any Black (0) pixel that is surrounded by floor tile colors
# represents a cutout glitch.
# Let's use morphological operations to find these black cutouts inside the tiles.
# Threshold to find floor tiles (value > 50, so anything not black)
_, floor_mask = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY)
# Invert to find black pixels
black_mask = cv2.bitwise_not(floor_mask)
# Find contours of the black regions
contours, _ = cv2.findContours(black_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
glitch_count = 0
for cnt in contours:
x, y, rw, rh = cv2.boundingRect(cnt)
# The screen border is black, so we ignore black regions touching the screen boundaries
if x <= 2 or y <= 2 or (x + rw) >= w - 2 or (y + rh) >= h - 2:
continue
# Glitches are small black gaps/triangles. Typically small (e.g. area between 4 and 40 pixels)
area = cv2.contourArea(cnt)
if 2 <= area <= 50:
# Check if it's inside the checkerboard area
# (which is roughly centered on the screen)
cv2.rectangle(markup, (x, y), (x + rw, y + rh), (0, 0, 255), 1) # Red box
glitch_count += 1
print(f"Detected {glitch_count} rendering glitches (black cutouts/gaps) inside the floor map.")
# Save the marked-up image to the artifacts directory
output_path = '/home/enne2/.gemini/antigravity-ide/brain/eebf5acd-ae2e-41bb-858e-6a4a5ca41897/analyzed_tiles.png'
cv2.imwrite(output_path, markup)
print(f"Saved analysis markup to: {output_path}")
if __name__ == '__main__':
main()

30
opencv_check_centering.py

@ -0,0 +1,30 @@
import cv2
import numpy as np
def main():
img = cv2.imread('hello_iso_gb.png')
if img is None:
print("Error: Could not load hello_iso_gb.png")
return
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h, w = gray.shape
print(f"Image dimensions: {w}x{h}")
# Print all unique gray values on screen
unique_vals = np.unique(gray)
print(f"Unique gray values: {unique_vals}")
# Find all contours in the image
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("\nAll non-trivial contours:")
for idx, cnt in enumerate(contours):
x, y, rw, rh = cv2.boundingRect(cnt)
area = cv2.contourArea(cnt)
# Filter out screen-sized or tiny noise contours
if 4 <= area <= 10000:
print(f"Contour {idx}: x={x}, y={y}, w={rw}, h={rh}, area={area}, center=({x + rw/2}, {y + rh/2})")
if __name__ == '__main__':
main()

102
player.c

@ -0,0 +1,102 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: player.png -c player.c -sw 16 -sh 16 -bpp 2 -noflip -keep_palette_order
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
BANKREF(player)
const palette_color_t player_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 player_tiles[448] = {
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x09,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x06,0x06,0x06,0x06,0x0e,0x0e,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x50,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x60,0x60,0x60,0x60,0x70,0x70,0x00,0x00,
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x09,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x06,0x06,0x0c,0x0c,0x1c,0x1c,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x50,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x10,0x10,0x18,0x18,0x1c,0x1c,0x00,0x00,
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x0a,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x06,0x06,0x06,0x06,0x0e,0x0e,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x90,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x60,0x60,0x60,0x60,0x70,0x70,0x00,0x00,
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x0a,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x08,0x08,0x18,0x18,0x38,0x38,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x90,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x60,0x60,0x30,0x30,0x38,0x38,0x00,0x00,
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x08,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x06,0x06,0x06,0x06,0x0e,0x0e,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x10,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x60,0x60,0x60,0x60,0x70,0x70,0x00,0x00,
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x08,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x08,0x08,0x18,0x18,0x38,0x38,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x10,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x60,0x60,0x30,0x30,0x38,0x38,0x00,0x00,
0x00,0x00,0x03,0x03,0x07,0x04,0x0f,0x08,0x0f,0x08,0x07,0x04,0x03,0x03,0x04,0x07,
0x0c,0x0b,0x0c,0x0b,0x04,0x07,0x03,0x03,0x06,0x06,0x0c,0x0c,0x1c,0x1c,0x00,0x00,
0x00,0x00,0xc0,0xc0,0xe0,0x20,0xf0,0x10,0xf0,0x10,0xe0,0x20,0xc0,0xc0,0x20,0xe0,
0x30,0xd0,0x30,0xd0,0x20,0xe0,0xc0,0xc0,0x10,0x10,0x18,0x18,0x1c,0x1c,0x00,0x00
};
const metasprite_t player_metasprite0[] = {
METASPR_ITEM(-8, -8, 0, S_PAL(0)),
METASPR_ITEM(0, 8, 2, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite1[] = {
METASPR_ITEM(-8, -8, 4, S_PAL(0)),
METASPR_ITEM(0, 8, 6, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite2[] = {
METASPR_ITEM(-8, -8, 8, S_PAL(0)),
METASPR_ITEM(0, 8, 10, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite3[] = {
METASPR_ITEM(-8, -8, 12, S_PAL(0)),
METASPR_ITEM(0, 8, 14, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite4[] = {
METASPR_ITEM(-8, -8, 16, S_PAL(0)),
METASPR_ITEM(0, 8, 18, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite5[] = {
METASPR_ITEM(-8, -8, 20, S_PAL(0)),
METASPR_ITEM(0, 8, 22, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite6[] = {
METASPR_ITEM(-8, -8, 16, S_PAL(0)),
METASPR_ITEM(0, 8, 18, S_PAL(0)),
METASPR_TERM
};
const metasprite_t player_metasprite7[] = {
METASPR_ITEM(-8, -8, 24, S_PAL(0)),
METASPR_ITEM(0, 8, 26, S_PAL(0)),
METASPR_TERM
};
const metasprite_t* const player_metasprites[8] = {
player_metasprite0, player_metasprite1, player_metasprite2, player_metasprite3, player_metasprite4, player_metasprite5, player_metasprite6, player_metasprite7
};

31
player.h

@ -0,0 +1,31 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: player.png -c player.c -sw 16 -sh 16 -bpp 2 -noflip -keep_palette_order
#ifndef METASPRITE_player_H
#define METASPRITE_player_H
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
#define player_TILE_ORIGIN 0
#define player_TILE_W 8
#define player_TILE_H 16
#define player_WIDTH 16
#define player_HEIGHT 16
#define player_TILE_COUNT 28
#define player_PALETTE_COUNT 8
#define player_COLORS_PER_PALETTE 4
#define player_TOTAL_COLORS 32
#define player_PIVOT_X 8
#define player_PIVOT_Y 8
#define player_PIVOT_W 16
#define player_PIVOT_H 16
extern const metasprite_t* const player_metasprites[8];
BANKREF_EXTERN(player)
extern const palette_color_t player_palettes[32];
extern const uint8_t player_tiles[448];
#endif

BIN
player.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

59
test_movement.py

@ -0,0 +1,59 @@
from pyboy import PyBoy
from pyboy.utils import WindowEvent
def main():
pyboy = PyBoy('hello_iso.gb', window='null', cgb=False)
# Let the game boot and generate the maze
for _ in range(60 * 2):
pyboy.tick()
# Read player position from RAM
# player_lx at 0xC4E8, player_ly at 0xC4E9
lx = pyboy.memory[0xC4E8]
ly = pyboy.memory[0xC4E9]
print(f"Initial player coordinates in RAM: lx={lx}, ly={ly}")
# Read maze array from RAM (7x7 starting at 0xC0B1)
maze = []
for y in range(7):
row = []
for x in range(7):
val = pyboy.memory[0xC0B1 + y * 7 + x]
row.append(val)
maze.append(row)
print("\nMaze layout in RAM (0=wall, 1=path):")
for y, row in enumerate(maze):
row_str = f"{y:02d}: "
for x, val in enumerate(row):
if x == lx and y == ly:
row_str += "P" # Player
else:
row_str += str(val)
print(row_str)
# Check neighbors of player
print(f"\nPlayer neighbors: Up={maze[ly-1][lx]}, Down={maze[ly+1][lx]}, Left={maze[ly][lx-1]}, Right={maze[ly][lx+1]}")
# Try pressing Down (Down-Left)
print("\nSimulating pressing DOWN...")
pyboy.send_input(WindowEvent.PRESS_ARROW_DOWN)
pyboy.tick()
pyboy.send_input(WindowEvent.RELEASE_ARROW_DOWN)
for _ in range(30):
pyboy.tick()
print(f"Player coordinates after DOWN: lx={pyboy.memory[0xC4E8]}, ly={pyboy.memory[0xC4E9]}")
# Try pressing Right (Down-Right)
print("\nSimulating pressing RIGHT...")
pyboy.send_input(WindowEvent.PRESS_ARROW_RIGHT)
pyboy.tick()
pyboy.send_input(WindowEvent.RELEASE_ARROW_RIGHT)
for _ in range(30):
pyboy.tick()
print(f"Player coordinates after RIGHT: lx={pyboy.memory[0xC4E8]}, ly={pyboy.memory[0xC4E9]}")
pyboy.stop()
if __name__ == "__main__":
main()

14
test_pyboy.py

@ -0,0 +1,14 @@
from pyboy import PyBoy
def main():
pyboy = PyBoy('hello_iso.gb', window='null', cgb=False)
# Tick a few frames to let the map render
for _ in range(60 * 2):
pyboy.tick()
pyboy.screen.image.save('hello_iso_gb.png')
pyboy.stop()
print("Screenshot saved to hello_iso_gb.png")
if __name__ == "__main__":
main()

124
tiles.c

@ -0,0 +1,124 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: tiles.png -c tiles.c -map -bpp 2 -noflip -keep_palette_order
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
BANKREF(tiles)
const palette_color_t tiles_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 tiles_tiles[528] = {
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,0xf8,0xfe,0xe0,0xf8,0x80,0xe3,
0xfe,0xff,0xf8,0xfe,0xe0,0xf8,0x80,0xe0,0x00,0x83,0x03,0x1c,0x1f,0x60,0x7f,0x80,
0x7f,0xff,0x1f,0x7f,0x07,0x1f,0x01,0x07,0x00,0x81,0x80,0x78,0xf8,0x07,0xff,0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0x0f,0x3f,0x03,0x8f,0x80,0x73,
0x01,0xce,0xc0,0xf1,0xf0,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0x00,0x1f,0xe0,0x01,0x1e,0x00,0x81,0x80,0xe0,0xe0,0xf8,0xf8,0xfe,0xfe,0xff,
0xfe,0x01,0xf8,0x06,0xc0,0x38,0x00,0xc1,0x01,0x07,0x07,0x1f,0x1f,0x7f,0x7f,0xff,
0x01,0xc7,0x07,0x1f,0x1f,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xfe,0x01,0xf8,0x06,0xe0,0x18,0x80,0x63,
0xfe,0x01,0xf8,0x06,0xe0,0x18,0x80,0x60,0x00,0x83,0x03,0x1c,0x1f,0x60,0x7f,0x80,
0x7f,0x80,0x1f,0x60,0x07,0x18,0x01,0x06,0x00,0x81,0x80,0x78,0xf8,0x07,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x3f,0xc0,0x0f,0x30,0x03,0x8c,0x80,0x73,
0x01,0xce,0xc0,0x31,0xf0,0x0c,0xfc,0x03,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0x1f,0xe0,0x01,0x1e,0x00,0x81,0x80,0x60,0xe0,0x18,0xf8,0x06,0xfe,0x01,
0xfe,0x01,0xf8,0x06,0xc0,0x38,0x00,0xc1,0x01,0x06,0x07,0x18,0x1f,0x60,0x7f,0x80,
0x01,0xc6,0x07,0x18,0x1f,0x60,0x7f,0x80,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xf9,0xfe,0xe7,0xf8,0x9c,0xe3,
0xfe,0xff,0xf9,0xfe,0xe7,0xf8,0x9f,0xe0,0x7c,0x83,0xe0,0x1c,0x80,0x60,0x00,0x80,
0x7f,0xff,0x9f,0x7f,0xe7,0x1f,0xf9,0x07,0x7e,0x81,0x07,0x78,0x00,0x07,0x00,0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xcf,0x3f,0x73,0x8f,0x0c,0x73,
0x30,0xce,0xce,0xf1,0xf3,0xfc,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0xe0,0xe0,0x1e,0x7e,0x81,0x9f,0xe0,0xe7,0xf8,0xf9,0xfe,0xfe,0xff,
0x00,0x01,0x01,0x06,0x07,0x38,0x3e,0xc1,0xf9,0x07,0xe7,0x1f,0x9f,0x7f,0x7f,0xff,
0x39,0xc7,0xe7,0x1f,0x9f,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x06,0x07,0x18,0x1c,0x63,
0x00,0x01,0x01,0x06,0x07,0x18,0x1f,0x60,0x7c,0x83,0xe0,0x1c,0x80,0x60,0x00,0x80,
0x00,0x80,0x80,0x60,0xe0,0x18,0xf8,0x06,0x7e,0x81,0x07,0x78,0x00,0x07,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x30,0x70,0x8c,0x0c,0x73,
0x30,0xce,0x0e,0x31,0x03,0x0c,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xe0,0xe0,0x1e,0x7e,0x81,0x1f,0x60,0x07,0x18,0x01,0x06,0x00,0x01,
0x00,0x01,0x01,0x06,0x07,0x38,0x3e,0xc1,0xf8,0x06,0xe0,0x18,0x80,0x60,0x00,0x80,
0x38,0xc6,0xe0,0x18,0x80,0x60,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
const unsigned char tiles_map[260] = {
0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,
0x05,0x06,0x07,0x08,
0x09,0x0a,0x03,0x04,
0x05,0x06,0x07,0x08,
0x01,0x02,0x0b,0x0c,
0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,
0x05,0x06,0x07,0x08,
0x01,0x02,0x03,0x04,
0x0d,0x0e,0x07,0x08,
0x09,0x0a,0x03,0x04,
0x0d,0x0e,0x07,0x08,
0x01,0x02,0x0b,0x0c,
0x0d,0x0e,0x07,0x08,
0x09,0x0a,0x0b,0x0c,
0x0d,0x0e,0x07,0x08,
0x01,0x02,0x03,0x04,
0x05,0x06,0x0f,0x10,
0x09,0x0a,0x03,0x04,
0x05,0x06,0x0f,0x10,
0x01,0x02,0x0b,0x0c,
0x05,0x06,0x0f,0x10,
0x09,0x0a,0x0b,0x0c,
0x05,0x06,0x0f,0x10,
0x01,0x02,0x03,0x04,
0x0d,0x0e,0x0f,0x10,
0x09,0x0a,0x03,0x04,
0x0d,0x0e,0x0f,0x10,
0x01,0x02,0x0b,0x0c,
0x0d,0x0e,0x0f,0x10,
0x09,0x0a,0x0b,0x0c,
0x0d,0x0e,0x0f,0x10,
0x11,0x12,0x13,0x14,
0x15,0x16,0x17,0x18,
0x19,0x1a,0x13,0x14,
0x15,0x16,0x17,0x18,
0x11,0x12,0x1b,0x1c,
0x15,0x16,0x17,0x18,
0x19,0x1a,0x1b,0x1c,
0x15,0x16,0x17,0x18,
0x11,0x12,0x13,0x14,
0x1d,0x1e,0x17,0x18,
0x19,0x1a,0x13,0x14,
0x1d,0x1e,0x17,0x18,
0x11,0x12,0x1b,0x1c,
0x1d,0x1e,0x17,0x18,
0x19,0x1a,0x1b,0x1c,
0x1d,0x1e,0x17,0x18,
0x11,0x12,0x13,0x14,
0x15,0x16,0x1f,0x20,
0x19,0x1a,0x13,0x14,
0x15,0x16,0x1f,0x20,
0x11,0x12,0x1b,0x1c,
0x15,0x16,0x1f,0x20,
0x19,0x1a,0x1b,0x1c,
0x15,0x16,0x1f,0x20,
0x11,0x12,0x13,0x14,
0x1d,0x1e,0x1f,0x20,
0x19,0x1a,0x13,0x14,
0x1d,0x1e,0x1f,0x20,
0x11,0x12,0x1b,0x1c,
0x1d,0x1e,0x1f,0x20,
0x19,0x1a,0x1b,0x1c,
0x1d,0x1e,0x1f,0x20,
};

29
tiles.h

@ -0,0 +1,29 @@
//AUTOGENERATED FILE FROM png2asset
// Conversion args: tiles.png -c tiles.c -map -bpp 2 -noflip -keep_palette_order
#ifndef METASPRITE_tiles_H
#define METASPRITE_tiles_H
#include <stdint.h>
#include <gbdk/platform.h>
#include <gbdk/metasprites.h>
#define tiles_TILE_ORIGIN 0
#define tiles_TILE_W 8
#define tiles_TILE_H 8
#define tiles_WIDTH 32
#define tiles_HEIGHT 520
#define tiles_TILE_COUNT 33
#define tiles_PALETTE_COUNT 8
#define tiles_COLORS_PER_PALETTE 4
#define tiles_TOTAL_COLORS 32
#define tiles_MAP_ATTRIBUTES 0
extern const unsigned char tiles_map[260];
#define tiles_map_attributes tiles_map
BANKREF_EXTERN(tiles)
extern const palette_color_t tiles_palettes[32];
extern const uint8_t tiles_tiles[528];
#endif

BIN
tiles.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Loading…
Cancel
Save