#!/usr/bin/env python3 """Prepara i fotogrammi di un personaggio (già ritagliati da slice_sprites.py) per il motore. python3 tools/slice_sprites.py --sheet assets/raw/andrea-sheet.png --out /tmp/andrea --cols 4 --rows 2 \ --despill --names walk_1,walk_2,walk_3,walk_4,stand,talk,take,back --prefix andrea_ python3 tools/prepare_character.py /tmp/andrea andrea assets/characters --height 120 Tutti i fotogrammi vengono ridotti con lo stesso fattore (l'altezza del fotogramma `stand` diventa --height) e salvati in un'unica striscia PNG. Il JSON accanto dice per ogni fotogramma dove sta nella striscia e dove sono i piedi: x è il centro del busto (la parte alta del corpo, che in una camminata resta ferma), y la base. """ import argparse import json from pathlib import Path from PIL import Image FRAMES = ['walk_1', 'walk_2', 'walk_3', 'walk_4', 'stand', 'talk', 'take', 'back'] def torso_center(im): """Centro orizzontale dei pixel opachi nel 40% alto della figura (testa e spalle).""" alpha = im.getchannel('A') l, t, r, b = alpha.getbbox() limit = t + (b - t) * 0.4 xs = [x for y in range(t, int(limit)) for x in range(l, r) if alpha.getpixel((x, y)) > 128] return sum(xs) / len(xs), b def main(): p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) p.add_argument('src', help='cartella con _.png') p.add_argument('name') p.add_argument('out') p.add_argument('--height', type=int, default=120) a = p.parse_args() frames = {f: Image.open(Path(a.src) / f'{a.name}_{f}.png').convert('RGBA') for f in FRAMES} stand = frames['stand'] factor = a.height / (stand.getchannel('A').getbbox()[3] - stand.getchannel('A').getbbox()[1]) strip, meta, x = [], {}, 0 for f, im in frames.items(): im = im.crop(im.getchannel('A').getbbox()) cx, base = torso_center(im) w, h = max(1, round(im.width * factor)), max(1, round(im.height * factor)) im = im.resize((w, h), Image.LANCZOS) strip.append(im) meta[f] = {'x': x, 'y': 0, 'w': w, 'h': h, 'ax': round(cx * factor, 1), 'ay': h} x += w + 2 sheet = Image.new('RGBA', (x, max(im.height for im in strip)), (0, 0, 0, 0)) for im, m in zip(strip, meta.values()): sheet.paste(im, (m['x'], 0)) out = Path(a.out) out.mkdir(parents=True, exist_ok=True) sheet.save(out / f'{a.name}.png', optimize=True) (out / f'{a.name}.json').write_text(json.dumps({'image': f'{a.name}.png', 'height': a.height, 'frames': meta}, indent=1) + '\n') print(f'{out / a.name}.png: {sheet.width}x{sheet.height}, {len(meta)} fotogrammi') if __name__ == '__main__': main()