Files
SoundGame/app/src/escape/gen/gen_cover.py
T
SoundGame Dev f0f0a9b50e 初始提交:3 款纯音频游戏 + 共享引擎 + 完整文档与资产管线
- 共享引擎(app/src/main):GestureEngine 6 手势识别、AudioEngine 三层音频
  (ExoPlayer BGM 交叉淡入 / 对白 ducking / SoundPool 低延迟)、Game/GameEngine
  状态机接口、MainActivity 全屏封面 + TalkBack
- 《声命线》storyline:末世互动广播剧,3 幕 8 抉择点 4 结局
- 《声东击西》reflex:听声辨位反应,12 波战斗 + BGM 三档 BPM 变速
- 《暗室》escape:3x3 网格密室逃脱,钥匙→铁柜→保险丝→电箱→大门谜题链
- 文档:setup(从零搭建)/ architecture(架构)/ engine-api(引擎 API)/
  asset-pipeline(资产流水线)/ games/*(三款游戏设计文档)
- 资产管线:Qwen3-TTS 对白 + 程序合成音效/BGM + Mureka BGM 的 gen 脚本与台账,
  全部 ogg 资产入库可复现
- env.d 环境脚本:android/tts 入库;sfx/mureka 含密钥不入库,仅提交 .example.sh 模板
2026-08-29 13:00:34 +08:00

71 lines
2.4 KiB
Python

# -*- coding: utf-8 -*-
"""《暗室》封面图:1080x1920 深色底 + 标题大字 + 手势提示。"""
import os
from PIL import Image, ImageDraw, ImageFont, ImageFilter
BASE = os.path.dirname(os.path.abspath(__file__))
FONT = os.path.join(BASE, "font.otf")
OUT = os.path.join(BASE, "..", "res", "drawable", "cover.png")
W, H = 1080, 1920
img = Image.new("RGB", (W, H))
d = ImageDraw.Draw(img)
# 深色径向渐变底(中心略亮的深蓝黑)
cx, cy = W / 2, H * 0.42
for y in range(H):
for_x = None
img = Image.new("RGB", (W, H))
px = img.load()
for y in range(H):
for x in range(W):
dist = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5 / (W * 0.75)
v = max(0.0, 1.0 - dist)
px[x, y] = (int(8 + 18 * v), int(10 + 22 * v), int(16 + 34 * v))
d = ImageDraw.Draw(img)
# 门框剪影(一道微开的门缝透光)
door_w, door_h = 420, 760
dx0, dy0 = (W - door_w) // 2, int(H * 0.30)
d.rectangle([dx0, dy0, dx0 + door_w, dy0 + door_h], outline=(60, 70, 95), width=10)
slit_x = dx0 + door_w - 46
d.rectangle([slit_x, dy0 + 12, slit_x + 18, dy0 + door_h - 12], fill=(220, 230, 200))
glow = Image.new("RGBA", (W, H), (0, 0, 0, 0))
gd = ImageDraw.Draw(glow)
gd.rectangle([slit_x - 60, dy0, slit_x + 80, dy0 + door_h], fill=(200, 215, 170, 60))
glow = glow.filter(ImageFilter.GaussianBlur(40))
img = Image.alpha_composite(img.convert("RGBA"), glow).convert("RGB")
d = ImageDraw.Draw(img)
d.rectangle([slit_x, dy0 + 12, slit_x + 18, dy0 + door_h - 12], fill=(235, 242, 210))
# 标题
f_title = ImageFont.truetype(FONT, 230)
f_sub = ImageFont.truetype(FONT, 46)
f_hint = ImageFont.truetype(FONT, 40)
title = "暗 室"
bb = d.textbbox((0, 0), title, font=f_title)
tw = bb[2] - bb[0]
d.text(((W - tw) / 2, H * 0.11), title, font=f_title, fill=(225, 228, 235))
sub = "纯 音 频 密 室 逃 脱"
bb = d.textbbox((0, 0), sub, font=f_sub)
d.text(((W - (bb[2] - bb[0])) / 2, H * 0.275), sub, font=f_sub, fill=(130, 140, 160))
# 手势提示
hints = ["四 向 滑 动 · 移 动", "单 击 · 检 查 双 击 · 使 用"]
yy = H * 0.78
for line in hints:
bb = d.textbbox((0, 0), line, font=f_hint)
d.text(((W - (bb[2] - bb[0])) / 2, yy), line, font=f_hint, fill=(150, 158, 175))
yy += 78
tip = "请 佩 戴 耳 机 游 玩"
bb = d.textbbox((0, 0), tip, font=f_sub)
d.text(((W - (bb[2] - bb[0])) / 2, H * 0.92), tip, font=f_sub, fill=(100, 108, 128))
img.save(OUT)
print("saved", os.path.abspath(OUT), img.size)