Files

6.8 KiB
Raw Permalink Blame History

name, description
name description
shmup-player-sprite 竖版射击游戏主角机三帧精灵(平飞/左滚转/右滚转)生产流水线。Use when 生成或调整玩家机 sprite、shmup aircraft sprite、bank/roll 滚转侧身帧、调试飞机贴图滚转效果、或为 1942 式竖版射击游戏制作新机型的三帧美术。关键词:主角机、玩家飞机、滚转身、bank frames、P-38、雷光、plane_funnel。

竖版主角机三帧精灵生产流水线

为本项目(1942 式竖版射击)生产主角机三帧动画精灵:平飞基准帧 + 左/右滚转帧。

核心思路:AI 只负责生成一张严格对称的平飞基准图;滚转帧用高度图浮雕投影确定性推导,避免 AI 生图的不可控性。

工具位置

流水线脚本在本项目 tools/gen_plane_sprites.py(git 跟踪,单一数据源)。机型档案在 tools/profiles/*.json(内置 p38,另有 plane_funnel)。

迁移到其他项目:把 tools/gen_plane_sprites.py 拷过去,参照脚本内 BUILTIN_PROFILES["p38"] 写新机型的 JSON profile 即可。

快速开始

# 密钥:环境变量 APIYI_API_KEY,或 tools/.apikey(已 gitignore,勿提交)

# 1. 生成基准图(唯一需要 AI 的一步)
python tools/gen_plane_sprites.py --profile tools/profiles/<机型>.json base
python tools/gen_plane_sprites.py check assets/raw/<name>-base.png --symmetry   # 对称度应 >95%

# 2. 确定性生成左右滚转帧(零 API)
python tools/gen_plane_sprites.py --profile tools/profiles/<机型>.json relief

# 3. 裁边 + 统一缩放 + 居中落地 assets/art/
python tools/gen_plane_sprites.py --profile tools/profiles/<机型>.json process

# 4. 校验三帧后 godot --import
python tools/gen_plane_sprites.py check assets/art/<name>.png

几何模型(理解一切的基础)

滚转侧身帧的正确语义:飞机不动,相机在飞机 Up-Right 平面内从正上方移到右上方 θ 角处(等距、看向机心)。正交投影下:

x' = x·cosθ − h·sinθ      y' = y

三个视觉后果,缺一不可:

  1. 翼展按 cosθ 压缩——整机变窄,纵向(机头到机尾)长度不变
  2. 有高度的部件向画面左移 h·sinθ(θ=45° 时座舱盖偏移 ≈ 高度的 0.7 倍)
  3. 朝向相机的侧面露出——机身/发动机舱右缘出现一条暗色侧面带

反面辨析:只压缩(无侧面露出)看起来仍是正俯视;机翼一高一低(2D 斜切)是"相机自己 roll",不是相机移动。

关键步骤与校验标准

1. base — AI 文生图基准帧

Prompt 四个硬约束,少一个都不行:

  • 正俯视("Top-down view, seen from directly above")
  • 严格左右对称("PERFECTLY LEFT-RIGHT SYMMETRIC")——对称是 relief 高度图正确的前提,也便于镜像出右滚转帧
  • 机头正上("nose pointing STRAIGHT UP")
  • 透明背景(gpt-image-1 原生支持 background: "transparent")

校验:check --symmetry,对称度 >95%、四角 alpha=0 才放行。不合格重新生成,不要带伤进入下一步。

2. relief — 高度图浮雕投影(推荐,确定性)

零 API,从基准图严格推导:

  1. 高度图 = 剪影距离变换(chamfer distance transform):管状结构(机身/发动机舱/尾撑)自动获得圆顶高度,薄结构(机翼/尾翼)自动低平——无需手绘高度图
  2. 逐像素投影 x' = x·cosθ − h·sinθ:陡坡(朝相机的侧面)被行内拉伸,缝隙用加暗色填充 → 新侧面露出;背侧坡压缩覆盖
  3. 右滚转帧 = 左帧水平镜像,两侧严格对称

调参旋钮(profile 的 relief 节,或 CLI --angle/--height/--side-dark 覆盖):

参数 p38 默认 作用
angle 45 相机偏角。越大翼展越窄、侧面越宽;48px 精灵建议 30-45
height 48 机身最大高度(原始图像素)。控制座舱/机脊的横向位移量
side_dark 0.4 露出侧面的最大暗度(0-1)
slope_th 0.3 高度梯度阈值,超过才视为侧面加暗;调低则机翼边缘也带暗面

3. process — 裁边缩放落地

统一缩放系数是隐藏的关键约束:以基准图外接框算出 scale = min(W/bw, H/bh),三帧共用。各帧独立缩放会导致同一架飞机跨帧纵向尺寸不一致(视觉上尾翼"离机身更远")。机身纵向长度是滚转不变量,必须跨帧锁定。

备选:bank — AI 图生图滚转帧

如果一定要 AI 重绘滚转帧(追求真实光影细节),prompt 纪律:

  • 直接描述飞机姿态("banking LEFT at 20°, left wing lower, right side sliver visible"),绝不描述相机移动("camera moved" 会被画成前视 3/4 插画)
  • 显式钉死:机头正上、机身竖直、翼尖同高、整机完整(枚举 bank_parts 所有部件)、螺旋桨机加"螺旋桨侧视不翻脸"(profile 的 propellers: true,喷气机设 false)
  • 生成后用 align 校正朝向(模板匹配 ±90° 搜索;不行就 align --rotate <度数> 手动)
  • 不要用二阶矩主轴法找角度——滚转的机翼会带偏主轴

踩坑记录(血泪教训)

坑 现象 解法
文生图直接说 "bank/roll" 模型自由发挥:机翼消失、整机画斜 基准帧只生成平飞;滚转交给 relief
prompt 描述相机移动 画成前视 3/4 插画(螺旋桨翻脸) 描述飞机姿态,不提相机
垂直剪切(shear)模拟滚转 飞机被拉斜,2D 平面感 那是相机自旋,几何错误
只水平压缩(无侧面) 仍是正俯视,无滚转感 必须有高度驱动的侧面露出
逐帧独立缩放 尾翼看似离机身更远 统一缩放系数(锚定基准图)
半分辨率高度图直接采样 机翼出现 2×2 方块暗纹 高度图双线性升回全分辨率再采样
陡坡均匀压暗 机身整体发暗发糊 渐变加暗:脊线亮→边缘暗,且仅陡坡

产物约定

assets/raw/{name}-base.png         AI 原始基准图(保留,勿删——relief 的输入)
assets/raw/{name}-bank-left.png    滚转帧原始图
assets/raw/{name}-bank-right.png
assets/art/{name}.png              最终三帧(48×56 或 profile 指定尺寸)
assets/art/{name}-bank-left.png
assets/art/{name}-bank-right.png

游戏侧接线约定(本项目 scripts/player.gd 已实现):三帧贴图切换 + 迟滞阈值(进入 0.45 / 退出 0.25),缺图回退平飞帧;滚转帧不做代码旋转/缩放变换。

环境依赖

  • Python 3.10+,Pillow(仅标准库 + PIL,无 numpy/scipy)
  • AI 步骤(仅 base / bank)需要 OpenAI 兼容图像接口(默认 apiyi,gpt-image-1)
  • 密钥:APIYI_API_KEY 环境变量,或 tools/.apikey(必须 gitignore)