- 新增 AICODE06-08~11 完整逐字稿教案(每课600+行) - 涂鸦PK主题:画图工具→基础对战→动画音效→班级锦标赛 - 核心工程思维:需求驱动→测试验证→增量迭代→数据驱动 - 更新 AICODE-06 课程大纲,追加第8-11课内容 - 新增 demo-pk/ 目录(画图工具/对战/动画三个demo) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
606 lines
38 KiB
Markdown
606 lines
38 KiB
Markdown
---
|
||
课时: 9
|
||
主题: 涂鸦PK(二)— 基础对战系统
|
||
核心能力: [拆解力, 韧性力]
|
||
核心工具: [Trae IDE, Kimi]
|
||
时长: 90分钟
|
||
透明化层级: 过程层
|
||
适用路线: AICODE-06
|
||
---
|
||
|
||
### 1. 课程目标
|
||
|
||
**知识目标:**
|
||
- 理解「边界情况」的概念:任何系统都有正常路径以外的边缘场景,这些场景必须在需求里明确定义,否则 AI 的行为不可预测
|
||
- 理解「独立窗口审核」原则:需求文档、边界审核、代码生成、测试验证各用独立会话,防止 AI 自我偏袒
|
||
- 理解「测试脚本」的价值:用代码来验证代码,比人工点击效率高十倍,且可重复执行
|
||
|
||
**能力目标:**
|
||
- 能用 Plan Mode 整理战斗系统需求文档,并用窗口 B 发现边界情况(拆解力)
|
||
- 能把自己的 Spritesheet 导入对战系统,完成逐条验收,遇到 bug 能描述「步骤→预期→实际」(韧性力)
|
||
- 能让 AI 生成测试脚本,读懂「✅通过/❌失败」的输出,并定位到需求文档中对应的条款
|
||
|
||
**情感目标:**
|
||
- 建立「测试不是挑刺,是保护」的意识——有 bug 的游戏比没有游戏更让人沮丧,测试帮你在发布前修好它
|
||
- 体验「让 AI 测试 AI 写的代码」的效率感,而不是自己一条条人工验证
|
||
- 对「今天的角色真的打起来了」产生真实的成就感,为第10课加动画做好期待
|
||
|
||
---
|
||
|
||
### 2. 核心概念与误概念预设
|
||
|
||
**核心概念认知层级:**
|
||
|
||
| 概念 | 学生类比 | 认知层级 |
|
||
|------|---------|---------|
|
||
| 边界情况 | 游戏规则书上写了「普通攻击」怎么算,但没写「两个人同时出手」怎么判——比赛现场这种情况真出现了,裁判不知道怎么判,整场比赛乱掉 | 理解层 |
|
||
| 独立窗口审核(新窗口原则) | 作文让同学评改:写作文的同学自己改,永远改不出大问题;换一个没看过你作文的同学来改,他会发现真正的漏洞 | 应用层 |
|
||
| 测试脚本 | 乐高玩具的「质检机器人」——每次按一个按钮,它自动把所有零件逐一检查一遍,告诉你哪个零件不对;比你自己一个个用眼睛看快一百倍,而且不会看漏 | 应用层 |
|
||
| 伤害公式 | 攻击力是出拳力气,防御力是护甲厚度,伤害 = 出拳力气 − 护甲厚度,最少也会有 1 点伤害(护甲再厚也会有点疼) | 识别层 |
|
||
| 先手机制 | 速度值高的人先出手,就像运动会百米跑步,反应快的人先起跑——如果两人反应时间一样,就抛硬币决定 | 识别层 |
|
||
|
||
**典型误概念表:**
|
||
|
||
| 编号 | 误概念 | 正确认知 | 激发策略 |
|
||
|------|--------|---------|---------|
|
||
| M1 | 游戏能跑就行,不用测试 | 有 bug 的游戏比没有游戏更难受;测试发现的 bug 才是可修复的 bug | 问:「你有没有玩过一个游戏,有个 bug 特别烦但一直不修?你是什么感受?」 |
|
||
| M2 | 测试脚本要自己写,太难了 | 测试脚本也可以让 AI 写,你只需要描述「我要验证什么结果」 | 演示:把「验证 ATK=15, DEF=5 时伤害=10」告诉 AI,它直接给出测试代码 |
|
||
| M3 | 同速的情况 AI 会自动处理好 | 边界情况必须在需求里明确,否则 AI 行为不可预测(可能每次随机,也可能直接报错) | 问:「如果两个角色速度一样,谁先出手?你需求里写了吗?」 |
|
||
| M4 | 伤害公式在脑子里,不用写进需求 | 代码里的公式必须和需求文档一致,否则测试脚本无法验证;口头约定不算 | 演示:需求里写「ATK 减 DEF」,代码里却写成「ATK 乘以 DEF」,逻辑完全不同 |
|
||
| M5 | 格挡和攻击同帧不会有问题 | 行动顺序是战斗公平性的核心;「同时出手」必须在需求里明确谁的优先级高 | 类比:石头剪刀布如果两人同时出,规则说谁赢?——必须有一个规则,不能靠 AI 猜 |
|
||
|
||
---
|
||
|
||
### 3. 教学准备
|
||
|
||
**工具与环境:**
|
||
- 每台电脑已安装 Trae IDE,Kimi 已登录,网络正常
|
||
- 每台电脑浏览器可以正常打开本地 HTML 文件
|
||
- 每台电脑上已有上节课完成的 Spritesheet PNG 文件(128×64,帧1待机+帧2攻击)
|
||
- 每台电脑上已有上节课完成的角色属性 JSON(hp/atk/def/spd/skill 字段,20分预算制)
|
||
- 投影可切换至任意学生屏幕
|
||
|
||
**教学资源:**
|
||
- 教师准备:demo-2-pk-battle.html(可直接运行的战斗演示,开课前准备好,用于 Connect 展示和 Contemplate 演示)
|
||
- 教师准备:战斗需求文档范例(见第5节,完整版,供学生卡壳时参考)
|
||
- 教师准备:测试脚本的预期输出截图(4条全部 ✅ 通过的版本,用于对比)
|
||
- 学生资源:上节课完成的 Spritesheet PNG 和角色属性 JSON(若有学生未完成,教师提供默认模板)
|
||
|
||
**教师备课体验任务:**
|
||
> 备课前,教师必须亲自完成以下操作:
|
||
>
|
||
> 1. 打开 demo-2-pk-battle.html,完整打一局,记录下「格挡+重击同回合」时伤害是怎么算的,以及「特技用完后再点特技按钮」的实际行为
|
||
> 2. 在窗口 A 整理一份战斗需求文档,然后在全新窗口 B 用审核提示词跑一遍,记录 AI 问出来的边界问题里哪几条最让你意外
|
||
> 3. 在窗口 D 生成测试脚本,验证伤害公式和先手机制,确认本课所有测试用例都能通过
|
||
> 4. 故意把伤害公式改成「ATK × DEF」,重跑测试脚本,截图「❌失败」的输出,备课时展示用
|
||
|
||
---
|
||
|
||
### 4. 教学流程
|
||
|
||
---
|
||
|
||
**第一幕:联系 (Connect) — 10分钟** 🔗
|
||
|
||
*本幕目标:让学生展示上节课做的角色,说出打法定位和取胜策略,激活策略意识;教师演示可以运行的对战系统,建立「今天目标」的画面感*
|
||
|
||
**【环节】角色展示 + 打法定位 (7分钟)**
|
||
|
||
**师:** 上节课结束前,每个人都交了两样东西:一个 Spritesheet PNG,一份角色属性 JSON。今天我们用这两样东西做什么?
|
||
|
||
**生:** (预期:做游戏?让它打起来?)
|
||
|
||
**师:** 对。上节课大家做了什么,记得吗?
|
||
|
||
**生:** (预期:画了自己的角色 / 设计了角色属性)
|
||
|
||
**师:** 对。你们每个人手里有一个属于自己的角色:有自己画的图,有自己定的属性,还有自己选的特技。今天不是来欣赏它的——今天要让它真的打起来。
|
||
|
||
**师:** 在打之前,我先问每个人一个问题。谁来第一个回答——你的角色是什么打法定位?为什么你的角色应该赢?
|
||
|
||
【点一个学生,把他的 Spritesheet 投屏展示】
|
||
|
||
**生:** (预期 A:「我是高攻击型,我的 ATK 是 16,我可以直接打穿对面」)
|
||
|
||
**生:** (预期 B:「我是高防御型,我血多,耗死对手」)
|
||
|
||
**生:** (预期 C:「我速度最快,我先手,每次都比对面早打」)
|
||
|
||
**师:** 很好。你说的「先手」——如果两个角色速度值一样怎么办?
|
||
|
||
**生:** (预期:不知道 / 随机?/ 谁编号小谁先?)
|
||
|
||
**师:** 这就是我们今天第一件事要想清楚的——你脑子里的规则,必须写成文字,AI 才能按你想的来做。
|
||
|
||
【诊断点:学生能否意识到「打法逻辑」和「代码规则」之间有一层需要翻译的过程】【识别层】
|
||
|
||
**【分支A】若学生对打法定位有清晰的想法:**
|
||
**师:** 很好,待会儿写需求文档的时候,你的打法定位就是你的出发点——你的角色是高攻击,那你的伤害公式、重击倍率、特技效果就都要围绕「攻击压制」来设计。
|
||
|
||
**【分支B】若学生说「我随便,什么定位都行」:**
|
||
**师:** 没关系,我们来帮你定位。你的 ATK 最高,还是 DEF 最高,还是 SPD 最高?
|
||
(引导学生从属性数值反推定位,而不是空想)
|
||
|
||
**【环节】展示今天目标 (3分钟)**
|
||
|
||
**师:** 我先给大家看一个东西。
|
||
|
||
【投屏打开 demo-2-pk-battle.html,运行一局对战】
|
||
|
||
**师:** 你们看——左边是玩家角色,右边是 AI 对手,有血条,有行动按钮,有战斗日志。这就是今天下课前你们要做到的东西。
|
||
|
||
**师:** 但注意——你们做出来的版本,角色是你们自己画的,属性是你们自己定的。你的角色放在左边,跟 AI 对手打。今天不做动画,角色还是用矩形占位,但战斗逻辑是真实的。下节课我们把图换上去、加动画。
|
||
|
||
**师:** 今天的核心是:战斗规则要真的是你想的规则,而不是 AI 随机猜的规则。怎么保证?用 Plan Mode。
|
||
|
||
**师:** 今天我们会开 4 个窗口——窗口 A 写需求、窗口 B 审核边界、窗口 C 生成代码、窗口 D 做测试。这 4 个窗口,每个只做一件事,互相不干扰。记住这个结构,以后你做任何大一点的项目都可以用。
|
||
|
||
---
|
||
|
||
**第二幕:建构 (Construct) — 65分钟** 🛠️
|
||
|
||
*本幕目标:走完「需求文档→边界审核→代码生成→导入 Spritesheet→验收→测试脚本验证」完整闭环,强化多窗口协作和边界意识*
|
||
|
||
---
|
||
|
||
**【分段一:Plan Mode — 战斗系统需求文档】(20分钟)**
|
||
|
||
*本段重点:学生在窗口 A 整理战斗系统需求,在窗口 B 用「边界审核」提示词发现漏洞,补充进文档*
|
||
|
||
**预设误概念:**
|
||
- 误概念 M3:同速情况 AI 会自动处理好,不用写
|
||
- 误概念 M4:伤害公式在脑子里不用写进需求文档
|
||
- 误概念 M5:格挡和攻击同帧不会有问题
|
||
|
||
**讲解与演示 (Teach & Demo): (7分钟)**
|
||
|
||
**师:** 我们先开窗口 A——这个窗口只做一件事:整理需求文档。
|
||
|
||
**师:** 今天的需求文档比俄罗斯方块简单一点,但有一个新的挑战——这个系统里有很多「边界情况」。什么叫边界情况?就是不在「正常流程」里,但真实对战时会出现的场景。
|
||
|
||
**师:** 我给你们举几个例子。正常流程是什么?玩家点攻击,AI 点攻击,互相扣血,谁血量归零谁输。这是主路径,好想,好写。
|
||
|
||
**师:** 但是——如果两个角色速度值完全相同,谁先出手?这条你有没有想过?
|
||
|
||
**生:** (预期:没想过 / 随机?)
|
||
|
||
**师:** 还有——特技每场只能用一次。如果玩家特技已经用完了,再点「特技」按钮,游戏会怎样?按钮灰掉不能点?还是提示「已用完」?还是直接变成普通攻击?
|
||
|
||
**生:** (预期:好像要变灰 / 要提示吧)
|
||
|
||
**师:** 对。还有——格挡时受到的伤害减少 50%,那对方用的是重击(伤害×1.8),格挡减伤是基于重击后的伤害算,还是基于原始伤害算?
|
||
|
||
**生:** (预期:有区别吗……?哦,区别很大!)
|
||
|
||
**师:** 这些都是边界情况。这些情况如果你没有在需求里写清楚,AI 会自己猜一个——可能猜得跟你想的不一样,可能每次结果还不同,可能直接崩掉。
|
||
|
||
**师:** 所以今天需求文档要写两轮。第一轮是窗口 A:把主路径写出来。第二轮是窗口 B:让 AI 扮演审核工程师,专门找你没考虑到的边界情况。
|
||
|
||
【投屏展示战斗需求文档的五个核心模块】
|
||
|
||
**师:** 战斗系统需求文档有五个必填模块。我过一遍每个的关键要点——
|
||
|
||
**师:** 模块一:先手机制。你必须写清楚两条:第一,SPD 高的先出手——这好理解;第二,**同速时怎么处理**——你必须选一个方案,写进文档。你可以写「同速时随机决定」,也可以写「同速时玩家先手」,但必须选一个,不能空着。
|
||
|
||
**师:** 模块二:伤害公式。写「ATK 减 DEF,最低造成 1 点伤害」。注意「最低 1 点」这个细节必须写——如果不写,当防御值大于攻击值时,AI 可能算出负数伤害,变成治疗对手了。
|
||
|
||
**师:** 模块三:行动类型。四种:普通攻击、重击(伤害×1.8)、格挡(本回合受伤减少 50%)、特技(每场只能用一次,效果来自角色 JSON 的 skill 字段)。
|
||
|
||
**师:** 模块四:胜负判定。HP≤0 立即判输,游戏结束。
|
||
|
||
**师:** 模块五:AI 对手决策逻辑。AI 对手不是乱打的——写清楚它的决策规则:HP 低于 30% 时用特技;25% 概率重击;否则普通攻击。
|
||
|
||
**师:** 我来快速演示一下这五个模块写出来是什么样的。
|
||
|
||
【投屏展示教师自己的需求文档草稿,只展示模块一和模块二,让学生对格式有直观感受,不逐字念,只指出关键字段】
|
||
|
||
**师:** 你们看,模块一的「同速处理」我写了「同速时随机决定,Math.random() < 0.5 为玩家先手」。你们不需要写代码,但要写清楚「同速时谁先」——随机、或者固定玩家先手,选一个写进去。
|
||
|
||
**师:** 模块二里,我特别标了「最低 1 点」并且加了验收标准:「当 ATK=3, DEF=8 时,伤害=1 而不是负数」。这就是一条可测试的需求——能写出具体数字的需求,才是真正写清楚了的需求。
|
||
|
||
**师:** 这五个模块写完,是你的「主路径」。然后我们开窗口 B,让 AI 来挑刺。
|
||
|
||
**学生实践 (Practice): (10分钟)**
|
||
|
||
**师:** 现在打开 Kimi,开一个新对话,这是窗口 A。用我刚才说的五个模块,把你的战斗系统需求文档写出来。不确定的地方先写一个版本,待会儿窗口 B 会帮你发现问题。
|
||
|
||
> 教师走动观察重点:
|
||
> - 是否有学生跳过「同速处理」这条?走过去问:「你这里写了 SPD 高的先手,那两人 SPD 一样怎么办?」
|
||
> - 是否有学生漏写「最低 1 点伤害」?问:「如果对手 DEF 比你 ATK 还高,伤害是负数还是零?你想要哪个?」
|
||
> - 是否有学生把 AI 对手的决策逻辑写得很复杂(超过 3 条)?提醒:「AI 对手逻辑先简单,战斗规则才是重点」
|
||
|
||
**进度同步 (Checkpoint): (3分钟)**
|
||
|
||
**师:** 五个模块都填了的举手。
|
||
|
||
**师:** 好,现在开窗口 B——新开一个 Kimi 对话,把你写好的需求文档整个复制过去,然后加上这句话:「你是一个游戏测试工程师,请列出这份需求文档里所有的边界情况和异常情况,只列问题,不需要解答。」提交。
|
||
|
||
【诊断点:学生是否能把「用窗口 B 挑需求漏洞」理解为「需求还没写完」,而不是「可以不管这些问题」】【理解层】
|
||
|
||
**【分支A】若学生窗口 B 得到了边界问题列表:**
|
||
**师:** 好,先把这些问题读一遍。你觉得哪条最重要——就是如果不处理,对战时一定会出问题的那条?
|
||
(让学生自己判断优先级,而不是逐条补充所有问题)
|
||
|
||
**【分支B】若学生说「AI 没问出什么有用的问题」:**
|
||
**师:** 我来帮你加一条——「同速时谁先出手」这条你文档里怎么写的?
|
||
(从教师预设的边界情况里选一条,帮学生发现漏洞)
|
||
|
||
**【分支C】若学生觉得「这些边界情况不重要,先做再说」:**
|
||
**师:** 好,我们来做个实验——你先做,遇到边界情况的时候我们再说。
|
||
(让学生先继续,在分段二验收时用真实 bug 来说明边界问题的后果)
|
||
|
||
**师:** 窗口 B 出来的问题,不需要全部解决——先挑最重要的 3 条,补充到你的需求文档里。什么叫「最重要」?就是如果不写清楚,对战时一定会出现的场景。「同速先手」、「特技用完后再点」、「格挡+重击叠加」——这三条必须在文档里有明确答案。
|
||
|
||
**师:** 好,5分钟,把窗口 B 给你的问题里最关键的几条回答了,补到需求文档里。
|
||
|
||
> 教师走动:重点帮学生判断哪条边界问题「必须解决」。判断标准——对战时能触发的频率高不高?触发了但没处理会崩游戏还是只是显示不对?优先处理会崩游戏的。
|
||
|
||
---
|
||
|
||
**【分段二:生成 PK 系统 → 导入 Spritesheet → 逐条验收】(25分钟)**
|
||
|
||
*本段重点:在窗口 C 生成战斗系统骨架,替换为自己的角色数据,验收核心功能*
|
||
|
||
**预设误概念:**
|
||
- 误概念 M1:能跑就行,不用验收每一条
|
||
- 误概念 M4:遇到 bug 直接让 AI 改代码,不回需求文档溯源
|
||
|
||
**讲解与演示 (Teach & Demo): (5分钟)**
|
||
|
||
**师:** 需求文档确认好了,进入执行阶段。打开 Trae IDE,新开一个文件,命名为 pk-battle.html。
|
||
|
||
**师:** 这次生成分两步走。**第一步**:先生成「带占位图的骨架」——角色先用彩色矩形代替,重点让战斗逻辑跑通。**第二步**:骨架验收通过后,再把你的 Spritesheet 换进去。
|
||
|
||
**师:** 为什么要分两步?如果你一开始就把 Spritesheet 传进去,战斗逻辑有 bug 的话,你不知道是逻辑问题还是图片问题——两个问题混在一起,很难调试。先把逻辑跑通,再换图,问题清晰。
|
||
|
||
**师:** 现在开窗口 C——这个窗口专门做代码生成。把你的需求文档复制进去,加上保底提示词,提交。
|
||
|
||
【投屏展示学生保底提示词(见第5节),教师演示提交过程,展示骨架生成结果】
|
||
|
||
**师:** 生成出来之后,把代码复制到 Trae IDE 里的 pk-battle.html,保存,用浏览器打开,开始验收。
|
||
|
||
**师:** 验收怎么做?还是我们之前说的三步——「步骤→预期→实际」。你做了一个操作,你期望看到什么,实际看到了什么。如果期望和实际不一样,记下来,这就是一个 bug。
|
||
|
||
**师:** 验收清单,我们一起来定:
|
||
|
||
```
|
||
验收清单(至少验这 5 条):
|
||
1. 普通攻击 → 对手 HP 减少,减少量 = ATK - DEF(最低 1)
|
||
2. 格挡 → 下一次受到伤害减少 50%
|
||
3. 重击 → 伤害比普通攻击×1.8
|
||
4. 特技按钮 → 用完一次后变灰或显示「已用」
|
||
5. HP≤0 → 游戏结束,显示胜负
|
||
```
|
||
|
||
**学生实践 (Practice): (17分钟)**
|
||
|
||
第一步(8分钟):用保底提示词在窗口 C 生成战斗骨架,复制到 Trae IDE,浏览器打开
|
||
第二步(4分钟):按验收清单逐条点击验收,记录「通过/不通过」
|
||
第三步(5分钟):把验收通过的骨架里的角色数据,替换为自己的角色属性 JSON;把矩形占位符的颜色改成自己角色的代表色
|
||
|
||
> 教师走动观察重点:
|
||
> - 学生是否在逐条验收,还是点一下「感觉可以」就算通过?走过去问:「第 3 条重击倍率你验了吗?怎么确认它是 1.8 倍?」
|
||
> - 学生遇到 bug 时,是直接跟 AI 说「帮我修复」,还是先回需求文档确认这条需求怎么写的?
|
||
> - 有学生进展很快的:引导他多做一步——把 Spritesheet 也导入,用 `drawImage` 替换矩形,不需要动画,只是让图片显示出来
|
||
|
||
**进度同步 (Checkpoint): (3分钟)**
|
||
|
||
**师:** 谁来说一条验收结果——哪条通过了,哪条没通过?
|
||
|
||
**生:** (预期 A:「普通攻击通过了,格挡没通过,格挡好像没有减伤」)
|
||
|
||
**生:** (预期 B:「特技用完之后按钮没变灰,还能继续按」)
|
||
|
||
**师:** 格挡没有减伤——这个 bug 我们用「步骤→预期→实际」来描述。步骤是什么?
|
||
|
||
**生:** 点格挡,然后对面攻击我。
|
||
|
||
**师:** 预期是什么?
|
||
|
||
**生:** 受到的伤害应该是正常伤害的 50%。
|
||
|
||
**师:** 实际是什么?
|
||
|
||
**生:** 受到的伤害跟没格挡一样。
|
||
|
||
**师:** 对。这个描述发给 AI,加上一句「请检查需求文档里的格挡逻辑,修复这个 bug」。注意——不是说「帮我改代码」,是「检查需求文档对应的逻辑」,让 AI 溯源。
|
||
|
||
【诊断点:学生是否会用「步骤→预期→实际」三要素描述 bug,而不是只说「格挡不对」】【应用层】
|
||
|
||
**【分支A】若学生能准确描述 bug 三要素:**
|
||
**师:** 这就是专业的 bug 报告。真正的软件工程师报 bug 就是这个格式,你今天已经在用了。
|
||
|
||
**【分支B】若学生描述模糊(「格挡感觉不太对」):**
|
||
**师:** 「感觉不对」AI 不知道从哪里改。你告诉我——你点了格挡之后,对面攻击你,你的 HP 掉了多少?你预期应该掉多少?
|
||
(帮学生把感受翻译成具体数字)
|
||
|
||
---
|
||
|
||
**【分段三:窗口 D 生成测试脚本 → 验证核心逻辑】(15分钟)**
|
||
|
||
*本段重点:在独立窗口 D 生成测试脚本,运行 4 条测试用例,读懂「✅通过/❌失败」输出,体验「让 AI 测试 AI」的效率*
|
||
|
||
**预设误概念:**
|
||
- 误概念 M2:测试脚本要自己写,太难了,我不会代码
|
||
- 误概念 M1:能跑就行,不需要写测试
|
||
|
||
**讲解与演示 (Teach & Demo): (5分钟)**
|
||
|
||
**师:** 你们刚才用手工逐条验收——点按钮,看结果。这样做是对的,但有一个问题:下次你改了一段代码,你要把所有条目再点一遍吗?
|
||
|
||
**生:** (预期:要的 / 好累 / 不想点)
|
||
|
||
**师:** 有一个更高效的方法——**测试脚本**。你告诉 AI「我要验证哪些规则,预期结果是什么」,AI 写一个 HTML 文件,你一打开,它自动跑完所有验证,每条显示「✅通过」或者「❌失败+原因」。
|
||
|
||
**师:** 这叫「用代码测试代码」。以后你每次改完代码,打开测试脚本跑一遍,5 秒看完所有结果,知道改了哪里有没有破坏原来的逻辑。
|
||
|
||
**师:** 注意——测试脚本必须在全新窗口 D 生成。为什么?因为如果你在窗口 C 生成测试脚本,AI 知道自己刚刚写了什么代码,它的测试会偏向「帮自己的代码辩护」——故意写成能通过的测试,而不是真正验证逻辑是否正确。
|
||
|
||
**师:** 独立窗口 D,让一个「什么都不知道」的 AI 来写测试,它才会真的按需求文档来验证。
|
||
|
||
【投屏展示窗口 D 测试脚本提示词(见第5节),演示把需求文档粘贴进去,提交】
|
||
|
||
【投屏展示测试脚本的运行结果:4条全部✅,效果直观】
|
||
|
||
**师:** 这 4 条测试验证了什么——
|
||
|
||
```
|
||
测试 1:ATK=15, DEF=5 → 伤害=10 ✅
|
||
测试 2:ATK=5, DEF=10 → 伤害=1(最低) ✅
|
||
测试 3:SPD=8 vs SPD=5 → SPD=8 先手 ✅
|
||
测试 4:ATK=10, DEF=2, 重击 → 伤害=14 ✅
|
||
```
|
||
|
||
**师:** 现在我把伤害公式故意改错——把「ATK - DEF」改成「ATK × DEF」,再跑一遍。
|
||
|
||
【演示:故意修改代码,重跑测试脚本,出现 ❌ 失败】
|
||
|
||
**师:** 你们看——测试脚本立刻告诉我「测试1失败:期望10,实际75」。这就是测试脚本的价值:改完代码立刻能发现问题,不用自己重新点一遍。
|
||
|
||
**学生实践 (Practice): (8分钟)**
|
||
|
||
**师:** 现在你们来做。打开全新窗口 D,用测试脚本提示词,把你的需求文档粘贴进去,生成测试脚本,保存为 pk-test.html,浏览器打开,看结果。
|
||
|
||
> 教师走动观察重点:
|
||
> - 是否有学生在窗口 C 生成测试脚本(违反独立窗口原则)?立刻叫停,强调「必须是窗口 D,全新对话」
|
||
> - 学生的测试结果有 ❌ 吗?引导他们找对应的需求条款,而不是直接改代码
|
||
> - 进度快的学生:引导拓展任务——「让 AI 帮你写一条需求里没有的边界测试,看是否通过」
|
||
|
||
**进度同步 (Checkpoint): (2分钟)**
|
||
|
||
**师:** 谁的 4 条测试全部通过的举手。
|
||
|
||
**师:** 有没有哪条测试失败了的?能说一下是哪条,失败的原因是什么?
|
||
|
||
**生:** (预期:「测试3失败了,说期望8先手但实际是5先手」)
|
||
|
||
**师:** 这就是测试脚本的价值——它告诉你具体哪里不对。现在打开你的需求文档,找「先手机制」那条,看看写的是什么,再对照你生成的代码,找差异。这才是正确的调试方式。
|
||
|
||
【诊断点:学生是否能从「❌失败」的输出里,找到对应的需求文档条款进行溯源】【应用层】
|
||
|
||
**【分支A】若学生能自己完成溯源:**
|
||
**师:** 你刚才做的就是「测试驱动调试」——测试报告告诉你哪里不对,你去需求里找根因,然后修代码。这是专业开发者的工作方式。
|
||
|
||
**【分支B】若学生看到 ❌ 直接去改代码而不溯源:**
|
||
**师:** 等等——你要改什么?测试说失败,但测试是按需求文档验证的。先问:你的需求文档里这条是怎么写的?再问:代码里是不是按这条写的?最后才改代码。
|
||
|
||
**【分支C】若学生的测试脚本全部通过但游戏实际有 bug:**
|
||
**师:** 这很有趣——测试通过但游戏有 bug,说明两件事之一:第一,测试脚本用的是独立实现,和游戏代码逻辑不一样;第二,你的 bug 不在测试覆盖的范围里——是一个「需求没写到的边界情况」。你知道是哪种吗?
|
||
(引导学生区分「需求定义的 bug」和「需求未覆盖的 bug」)
|
||
|
||
---
|
||
|
||
**第三幕:反思 (Contemplate) — 10分钟** 🤔
|
||
|
||
*本幕目标:两学生角色现场对战演示(投屏全班围观),展示「同一规则、不同角色」下的策略差异*
|
||
|
||
**【环节】角色对战演示 (6分钟)**
|
||
|
||
**师:** 好,现在我们来见证今天最重要的时刻——让两个同学的角色真的打一场。
|
||
|
||
【选两个进度最快的学生,把他们的 pk-battle.html 分别投屏,或者其中一个学生的对战画面投屏全班观看】
|
||
|
||
**师:** 我们先看左边——这个角色是什么打法?
|
||
|
||
**生(观察者):** (预期:高攻击型 / 速度型 / 防御型)
|
||
|
||
**师:** AI 对手用的是默认属性。先看第一回合谁先出手——
|
||
|
||
【运行对战,全班实时观看,教师边打边念战斗日志】
|
||
|
||
**师:** 看到没,先手机制起作用了——SPD 高的先出手。现在玩家用重击——
|
||
|
||
【展示重击效果,强调伤害计算是按需求文档的公式来的】
|
||
|
||
**师:** 这场对战里有哪条规则你们觉得体现得最清楚?
|
||
|
||
**生:** (预期:先手 / 格挡减伤 / 特技限制次数)
|
||
|
||
**【环节】互评与讨论 (4分钟)**
|
||
|
||
**师:** 现在回顾今天的工作。今天你们打开了几个窗口,每个窗口做什么?
|
||
|
||
**生:** (预期:窗口 A 写需求,窗口 B 找边界,窗口 C 生成代码,窗口 D 做测试)
|
||
|
||
**师:** 对。这四个窗口,缺一个会出什么问题?比如如果跳过窗口 B——
|
||
|
||
**生:** (预期:边界情况没想到,游戏对战时可能出 bug)
|
||
|
||
**师:** 如果窗口 D 不开新窗口,在窗口 C 里让 AI 测自己的代码——
|
||
|
||
**生:** (预期:AI 会偏袒自己,测试结果不可信)
|
||
|
||
**师:** 今天遇到最大的挑战是什么?
|
||
|
||
**生:** (预期 A:「边界情况想不到」/ 预期 B:「看懂测试失败的原因」/ 预期 C:「导入 Spritesheet」)
|
||
|
||
**师:** 你们今天写需求、审核、生成、验收、测试——5 个步骤。这 5 步,哪一步对你来说最有收获?
|
||
|
||
**生:** (开放回应,教师倾听,不评判)
|
||
|
||
**师:** 我来说说我的观察——今天做得最好的事,是大家在遇到 bug 时,第一步不是「让 AI 帮我改」,而是先问「哪条需求没说清楚」。这个习惯,今天有人做到了,有人还在培养。没关系——这个习惯养成了,你做任何项目都会比别人少踩很多坑。
|
||
|
||
---
|
||
|
||
**第四幕:延续 (Continue) — 5分钟** 🚀
|
||
|
||
**【环节】抽象总结 (3分钟)**
|
||
|
||
**师:** 今天我们做了一件很重要的事——让「脑子里的规则」变成「代码里真正执行的规则」,中间经过了几个步骤?
|
||
|
||
**生:** (预期:写需求、找边界、生成代码、验收、测试脚本)
|
||
|
||
**师:** 对。这个流程不只是做游戏用的——以后你做任何项目,只要涉及「规则」,都要走这个流程。规则越复杂,「找边界」这步就越重要。
|
||
|
||
**师:** 今天你们掌握的能力有一个名字,叫**「测试驱动验证」**——先定规则,再写代码,再用测试检查代码是不是真的按规则跑。这是真实开发团队的工作方式,不是只有高手才能用的,你们今天已经用上了。
|
||
|
||
**师:** 还有一个能力——「边界意识」。以后遇到任何系统,你的第一反应不是「正常情况怎么用」,而是「边界情况、异常情况怎么处理」。这个意识让你的系统更稳定,bug 更少。
|
||
|
||
**师:** 边界意识不只是写代码时用的。你们有没有玩过一个游戏,有个 bug 特别烦——比如某个角色在特定情况下无敌,或者某个技能叠加 20 层秒杀对手——这些 bug 从哪里来?就是设计师在写规则的时候,没有考虑到「如果玩家这样做怎么处理」。你们今天练习的,就是这个能力。
|
||
|
||
**【环节】下节预告 + 5分钟挑战 (2分钟)**
|
||
|
||
**师:** 现在你们的战斗系统能跑,逻辑是对的,但角色还是矩形占位符。下节课我们做什么?
|
||
|
||
**生:** (预期:换成自己的图?/ 加动画?)
|
||
|
||
**师:** 对——下节课我们把你的 Spritesheet 真正加进战斗系统,受击有闪烁效果,攻击有前摇后摇,死亡有倒下动画。你的角色会真的「活起来」。
|
||
|
||
**师:** 本周 5 分钟 AI 挑战——让 AI 帮你写一条需求文档里没有的边界情况测试,提交到测试脚本里,看是否通过。如果通过了,说明你的代码比需求文档还严格;如果没通过,说明你发现了一个新 bug。下节课分享。
|
||
|
||
**师:** 最后一件事——在 pk-battle.html 的顶部注释里,写上你的角色名、打法定位一句话总结,还有今天你发现的最有意思的一条边界情况。格式随意,只要下节课你打开文件,还能想起今天做了什么。
|
||
|
||
---
|
||
|
||
### 5. AI助教使用指南
|
||
|
||
**教师演示用提示词(窗口 A,需求文档整理):**
|
||
|
||
```
|
||
你是一个需求分析师。我要做一个基于 HTML/CSS/JS 的回合制战斗游戏,规则如下:
|
||
- 先手机制:SPD 高的角色先出手;同速时随机决定(或编号小的先手,明确规定一种)
|
||
- 伤害公式:ATK - DEF,最低造成 1 点伤害
|
||
- 行动类型:普通攻击(按公式)/ 重击(伤害×1.8)/ 格挡(本回合受伤减少50%)/ 特技(每场只能用一次,效果来自角色JSON的skill字段)
|
||
- 胜负判定:HP≤0 判输,立即结束
|
||
- AI对手决策:HP低于30%用特技;25%概率重击;否则普通攻击
|
||
|
||
请把这些需求整理成规范需求文档,包含:功能描述、触发条件、功能规则、边界情况说明、验收标准。
|
||
```
|
||
|
||
**边界审核用提示词(窗口 B,独立新对话):**
|
||
|
||
```
|
||
你是一个游戏测试工程师。以下是战斗系统需求文档,请列出所有你能想到的边界情况和异常情况(例如:同速时谁先出手?特技已用完再点会怎样?格挡叠加重击怎么算?双方同时HP≤0怎么判?),只列问题,不需要解答:
|
||
|
||
[粘贴需求文档]
|
||
```
|
||
|
||
**测试脚本生成(窗口 D,独立新对话):**
|
||
|
||
```
|
||
以下是我的战斗系统需求文档:
|
||
|
||
[粘贴需求文档]
|
||
|
||
请帮我写一个 JavaScript 测试脚本(单文件 HTML),验证以下4条规则:
|
||
1. 伤害公式:ATK=15, DEF=5 → 伤害=10;ATK=5, DEF=10 → 伤害=1(最低1点)
|
||
2. 先手判定:SPD=8 vs SPD=5 → SPD=8 的先出手
|
||
3. HP≤0 → 游戏结束标志为 true
|
||
4. 重击倍率:ATK=10, DEF=2, 重击 → 伤害=(10-2)×1.8=14(取整)
|
||
|
||
每条测试显示"✅通过"或"❌失败:期望XXX,实际XXX"。用纯 HTML/JS,不需要 Phaser.js。
|
||
```
|
||
|
||
**学生保底提示词(窗口 C,生成战斗系统骨架):**
|
||
|
||
```
|
||
请帮我用纯 HTML/CSS/JS(单文件)做一个回合制战斗游戏:
|
||
|
||
角色数据从 JS 对象读取(字段:name/hp/maxHp/atk/def/spd/skill):
|
||
- 玩家角色在左边,AI 对手在右边
|
||
- 先用彩色矩形代替角色图片(稍后替换)
|
||
|
||
战斗规则:
|
||
- 先手:SPD 高的先出手;同速时随机
|
||
- 伤害公式:ATK - DEF,最低 1 点
|
||
- 四种行动按钮:普通攻击 / 重击(×1.8)/ 格挡(本回合受伤-50%)/ 特技(每场限用一次)
|
||
- AI对手逻辑:HP<30%用特技;25%概率重击;否则普通攻击
|
||
- HP≤0 判输,显示胜负结果,提供「再来一局」按钮
|
||
|
||
界面要求:
|
||
- 双方头顶有 HP 血条(数值显示)
|
||
- 底部有战斗日志(最近3条)
|
||
- 特技用完后按钮变灰不可点击
|
||
|
||
只给骨架,角色图片先用矩形占位,单文件 HTML。
|
||
```
|
||
|
||
**进阶提示词(替换 Spritesheet):**
|
||
|
||
```
|
||
以下是我的 pk-battle.html 中绘制角色的代码片段:[粘贴相关代码]
|
||
|
||
请修改角色绘制逻辑,把左边玩家角色的矩形替换为 Spritesheet 图片显示:
|
||
- Spritesheet 文件名:player-sprite.png,128×64 像素
|
||
- 帧1(x=0, y=0, w=64, h=64):待机状态
|
||
- 帧2(x=64, y=0, w=64, h=64):攻击状态
|
||
- 平时显示帧1,玩家攻击时显示帧2 持续 300ms 后恢复帧1
|
||
- 图片要等比缩放,显示在原来矩形的位置
|
||
```
|
||
|
||
---
|
||
|
||
### 6. 教师指南
|
||
|
||
**本课技术备注:**
|
||
|
||
- **Spritesheet 导入**:`new Image()` → `onload` → `ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)`。sx/sy 是帧在图片中的起始坐标,sw/sh 是帧的宽高,dx/dy 是画布上的目标位置,dw/dh 是目标大小。教师需要理解这 8 个参数的含义,学生不需要记,只需知道「帧1=x0,帧2=x64」。
|
||
- **回合制 vs 实时战斗**:本课做的是回合制(玩家点一次按钮 = 一个回合)。教师不要混淆,不要和「帧循环/requestAnimationFrame」扯在一起,那是下节课动画的内容。
|
||
- **先手机制的实现**:在回合开始时比较 SPD,高的先执行攻击逻辑,低的后执行。同速时 `Math.random() < 0.5` 决定。这个逻辑放在「玩家点击行动按钮」的事件处理函数里。
|
||
- **格挡状态**:格挡是一个「状态标记」(如 `isBlocking = true`),在本回合受到伤害时检查这个标记,伤害减半后重置标记。注意:格挡对「下一次受到的攻击」生效,还是「本回合」生效,需在需求里明确(本课设计为「格挡后敌方先手攻击时生效」)。
|
||
- **测试脚本独立窗口**:这是本课最重要的原则。测试脚本里的战斗逻辑函数是「从需求文档重新实现」的独立版本,不引用 pk-battle.html 的代码——所以必须在独立窗口生成,让 AI 按需求文档写,而不是看着自己的代码写测试。
|
||
|
||
**常见问题 FAQ:**
|
||
|
||
| 问题 | 应对 |
|
||
|------|------|
|
||
| 「特技按钮用了还能继续按」 | 引导学生检查需求文档里「特技每场限用一次」的验收标准写了什么,再在代码里找特技的触发逻辑,看有没有加 `skillUsed` 标记 |
|
||
| 「测试脚本生成出来全部通过,但游戏实际打起来伤害不对」 | 说明测试脚本和游戏代码用的是两套独立实现。先确认测试脚本按需求文档写,再对照游戏代码里的实现,找两者差异 |
|
||
| 「Spritesheet 图片不显示,一片黑」 | 99% 是路径问题——图片文件和 HTML 文件要放在同一个目录,路径写相对路径。让学生把 HTML 和 PNG 放到同一个文件夹再刷新 |
|
||
| 「重击的伤害计算和我预期不一样」 | 让学生打开战斗日志,找重击那行,用计算器手算一遍:(ATK - DEF) × 1.8,取整,对比日志里的数值 |
|
||
| 「AI 对手一直用特技,根本不普通攻击」 | AI 对手的决策逻辑里「HP<30%用特技」的判断可能有 bug——HP 初始值设置不对,或者条件写反了。引导学生检查 AI 对手的 maxHp 和当前 hp 的比较逻辑 |
|
||
| 「窗口 B 没问出什么问题」 | 提示学生在提示词末尾加一句:「请特别关注:同速先手、特技用完再点、格挡叠加重击、双方同时归零 这四个场景」 |
|
||
| 「测试脚本里 ✅ 全通过,但我不知道这说明什么」 | 说明你的战斗逻辑函数在这 4 种情况下是正确的。测试脚本是「护栏」——以后你改代码,再跑一次,如果还是全通过,说明你没有破坏原来的逻辑 |
|
||
| 「怎么知道 AI 对手「25%概率重击」是不是真的 25%?」 | 这是个好问题。严格测试需要跑 100 次统计分布,但我们的课堂不做这个。你可以告诉 AI「请解释这段 AI 决策代码里重击概率是如何实现的」,让 AI 用中文解释给你看 |
|
||
|
||
**课堂风险预案:**
|
||
|
||
- **如果 AI 服务不可用(Kimi 宕机)**:切换到 Trae IDE 的内置 AI 对话,或使用教师备用的 demo-2-pk-battle.html 直接展示;学生完成需求文档部分,代码生成推迟
|
||
- **如果学生进度差异过大**:进度快的学生做拓展(导入 Spritesheet + 写边界测试);进度慢的学生保证完成「战斗骨架能跑通 + 普通攻击验收通过」即可,其余留作课后
|
||
- **如果有学生上节课的 Spritesheet 未完成**:提供默认占位图(单色 128×64 PNG),确保不因图片问题卡住当天进度
|
||
|
||
---
|
||
|
||
### 7. 5分钟日常AI挑战
|
||
|
||
**本周挑战:** 让 AI 帮你写一条「需求文档里没有的」边界测试,看看能不能通过
|
||
|
||
**挑战说明:**
|
||
打开窗口 D(全新对话),告诉 AI:「我的战斗系统需求文档里有这些规则:[粘贴你的需求文档]。请帮我写一条我没有明确写进需求的边界测试——就是那种「正常情况不会想到,但真实对战时可能出现」的场景。」把这条新测试加入你的 pk-test.html,运行,看是通过还是失败。把结果(截图或描述)带到下节课分享。
|
||
|
||
**下节课分享:** 下节课选 2-3 位同学展示——「我写的新边界是什么,测试结果如何,有没有发现 bug」
|
||
|
||
---
|
||
|
||
### 8. 拓展任务
|
||
|
||
**拓展一(推荐):** 把你的 Spritesheet 真正导入 pk-battle.html,用 `drawImage` 替换矩形占位符;不需要动画,只要图片能显示在正确位置。验收标准:打开游戏,左边角色是你自己画的图,不是矩形。
|
||
|
||
**拓展二(挑战):** 给你的战斗系统加一条新的行动类型:「反击」——格挡时如果对方用了重击,本回合额外反弹 30% 伤害给对方。先把这条规则写进需求文档,在窗口 B 审核边界情况(格挡+反击叠加怎么算?反击触发条件是什么?),然后在窗口 C 生成新代码,在窗口 D 补充测试用例,确保测试通过。
|
||
|
||
**拓展三(终极挑战):** 做一个双人对战模式——两个玩家分别控制左边和右边的角色,轮流点行动按钮。需求文档里要写清楚:轮次如何切换、一方操作完后如何提示另一方、胜负后如何重新开始。先写需求,再生成,再测试。
|
||
|
||
---
|
||
|
||
> 本教案遵循穹狼科创 SDDT + 4C 教学方法论编写,配合 `教学方法论规则.md` 和 `标准教案模板.md` 使用。
|