全程用 AI 做一款商业级手游 · EP10 道具系统:让三个按钮真正改变棋盘

EP9 收尾复盘时,我留了一句诚实的话:游戏里那三个道具按钮------撤销 / 炸弹 / 换一换 ------UI 做好了、点了会扣计数、会响一声,但按下去棋盘根本没变。这是当时整个游戏唯一"按了没实际效果"的地方。这一集(EP10)回头把它补完,让它真正可玩到底。

道具是 Block Blast 这类游戏的重要付费/留存抓手(道具靠玩、连签、内购获得,EP5/EP6 已经把"怎么得到道具"做好了),但前提是道具得真的有用。三个道具,三种对棋盘的操作:

撤销:落子前留一张快照

撤销的本质是"把棋盘退回上一步"。做法是在每次成功落子(和每次炸弹)之前,给整盘 + 托盘 + 分数拍一张快照;撤销就是把快照贴回去:

csharp 复制代码
int[,] _undoBoard; List<Piece> _undoTray; int _undoScore; bool _canUndo;

void Snapshot()
{
    _undoBoard = Board.CloneCells();          // 整盘拷一份
    _undoTray  = new List<Piece>(Tray);
    _undoScore = Score.Value;
    _canUndo   = true;
}

public bool Undo()
{
    if (!CanUndo) return false;
    Board.LoadCells(_undoBoard);              // 贴回去
    Tray.Clear(); Tray.AddRange(_undoTray);
    Score.Value = _undoScore;
    GameOver = false;                         // 撤销能把你从死局里救回来
    _canUndo = false;                         // 一次只能撤一步
    return true;
}

注意 GameOver = false------撤销不只是反悔,它能从死局复活 (这正是它作为付费道具的价值:卡死了,花一个撤销续命)。而且一次只能撤一步(_canUndo 撤完即关),不能无限回退。

炸弹:点哪炸哪,清掉 3x3

炸弹给棋盘开一个 BombArea,点中的格子周围 3x3 全清,返回清掉的数量:

csharp 复制代码
public int BombArea(int cx, int cy, int radius)
{
    int n = 0;
    for (int x = cx - radius; x <= cx + radius; x++)
        for (int y = cy - radius; y <= cy + radius; y++)
            if (InBounds(x, y) && _cell[x, y] != 0) { _cell[x, y] = 0; n++; }
    return n;
}

视图层把炸弹做成"两步":点道具按钮 → 进入"待引爆"状态(顶上提示"点击方块引爆")→ 再点棋盘任意格 → 引爆那一片。只有真炸到东西才扣道具(点空地不消耗),而且炸弹也留了撤销点(手滑了能撤回来)。

下面这两张是真机实拍------左边是道具操作前棋盘堆了一片,点炸弹、再点左下角,那一片 3x3 就被炸空了(填充数从 13 掉到 4,橙色迸裂粒子正好盖在炸空的那一片上):

换一换:重发一手新托盘

最简单的一个:当前三块不顺手,换一换重发三块新的(不可撤销,会清掉撤销点,并重判死局------万一换出来全放不下就是真死局了):

csharp 复制代码
public void RefreshTray()
{
    DealTray();
    _canUndo = false;
    GameOver = !Board.AnyPlaceable(UnusedTray());
}

顺手逼出一个真 bug

写自检的时候,单独跑这一集的道具测试是 16/16 全绿,但接在前面 9 集后面一起跑,就挂一条:「开局不可撤销」失败。

追下去是个真 bug:NewGame 重置了棋盘、分数、死局标志,却没清撤销快照 ------所以开了新一局,_canUndo 还是上一局最后一步留下的 true,于是你能在新局里"撤"回上一局的棋盘。修复就一行,在 NewGame 里补上 _canUndo = false; _undoBoard = null;

这种 bug 单测一个系统时根本暴露不出来------必须多个系统按真实顺序连起来跑才会浮出水面。这也是为什么我每加一集都把全部自检从头跑一遍,而不只跑新写的那几条。

验证:16 条断言 + MCP 真机三连点

逻辑层 16 条断言钉死:撤销还原棋盘/分数/托盘且一次性、炸弹清区域且空炸不消耗、炸弹可撤销、换一换重发满 3 块且清撤销点......

复制代码
A 开局不可撤销 / 落子后可撤销 / 撤销还原棋盘(filled==0)/分数(==0)/托盘(3块) / 不能连撤两次
B 引爆已填格清掉东西(>0) / 填充数下降 / 炸弹可撤销 / 空炸清0 / 空炸不留撤销点
C 换一换后托盘满3块 / 换一换清掉撤销点
==== 16/16 PASS ====

断言之外,还是老规矩------用 MCP 在真 PlayMode 里把三个按钮一个个点了一遍:

  • 撤销simulate_mouse_click)→ 顶栏分数从 23 退回 12,上一步消掉的方块全回来了,道具计数 17→16;
  • 炸弹 → 顶上弹出"点击方块引爆",再点棋盘 → 那片 3x3 炸空(上面两张截图);
  • 换一换 → 托盘三块瞬间换成全新的三块。

每一步都 capture_game_view 截图回看,确认棋盘真的按预期变了。三个按钮,从"按了没反应"变成"按了真改局面"。

撤销最商业的用法:死局复活

把撤销做对之后,顺手补上了一个真正用到它的地方------死局结算面板 。原来死局只有一行"GAME OVER"文字,太糙。现在死局会弹一个结算面板:本局得分、最高分、新纪录标记,以及两个按钮------再来一局复活(用撤销)

"复活"就是撤销那条命脉的商业化用法:死局 = 上一步把自己堵死了,而落子前正好留了撤销快照,所以 复活 = 消耗一个撤销道具 + Undo(),棋盘退回死局前、GameOver 翻回 false,接着玩。这就是 F2P 里"卡死了花点东西续命"的钩子------道具的需求正是这么被设计出来的。死局广播也走事件总线(控制器 Send(GameOverMsg) → UI 弹面板),和前面所有系统一个套路。

我用 MCP 把这条也点了一遍:触发死局 → 面板弹出(带"★新纪录★")→ 点"复活" → 分数 25 退回 23、撤销 24→23、GameOver 翻回 false、回到对局;再点"再来一局" → 空棋盘新开。

顺手把首页和局内分开 + 道具换成图标

对照成熟商业休闲游戏的通行结构后,又补了两处"正经游戏该有"的结构:

首页 / 局内分离。原来所有东西堆在一屏,现在是标准的"先首页、点开始才进对局":首页是个干净的大厅------标题、最高分、一个大大的"开始游戏",加上商城/每日/皮肤导航;点开始才进棋盘,局内左上角有"← 首页"随时退回。

道具按钮换成图标。原来是"撤销/炸弹/换一换"三个文字按钮,太工程师了。改成图标按钮------一张程序化生成的圆角光泽底,套上撤销(循环箭头)/炸弹/换一换(双向箭头)三个图标,右下角一个数量角标。一眼就懂、也更像那么回事:

这两处都是用 MCP 点着改、截图比着调出来的------首页点"开始游戏"进局内、点图标道具触发效果(撤销 score 10→7、道具数 35→34)、点"← 首页"退回大厅,全程 simulate_mouse_click 验证。

这一集的产物与诚实的话

  • BlockGameController 加撤销快照/Undo/Bomb/RefreshTrayBoardModelCloneCells/LoadCells/BombAreaGameView 接道具入口 + 炸弹"待引爆"交互。
  • 16 条断言全绿(修了 NewGame 不清撤销快照的 bug)+ MCP 真机三连点验证。
  • 死局结算面板(最终分/最高分/新纪录 + 复活/再来一局),死局走 GameOverMsg 事件广播,"复活"复用撤销道具。
  • 至此,游戏里再没有"按了没效果"的按钮,死局也不再是一行干文字。

诚实地讲:道具的玩法逻辑做完了,表现也接了一部分------炸弹引爆已经有迸裂粒子(复用 EP7 那套缓动 + 白色光泽方块碎片,和消行一个效果)。还差的是撤销的"方块飞回"动画、换一换的洗牌动效,这些纯 juice 是锦上添花(EP7 框架已备好,接上去就行),不影响"能不能玩"。功能闭环这一层,三个道具已经真正合上了。

相关推荐
随意起个昵称1 小时前
线性dp-LIS题目5(导弹拦截,二分优化)
c++·算法·动态规划
计算机安禾1 小时前
【数据库系统原理】第16篇:范式理论(下):多值依赖与第四范式——消除非平凡的非函数依赖
算法
lqqjuly1 小时前
一致性模型深度解析
人工智能·深度学习·算法
RisunJan1 小时前
Linux命令-patch (为开放源代码软件安装补丁程序)
linux·服务器·算法
秋天的一阵风1 小时前
✨ 代码秒跳转、自动补全?全靠 LSP 和 AST!
前端·后端·ai编程
沉默王二1 小时前
又一个神级 Codex Skill 诞生了!
agent·ai编程
SmalBox2 小时前
【节点】[VoronoiNoise节点]原理解析与实际应用
unity3d·游戏开发·图形学
ThatMonth2 小时前
Chroma 向量数据库使用教程
ai编程
一条大祥脚2 小时前
ABC460贪心|多源BFS|数论|计数|线段树|树的直径
算法·宽度优先