Skip to content

Repository files navigation

糖泡堂 SugarBubble Arena v1.0.1

v1.0.1 修的 bug(都是实机反馈出来的)

现象 根因 修法
人物卡进墙里 走横向时会把角色向行中心"吸附"以便穿缝,但这个吸附没做碰撞检测,会把人挤进旁边的墙 吸附前检查迎面那条边;另加 _unstick() 兜底,中心真进了实心格就推回最近空格
放下糖泡就自杀(探险模式最明显) 从自己的糖泡上走下来后,身后半个身子还压在糖泡格里(此时糖泡已对他变实心)。原本要求整个包围盒无碰撞才允许移动,于是人被自己的糖泡卡死在原地,然后被自己炸死 移动只检查迎面那条边,不看整个包围盒。顺带 AI 自杀率从 ~25% 降到 ~5% —— 机器人也一直被同一个 bug 卡着
出生点被糖果箱围死 探险地图中心出生点四邻全是箱子,1 级威力放泡覆盖自己脚下,无处可躲 地图重排;并给所有地图加保险:出生点 3×3 内的可炸物一律清空,附带一个自动校验(每个出生点放泡后必须存在逃生路线)
文字不在同一水平线上 控件标签用 topleft 锚点却传了 centery 的 y,数值用的是垂直居中锚点,一高一低 text() 增加 midleft 锚点,标签与数值统一垂直居中
音量只能变大 鼠标点击和回车都只走 shift(+1),没有"减小"的入口 滑条改成点哪儿就是哪儿、可拖动、滚轮可调;回车在满值时回到最小值
左右切换显示成方框 用了 ◀ ▶ 字符,很多中文字体没有这两个字形 改成 pygame.draw.polygon 手绘三角;成就的 ★ ☆ 同样改为手绘
界面被切掉(顶栏/底部玩家卡看不全) 固定 1152×720 窗口,在小屏或 125%/150% DPI 缩放的机器上放不进桌面 Windows 下声明 DPI 感知;改成固定画布 + 等比缩放架构,窗口可随意拖动大小、可全屏,鼠标坐标自动换算
切换界面语言后中英混排 字体缓存没清,且控件文字在创建时就定死了 init_fonts() 清缓存,切语言后重建界面

原始说明

一款用 Python + pygame 写的休闲竞技游戏,按前一份《QQ堂》产品分析文档里的设计结论逐条落地, 可用 PyInstaller 打包成单文件 exe(双击即玩,不需要装 Python)。

零素材依赖:所有美术都是 pygame 图元手绘,所有音效与背景音乐都是 numpy 实时合成的, 所以打包产物就是一个自包含的可执行文件,没有任何 assets 目录。


一、先说打包成 exe

Windows(推荐)

  1. 装 Python 3.9~3.12(安装时勾选 Add Python to PATH
  2. 双击 build.bat

脚本会依次做:装依赖 → 跑自检 → PyInstaller 打包,产物在 dist\SugarBubble.exe(约 3545 MB)。 单文件 exe 首次启动需要 38 秒解包,属正常现象;想改中文名直接重命名即可。

想先跑起来看看而不打包:双击 run.bat

中文版打包说明与常见问题(杀软误报、pip 换源、崩溃日志位置)见 build-readme-cn.txt

build.bat / run.bat纯 ASCII + CRLF 的,请勿在里面加中文注释。 cmd.exe 按系统 ANSI 代码页(GBK)读 .bat,UTF-8 中文注释解码错位后会夹出 & 这类分隔符,把注释截成半截命令执行,报 'xxx' 不是内部或外部命令

Linux / macOS

bash build.sh          # 产物 dist/sugarbubble

已验证

打包链路在本机(Linux / Python 3.12 / pygame 2.6.1 / PyInstaller 6.x)已完整跑通, 产物 34 MB,冻结后的可执行文件 --selftest 通过。Windows 侧用同一份 spec。

spec 里两条注释别删:

  • 不要把 xml / email / http 放进 excludes —— pkg_resources 的运行时 hook 会用到, 排掉会在启动瞬间崩(ModuleNotFoundError: No module named 'xml')。
  • upx=False —— UPX 压缩过的单文件 exe 被 360 / 火绒 / Defender 误报的概率明显更高。

命令行开关:--selftest 无窗口跑一遍全部模式并退出(打包后验证用)、--version


二、操作

操作 1P 2P(同一台机器)
移动 方向键 W A S D
放糖泡 空格 F
飞镖引爆 左 Ctrl G
叉子自救 左 Shift R

暂停 Esc · 帮助 F1 · 全屏 F11 · 回放变速 Tab


三、核心机制:把"被困—营救"做成灵魂

分析文档里的第一条结论是:一个反转型死亡机制,胜过十个数值系统。所以整套代码是围绕这条写的。

糖泡  2.6s 引信 → 十字爆炸(半径=威力) → 生成糖浆(0.75s)
碰到糖浆 → 被困(不能动,4.2s 后出局)
    ├─ 队友接触 0.25s  → 救出(+营救计数)
    ├─ 敌人接触         → 立刻出局(补刀)
    └─ 自己有叉子       → 自救
全队出局 = 本局输

一次爆炸同时创造了一个救援机会和一个补刀机会 —— 这是原作最高频的情绪来源, 也是 AI 决策优先级里"营救队友"排在"打人"之前的原因。

实测 4 个高手 AI 混战,约 63% 的出局来自敌人、24% 自炸、10% 队友误伤, 说明这个博弈是真的在跑,不是摆设。

四、复用操作、替换目标:5 个模式

模式 胜利条件 关键差异
经典模式 团灭对手,多局决胜 道具全开
无道具竞技 团灭对手 固定数值、不掉道具,纯走位与卡泡
足球模式 限时内补刀数多者胜 糖泡从天而降,全员自带踢泡,可复活
抢包子 先运回 3 个包子 抢敌方包子铺 → 搬回自家大本营,被困会掉包子
探险模式 单人 PvE,撑波数 一波波糖怪,3 条命,波数越高 AI 越强

操作永远只有"走 + 放泡",换的只是胜利条件和场景元素 —— 这是文档里那条"最便宜的内容扩量"。

五、道具与地形

局内道具:威力 / 糖泡数 / 速度(三类基础)、叉子(自救)、飞镖(远程引爆)、 护盾(挡一次)、踢泡(撞向糖泡把它踢走)、变身(8s 满属性,被炸只变回原形)、 捣蛋(负面:威力降到 1 且减速 6s)。

地形:糖果箱(一炸开,可能掉道具)、硬糖箱(炸两次)、传送带、传送门、减速泥地、 大本营 / 包子铺。

六、付费公平性(有意保留原作的"缺点")

商店只卖两类东西:皮肤(纯外观)和出场携带(开局 +1 威力 / +1 叉子这类,最多 3 格)。 糖泡威力上限、爆炸判定、糖浆时长不因任何消费改变。

这正是文档里指出的那个悖论 —— 公平换口碑、变现受限。这里保留公平设计, 把变现压力交给等级/成就/皮肤,同时用确定性录像成就系统替代当年缺失的长线内容。

七、AI

core/ai.py,决策优先级:

自救 > 逃离爆炸 > 营救队友 > 补刀被困敌人 > 模式目标(送包子) >
埋泡打人 > 拆箱开路 > 追道具 > 逼近敌人 > 随机游走

两层安全保证:

  1. 危险图 danger[格子] = 该格变致命的剩余时间,含连锁引爆时间松弛(3 轮迭代)
  2. 放泡前逃生检查:算出这颗泡引发的完整爆炸区(含它会连锁引爆的其他泡), BFS 确认引信内存在可达安全格,否则不放

第 2 条里"含连锁"这句是关键。最初只算自己那颗泡的十字范围,AI 自杀率高得离谱; 把连锁引爆算进去之后才正常。

难度分 4 档(新手/普通/高手/宗师),差异在反应间隔、失误率、攻击欲、搜索深度。 失误按每秒发生率 + 冷却建模,而不是"每次重规划都掷一次骰子" —— 后者会让重规划越频繁的高难度 AI 反而死得越多。

八、录像回放

对局是固定步长(1/60s)+ 单一随机种子的确定性模拟,AI 也只依赖种子, 所以录像只需存人类玩家每帧的输入位掩码(还做了变化点编码),一场几 KB。

自测里有确定性验证:同种子跑两遍,帧数、坐标、战绩必须逐位一致(当前 PASS)。

九、工程结构

main.py                 入口 + 场景栈(菜单/设置/商店/生涯/对局/结算/录像)
core/settings.py        全部调参常量(数值都集中在这,改平衡不用翻代码)
core/maps.py            6 张手工地图(ASCII 图例)+ 随机地图生成器 + Board
core/entities.py        Player / Bubble / Syrup / Item / Bun / 粒子 / 飘字
core/match.py           对局核心:物理、爆炸链、被困判定、5 种模式规则、胜负
core/ai.py              机器人:危险图、BFS 寻路、逃生检查、行为树
core/audio.py           numpy 程序化音效 + 8 小节循环 BGM(无声卡自动静音降级)
core/profile.py         存档:勇气/宝石/等级/皮肤解锁/携带/成就/生涯统计
core/replay.py          录像录制与回放
ui/widgets.py           中英字体自适应 + 按钮/滑条/轮换控件 + 菜单容器
ui/render.py            对局渲染(棋盘、角色、糖泡、糖浆、HUD、特效)
tools/smoke_test.py     无头自测:全模式跑通 + 渲染 + 确定性验证
tools/screenshot.py     把各界面渲染成 PNG

约 4500 行。存档位置:Windows %APPDATA%\SugarBubble\,其他 ~/.sugarbubble/

中文字体自适应

界面文字全部走 W.T("中文", "English")。启动时按 微软雅黑 → 黑体 → Noto Sans CJK → 文泉驿 → PingFang 的顺序找系统字体, 并实际渲染一个汉字验证字形存在(不是只看文件在不在); 找不到就整体切英文界面,而不是满屏豆腐块。设置里也能手动锁定 English。

十、自测

python tools/smoke_test.py     # 全模式 × 全地图跑到分出胜负 + 渲染 + 确定性
python tools/screenshot.py     # 输出各界面 PNG
python main.py --selftest      # 快速冒烟(打包后也能对 exe 跑)

当前 smoke_test 结果:15 个模式×地图组合全部正常分出胜负, 模拟速度 300010000 逻辑帧/秒(约 50160 倍实时),确定性 PASS。

十一、已知取舍

  • 没有联网对战。原作的命脉是 QQ 关系链,但网络同步(尤其是这种要求判定精确的爆炸游戏) 是另一个量级的工程。当前是本机 1~2 人 + AI。确定性模拟这套底子是为帧同步准备的, 真要做联网,从这里接 lockstep 是最省力的路径。
  • 没有反外挂。文档里说外挂治理失效等于把公平设计的价值清零 —— 单机版这条不适用, 但如果要联网,服务端权威判定必须在第一版就做,不能留到后面。
  • 美术是几何图元。可爱风靠配色和眼睛朝向撑,没有真正的骨骼动画。
  • 音频合成在启动时约占 0.3~0.6 秒。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages