ys2-intro/assets/ys2/09_island_scroller_vertical_todo/tilemap_tool2.py

136 lines
3.6 KiB
Python
Raw Normal View History

2025-11-15 07:09:41 -05:00
from PIL import Image
import csv
import sys
import os
TILE_W = 8
TILE_H = 8
TILES_PER_ROW = 24 # because 24 tiles * 8 px = 192 px rows in the map
def load_tileset(path):
tileset = Image.open(path).convert("RGBA")
ts_w, ts_h = tileset.size
tiles_x = ts_w // TILE_W
tiles_y = ts_h // TILE_H
tiles = []
for ty in range(tiles_y):
for tx in range(tiles_x):
tile = tileset.crop((
tx * TILE_W,
ty * TILE_H,
tx * TILE_W + TILE_W,
ty * TILE_H + TILE_H
))
tiles.append(tile)
print(f"Tileset loaded: {len(tiles)} tiles ({tiles_x}×{tiles_y})")
return tiles
def find_tile_index(block, tiles):
"""Return index of tile in tiles[] or raise error if not found."""
for i, t in enumerate(tiles):
if list(block.getdata()) == list(t.getdata()):
print(f"Made {i}, {t}")
return i
raise ValueError("Tile not found in tileset!")
def build_csv_from_image(src_path, tileset_path, csv_out):
img = Image.open(src_path).convert("RGBA")
w, h = img.size
tiles = load_tileset(tileset_path)
# Must be aligned
if w % TILE_W != 0 or h % TILE_H != 0:
raise ValueError("Image dimensions must be multiples of 8.")
map_w = w // TILE_W
map_h = h // TILE_H
print(f"Building CSV: {map_w}×{map_h} tiles")
rows = []
tile_indices = []
# Scan image in 8×8 blocks
for ty in range(map_h):
row_tiles = []
for tx in range(map_w):
block = img.crop((
tx * TILE_W,
ty * TILE_H,
tx * TILE_W + TILE_W,
ty * TILE_H + TILE_H
))
idx = find_tile_index(block, tiles)
row_tiles.append(idx)
tile_indices.append(row_tiles)
# Output CSV with line breaks after 24 tiles
with open(csv_out, "w", newline="") as f:
writer = csv.writer(f)
for row in tile_indices:
# 24-tile chunks
for i in range(0, len(row), TILES_PER_ROW):
writer.writerow(row[i:i + TILES_PER_ROW])
print(f"CSV written to {csv_out}")
def build_png_from_csv(csv_path, tileset_path, out_path):
tiles = load_tileset(tileset_path)
# Read CSV
tile_rows = []
with open(csv_path, newline="") as f:
reader = csv.reader(f)
for row in reader:
if row:
tile_rows.append([int(v) for v in row])
height_blocks = len(tile_rows)
width_blocks = len(tile_rows[0])
out_w = width_blocks * TILE_W
out_h = height_blocks * TILE_H
out_img = Image.new("RGBA", (out_w, out_h))
print(f"Reconstructing {out_w}×{out_h} image")
for ty, row in enumerate(tile_rows):
for tx, tile_index in enumerate(row):
tile = tiles[tile_index]
out_img.paste(tile, (tx * TILE_W, ty * TILE_H))
out_img.save(out_path)
print(f"Reconstructed PNG saved to {out_path}")
# -----------------------------------------------------------------------
# Command-line wrapper
# -----------------------------------------------------------------------
if __name__ == "__main__":
if len(sys.argv) < 5:
print("Usage:")
print(" python build_tilemap.py makemap <tileset.png> <image.png> <out.csv>")
print(" python build_tilemap.py makepng <tileset.png> <in.csv> <out.png>")
sys.exit(1)
mode = sys.argv[1].lower()
tile = sys.argv[2]
a = sys.argv[3]
b = sys.argv[4]
if mode == "makemap":
build_csv_from_image(a, tile, b)
elif mode == "makepng":
build_png_from_csv(a, tile, b)
else:
print("Unknown mode.")