examples/rpgwalk: 8 RPG-персонажей ходят по травяному полю
Демо на реальном арте (third_party/16x16-RPG-characters, bard): conv_sprites.py режет PNG 192×128 (8 персонажей = блоки 3×4 кадров: ряды вниз/влево/вправо/вверх × кадры маятника 0/1/2) в 8 вертикальных лент по 12 кадров и строит bard.pal (слоты 0-15 EGA + цвета PNG с 16, прозрачность → 0xFF). 8×12 кадров не лезут в одну EMM-страницу — ДВА атласа по 4 персонажа (движок сам переключает страницы W0). Палитра из файла: gfx_pal_fload + gfx_pal_sync. Смена направления = sprite_anim(dir*3, dir*3+2, PINGPONG). Правила хождения (двухфазная машина на sprite_moveto): до края → разворот 180° → случайная точка (не меньше четверти экрана) → поворот ±90° → снова до края. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Конвертер third_party/16x16-RPG-characters (02-bard.png) → ленты
|
||||
атласа + палитра для examples/rpgwalk.
|
||||
|
||||
Источник: RGBA 192×128 = 8 рядов × 12 картинок 16×16; персонаж =
|
||||
блок 3×4 (4 блока в ряду, 2 ряда блоков = 8 персонажей):
|
||||
строка блока 0 — идёт ВНИЗ (на нас), кадры 0/1/2 (маятник);
|
||||
строка 1 — ВЛЕВО; строка 2 — ВПРАВО; строка 3 — ВВЕРХ.
|
||||
|
||||
Выход:
|
||||
char0.raw..char7.raw — вертикальные ленты 16×192 (12 кадров:
|
||||
dir*3 + frame — sprite_anim(dir*3, dir*3+2, PINGPONG));
|
||||
bard.pal — палитра gfx_pal_fload: слоты 0..15 = EGA (как ставит
|
||||
initgraph, таблица из _bgi_mode_set), слоты 16.. = цвета PNG.
|
||||
Пиксели: прозрачное (alpha<128) → 0xFF, цвет → 16 + индекс.
|
||||
"""
|
||||
from PIL import Image
|
||||
|
||||
SRC = ("../../third_party/16x16-RPG-characters/sprites/"
|
||||
"old-style/02-bard.png")
|
||||
BASE = 16 # цвета PNG кладём после EGA-шестнадцати
|
||||
|
||||
# B, G, R, pad — как в libbgi/bgi256/_bgi_mode_set.c
|
||||
EGA = [
|
||||
(0, 0, 0), (168, 0, 0), (0, 168, 0), (168, 168, 0),
|
||||
(0, 0, 168), (168, 0, 168), (0, 84, 168), (168, 168, 168),
|
||||
(84, 84, 84), (255, 84, 84), (84, 255, 84), (255, 255, 84),
|
||||
(84, 84, 255), (255, 84, 255), (84, 255, 255), (255, 255, 255),
|
||||
]
|
||||
|
||||
im = Image.open(SRC).convert("RGBA")
|
||||
assert im.size == (192, 128), im.size
|
||||
|
||||
colors = {} # (r,g,b) -> палитровый индекс
|
||||
|
||||
|
||||
def px(x, y):
|
||||
r, g, b, a = im.getpixel((x, y))
|
||||
if a < 128:
|
||||
return 0xFF
|
||||
key = (r, g, b)
|
||||
if key not in colors:
|
||||
assert BASE + len(colors) < 0xFF, "палитра переполнена"
|
||||
colors[key] = BASE + len(colors)
|
||||
return colors[key]
|
||||
|
||||
|
||||
for c in range(8):
|
||||
bx, by = (c % 4) * 48, (c // 4) * 64
|
||||
data = bytearray()
|
||||
for d in range(4): # вниз/влево/вправо/вверх
|
||||
for f in range(3): # кадры маятника
|
||||
for y in range(16):
|
||||
for x in range(16):
|
||||
data.append(px(bx + f * 16 + x, by + d * 16 + y))
|
||||
open(f"char{c}.raw", "wb").write(data)
|
||||
|
||||
pal = bytearray()
|
||||
for b, g, r in EGA:
|
||||
pal += bytes((b, g, r, 0))
|
||||
for (r, g, b) in colors: # dict сохраняет порядок вставки
|
||||
pal += bytes((b, g, r, 0))
|
||||
open("bard.pal", "wb").write(pal)
|
||||
|
||||
print(f"conv_sprites: 8 лент 16x192, палитра EGA+{len(colors)} цветов "
|
||||
f"({len(pal)} Б)")
|
||||
Reference in New Issue
Block a user