diff --git a/design/art/samples/generate_hero_sample.py b/design/art/samples/generate_hero_sample.py new file mode 100644 index 00000000..e8a15757 --- /dev/null +++ b/design/art/samples/generate_hero_sample.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +""" +主角站姿像素画样例生成器 — Dungeon Sweeper +依据 design/art/art-bible.md: + - 小人蓝 #2E6E8E 主色(§4.1) / 亮色描边+落影底盘轮廓通道(§3.1) + - 3 头身候选档(§3.1 两档之一;终稿归 §5 角色批) + - 窄/直立/对称/凹凸≤2,剑收于剪影内(§3.1/§3.4) + - 不用红(危险专属)/金(收益专属)/紫赤 300-345° 禁入带(§4.2) +输出: hero-standing-pose.png (1x) + hero-standing-pose-preview.png (8x 四联测试条) +""" +from PIL import Image, ImageOps + +PAL = { + 'O': (255, 246, 224, 255), # 亮色描边(暖白) + 'b': (85, 144, 175, 255), # 蓝高光(小人蓝同族) + 'B': (46, 110, 142, 255), # 小人蓝 §4.1 + 'd': (31, 74, 96, 255), # 蓝暗部(同族) + 'S': (242, 199, 156, 255), # 肤色(暖) + 's': (214, 159, 108, 255), # 肤暗部 + 'E': (51, 38, 27, 255), # 数字墨(眼) §4.1 + 'T': (138, 90, 52, 255), # 皮革(木色族 §4.4) + 't': (92, 58, 30, 255), # 皮革暗部 + 'W': (183, 195, 203, 255), # 剑-钢 + 'w': (132, 147, 157, 255), # 剑-钢暗部 + 'G': (110, 91, 62, 255), # 落影底盘(暖深) +} + +# 左半 16 列(col 0..15),右半水平镜像;-figure 对称剪影 +LEFT = [ + "................", # 0 + "................", # 1 + "................", # 2 + ".............OOO", # 3 兜帽顶 + "............OBBB", # 4 + "...........Obbbb", # 5 + "...........ObbBB", # 6 + "...........ObBBB", # 7 + "...........OSSSS", # 8 额/脸顶(加宽脸窗) + "...........OSSES", # 9 + "...........OSSES", # 10 眼(下移一档更亲和) + "...........OSSSS", # 11 + "...........OSsss", # 12 下巴暗 + "...........Odddd", # 13 兜帽收底 + "..........Oddddd", # 14 肩起 + "..........OdBBBB", # 15 肩 + "..........OdBbbB", # 16 胸(中高光) + ".........OBBBbbB", # 17 臂现 + ".........OdTBbbB", # 18 臂+背带 + ".........OdTBbbB", # 19 + ".........OdTBbbB", # 20 + ".........OdTBbbB", # 21 + ".........OdTBbbB", # 22 + ".........OdTBbbB", # 23 + ".........OdTttTW", # 24 腰带+扣(2px 居中) + ".........OdTttTW", # 25 + ".........OdTTTTt", # 26 双手套握柄 + ".........OddBBBt", # 27 柄下 + ".........OBBOWWW", # 28 剑格 + ".........OBBBBBW", # 29 髋/剑身起 + "..........OdBddW", # 30 腿+剑 + "..........OdBddW", # 31 + "..........OdBddW", # 32 + "..........OdBddW", # 33 + "..........OdBddW", # 34 + "..........OdBddW", # 35 + "..........OdBddW", # 36 + "..........OTTttW", # 37 靴 + "..........OTTttW", # 38 + "..........OTTttW", # 39 + "..........OTTttW", # 40 + "..........OttttW", # 41 靴底 + "..............OW", # 42 剑尖 + "................", # 43 + ".........GGGGGGG", # 44 落影底盘 + "...........GGGGG", # 45 + "................", # 46 + "................", # 47 +] + +W, H = 32, 48 +grid = [['.'] * W for _ in range(H)] +for y, lft in enumerate(LEFT): + for x, ch in enumerate(lft): + grid[y][x] = ch + grid[y][W - 1 - x] = ch + +# 剑身右侧 1px 暗部(col 16),避免完全对称的死平 +for y in range(29, 42): + if grid[y][15] == 'W': + grid[y][16] = 'w' + + +def render(scale=1): + img = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + px = img.load() + for y in range(H): + for x in range(W): + c = PAL.get(grid[y][x]) + if c: + px[x, y] = c + return img.resize((W * scale, H * scale), Image.NEAREST) + + +def on_bg(img, color): + bg = Image.new('RGBA', img.size, color + (255,)) + bg.alpha_composite(img) + return bg + + +one_x = render(1) +one_x.save('hero-standing-pose.png') + +# 测试条: 掩尘底 / 裸土底 / 暗底 / 灰度(轮廓通道验证) +x8 = render(8) +tiles = [ + on_bg(x8, (201, 175, 131)), # 掩尘 #C9AF83 + on_bg(x8, (179, 154, 120)), # 裸土 #B39A78 + on_bg(x8, (46, 42, 38)), # 暗底对照 + ImageOps.grayscale(on_bg(x8, (201, 175, 131))).convert('RGBA'), +] +GAP = 24 +strip = Image.new('RGBA', + (len(tiles) * x8.width + (len(tiles) + 1) * GAP, x8.height + 2 * GAP), + (250, 244, 230, 255)) +for i, t in enumerate(tiles): + strip.alpha_composite(t, (GAP + i * (x8.width + GAP), GAP)) +strip.save('hero-standing-pose-preview.png') +print('done:', one_x.size, '->', strip.size) diff --git a/design/art/samples/hero-standing-pose-preview.png b/design/art/samples/hero-standing-pose-preview.png new file mode 100644 index 00000000..003a7343 Binary files /dev/null and b/design/art/samples/hero-standing-pose-preview.png differ diff --git a/design/art/samples/hero-standing-pose.png b/design/art/samples/hero-standing-pose.png new file mode 100644 index 00000000..cbf2ae70 Binary files /dev/null and b/design/art/samples/hero-standing-pose.png differ