# 声控狗叫对战 2D 浏览器游戏设计与实现计划 ## 目标 基于用户提供的视频: `C:\Users\DSK\Videos\一款双方比狗叫的游戏 - 1.一款双方比狗叫的游戏(Av116504192360177,P1).mp4` 提取其中“双方比狗叫”的核心玩法,并按照 BDD / TDD / DDD 的方法,为 Genarrative 中可运行于浏览器的 2D 游戏方案生成一份可落地设计与实现思路。实现方向遵循仓库内 `game-studio` 插件工作流,默认采用 2D Phaser + TypeScript + Vite + DOM HUD 的浏览器游戏架构。 本计划仅做方案设计,不直接编码。 ## 当前上下文与输入分析 ### 已识别视频核心画面 通过抽帧观察,视频中的游戏呈现出以下稳定特征: - 画面是横版 2D 手绘舞台,场景包括公园、海边等固定关卡背景。 - 双方各有一只狗作为对战角色,站在左右两侧。 - 中央有明显倒计时,例如 `30`、`28`。 - 顶部有红蓝双方拉锯式能量条 / 进度条。 - 中央提示出现:`对着麦克风汪一声`、`用声音大小 + 叫声次数推动能量条!` - 玩家输入不是传统键鼠,而是麦克风声音。 - 玩家需要模仿狗叫,系统根据声音大小与叫声次数推动能量条。 - 屏幕会根据叫声出现 `BARK`、`WOOF`、`WAN`、`WANGOOF` 等拟声词与冲击波视觉反馈。 - 回合结束时,根据能量条偏向或推进结果判定胜负。 ### 提炼出的核心玩法 这是一个“声控拔河式狗叫对战”小游戏: - 两名玩家 / 一名玩家对 AI 分别代表左右两只狗。 - 每局限时 30 秒。 - 玩家通过麦克风持续发出狗叫声。 - 游戏实时分析音量峰值、叫声次数、叫声节奏。 - 声音越大、叫声越密集,己方推动力越强。 - 顶部能量条在双方推动力差值下左右移动。 - 时间结束后,能量条偏向哪一方,哪一方获胜。 ### 需要合理抽象的地方 视频中存在直播弹幕、贴图、表情包、遮挡层,这些不是游戏本体机制。本方案只吸收游戏本体核心: - 双方狗狗对叫 - 麦克风输入 - 声音强度 + 次数判定 - 红蓝拉锯能量条 - 限时回合 - 夸张拟声词与冲击波反馈 ## game-studio 插件路线 根据仓库内 `.hermes/plugins/game-studio` 技能: - 早期游戏工作先走 `game-studio` 总入口。 - 2D 浏览器游戏默认选择 Phaser。 - 架构上需要分离 simulation 与 renderer。 - HUD / 菜单 / 设置优先使用 DOM overlay,不把密集文字塞进 canvas。 - 玩法状态不应由 Phaser Scene 直接持有,Scene 只负责渲染、动画、相机、输入适配。 因此本方案采用: - Runtime:Phaser 3 - Language:TypeScript - Build:Vite - UI:React/DOM HUD overlay 或项目现有 DOM UI 层 - Audio input:Web Audio API + MediaDevices.getUserMedia - Simulation:纯 TS domain/service 层 - Renderer:Phaser Scene 读取 simulation snapshot 并播放动画/特效 ## 游戏概念设计 ### 游戏名建议 - 中文:`汪汪声浪大作战` - 英文代号:`bark-battle` - Play type ID 建议:`bark-battle` ### 玩家幻想 玩家不是通过按键战斗,而是真的对着麦克风“汪汪叫”,把自己的狗狗声浪推向对手。游戏目标是在倒计时结束前用更响、更密集、更有节奏的叫声赢得声浪拔河。 ### 核心动词 - 叫:对麦克风发出狗叫声。 - 推:通过叫声推动能量条。 - 压制:让能量条持续向对手方向倾斜。 - 爆发:短时间内连续高质量叫声触发冲击波。 - 防守:对手强势时通过持续叫声把能量条拉回。 ### 单局流程 1. 准备阶段 - 展示双方狗狗、地图、麦克风权限提示。 - 用户授权麦克风。 - 系统检测环境噪音并校准阈值。 2. 倒计时阶段 - 3、2、1 或中央 `30` 倒计时开始。 - 玩家看到提示:`对着麦克风汪一声`。 3. 对战阶段 - 每帧或固定 tick 采集麦克风音量。 - 根据音量峰值与短促叫声次数计算本方 barkPower。 - AI 或远端对手产生 opponentPower。 - 能量条根据 `playerPower - opponentPower` 拉锯。 - 狗狗张嘴动画、拟声词、冲击波按声音强度生成。 4. 结算阶段 - 30 秒结束。 - 能量条偏玩家侧则胜利,偏对手侧则失败,接近中线则平局。 - 展示叫声次数、最大音量、平均节奏、声浪评分。 5. 重开 / 返回 - 支持再来一局。 - 支持返回玩法入口或结果页。 ## 规则设计 ### 关键状态 ```ts type BarkBattlePhase = 'permission' | 'calibration' | 'countdown' | 'playing' | 'finished' type BarkBattleSnapshot = { phase: BarkBattlePhase remainingMs: number energy: number // -100 到 100,负数偏对手,正数偏玩家 player: BarkSideState opponent: BarkSideState winner: 'player' | 'opponent' | 'draw' | null } type BarkSideState = { barkCount: number currentVolume: number recentPeak: number combo: number power: number isBarking: boolean } ``` ### 输入判定 #### 音量采样 - 使用 Web Audio API 创建 `AnalyserNode`。 - 每个 simulation tick 读取频域或时域数据。 - 计算 RMS 或 peak volume。 - 根据校准后的环境噪音设置动态阈值。 #### 一次“叫声”的判定 一次有效叫声建议满足: - 音量超过 `barkThreshold`。 - 与上一次叫声峰值至少间隔 `minBarkGapMs`,避免持续噪音被无限计数。 - 持续时长在合理范围,例如 80ms 到 1200ms。 - 可选:频谱能量集中在中高频,不强制做复杂语音识别,MVP 先用音量 + 峰值节奏。 #### 推动力计算 ```text playerPower = volumeScore * 0.65 + barkRateScore * 0.35 + comboBonus opponentPower = aiPower 或远端玩家 power energyDelta = (playerPower - opponentPower) * deltaTime * balanceFactor energy = clamp(energy + energyDelta, -100, 100) ``` ### AI 对手 MVP 若先做单机浏览器版,右侧对手可由 AI 模拟: - 简单难度:周期性小叫,power 低。 - 普通难度:有节奏地爆发,power 中等。 - 困难难度:根据玩家领先程度自适应追赶,但不得作弊到不可赢。 后续可扩展为多人实时对战。 ## BDD 行为场景 ### 功能: 麦克风授权与准备 ```gherkin 功能: 狗叫对战麦克风准备 为了让玩家能用声音参与对战 作为浏览器玩家 我希望游戏在开局前明确请求麦克风权限并完成环境校准 场景: 玩家允许麦克风权限后进入准备倒计时 假如玩家打开狗叫对战页面 当玩家同意浏览器麦克风授权 那么系统应进入环境噪音校准阶段 而且校准完成后应显示开局倒计时 场景: 玩家拒绝麦克风权限 假如玩家打开狗叫对战页面 当玩家拒绝浏览器麦克风授权 那么系统应显示无法声控游玩的提示 而且应提供重试授权入口 而且不应直接开始对战 ``` ### 功能: 声音推动能量条 ```gherkin 功能: 声音大小和叫声次数推动能量条 为了复刻双方比狗叫的核心体验 作为玩家 我希望自己的叫声能实时推动顶部能量条 场景: 玩家发出一次有效狗叫 假如游戏处于 playing 阶段 而且麦克风输入音量超过有效叫声阈值 当系统检测到一次新的叫声峰值 那么玩家叫声次数应增加 1 而且玩家狗狗应播放张嘴吠叫动画 而且画面应出现拟声词反馈 场景: 玩家连续大声狗叫压制对手 假如游戏处于 playing 阶段 而且玩家在短时间内产生多次有效叫声 当玩家推动力高于对手推动力 那么顶部能量条应向玩家侧移动 而且玩家侧声浪特效应增强 场景: 环境噪音低于阈值不计入叫声 假如游戏处于 playing 阶段 当麦克风只有低于阈值的背景噪音 那么玩家叫声次数不应增加 而且能量条不应因为背景噪音明显移动 ``` ### 功能: 限时胜负结算 ```gherkin 功能: 狗叫对战胜负结算 为了让单局对抗有明确目标 作为玩家 我希望倒计时结束后根据能量条位置判定胜负 场景: 倒计时结束时玩家侧占优 假如游戏剩余时间归零 而且能量条位于玩家侧 当系统进入结算阶段 那么系统应判定玩家胜利 而且展示玩家叫声次数、最大音量和声浪评分 场景: 倒计时结束时双方接近平衡 假如游戏剩余时间归零 而且能量条处于平局阈值范围内 当系统进入结算阶段 那么系统应判定为平局 而且展示再来一局入口 ``` ### 功能: 移动端与无麦克风降级 ```gherkin 功能: 声控游戏移动端与无麦克风降级 为了让不同设备玩家都能理解当前状态 作为移动端或无麦克风环境玩家 我希望系统给出清晰、可操作的降级路径 场景: 当前浏览器不支持麦克风 API 假如玩家设备不支持 getUserMedia 当玩家进入狗叫对战页面 那么系统应显示设备不支持麦克风输入 而且提供返回入口 场景: 移动端进入对战页面 假如玩家使用移动端浏览器 当玩家进入狗叫对战页面 那么主要能量条、倒计时和狗狗角色应保持可见 而且非关键设置应收起到菜单中 ``` ## DDD 领域划分 ### 领域层:bark-battle domain 职责:只处理玩法规则,不依赖 Phaser、DOM、Web Audio、后端。 建议模块: - `BarkBattleSession` - 管理 phase、remainingMs、energy、winner。 - `BarkDetector` - 根据音量样本判断是否形成一次有效叫声。 - `EnergyTugOfWar` - 根据双方 power 更新能量条。 - `BarkBattleScoring` - 计算最大音量、叫声次数、combo、评分。 - `OpponentStrategy` - 单机 AI 对手策略接口。 领域规则必须可用纯单元测试验证。 ### 应用层:use case / controller 职责:编排麦克风输入、simulation tick、AI 对手、结果输出。 建议用例: - `requestMicrophonePermission()` - `calibrateAmbientNoise()` - `startBarkBattleSession()` - `submitAudioSample(sample)` - `tickBarkBattle(deltaMs)` - `finishBarkBattle()` ### 基础设施层 职责:浏览器 API 与引擎适配。 - `BrowserMicrophoneInput` - 封装 `navigator.mediaDevices.getUserMedia`。 - 输出 normalized volume samples。 - `PhaserBarkBattleScene` - 渲染狗狗、背景、拟声词、冲击波。 - 不持有核心玩法规则。 - `DomBarkBattleHud` - 展示倒计时、能量条、权限提示、结算面板。 ### 表现层 - Phaser Canvas:地图、狗狗、声浪、粒子、拟声词。 - DOM HUD:顶部能量条、倒计时、权限/结算/设置面板。 ## TDD 落地顺序 ### 第一轮:领域规则 RED-GREEN-REFACTOR 先写纯 TS 单元测试,不接 Phaser,不接麦克风。 目标测试: - `BarkDetector`:超过阈值且间隔足够时计为一次叫声。 - `BarkDetector`:持续噪音不会无限增加叫声次数。 - `EnergyTugOfWar`:玩家 power 高于对手时 energy 向玩家侧移动。 - `EnergyTugOfWar`:energy 被 clamp 在 -100 到 100。 - `BarkBattleSession`:倒计时归零后进入 finished。 - `BarkBattleSession`:根据 energy 判定 player/opponent/draw。 ### 第二轮:应用层测试 - 模拟音频 sample 输入,验证 session snapshot 更新。 - 模拟 AI 对手 power,验证能量条拉锯。 - 模拟权限失败,验证 phase 不进入 playing。 ### 第三轮:组件 / 集成测试 - HUD 根据 snapshot 显示倒计时。 - HUD 根据 energy 渲染红蓝能量条比例。 - 权限拒绝时显示重试入口。 - 结算阶段显示胜负与再来一局。 ### 第四轮:浏览器 smoke / playtest - 本地启动页面。 - 授权麦克风。 - 对麦克风发声后看到拟声词与能量条变化。 - 移动端宽度下主游戏画面不被 HUD 遮挡。 ## 建议文件结构 如果作为独立前端玩法原型,可采用: ```text src/games/bark-battle/ domain/ BarkBattleSession.ts BarkDetector.ts EnergyTugOfWar.ts BarkBattleScoring.ts OpponentStrategy.ts application/ BarkBattleController.ts BrowserMicrophoneInput.ts phaser/ BarkBattleScene.ts BarkBattlePreloadScene.ts barkBattleAssets.ts ui/ BarkBattleHud.tsx BarkBattleResultPanel.tsx BarkBattlePermissionPanel.tsx tests/ BarkDetector.test.ts EnergyTugOfWar.test.ts BarkBattleSession.test.ts ``` 如果接入 Genarrative 玩法类型闭环,后续还需要按 `genarrative-play-type-integration` 扩展: ```text src/components/bark-battle-runtime/BarkBattleRuntimeShell.tsx src/components/bark-battle-result/BarkBattleResultView.tsx src/services/barkBattleRuntimeClient.ts packages/shared/src/contracts/barkBattle.ts server-rs/crates/shared-contracts/src/bark_battle.rs ``` MVP 阶段建议先做浏览器单机 runtime 原型,再决定是否进入创作入口、作品发布、广场和后端持久化。 ## UI / 视觉方向 ### 画面 - 横版固定舞台。 - 左右两只狗对峙。 - 背景可先做公园一张图,后续扩展海边、街区等地图。 - 狗狗用 2D sprite 或简单骨架帧动画。 ### HUD - 顶部:红蓝声浪能量条。 - 中央:大号倒计时,只在开局和关键时间突出显示。 - 左右:双方狗狗状态,不堆叠复杂面板。 - 底部或角落:麦克风状态、小型重试按钮。 - 结算:居中弹出简洁面板,显示胜负和关键数据。 ### 动效 - 叫声触发狗狗张嘴。 - 声音越大,拟声词越大,冲击波越宽。 - combo 时触发短暂屏幕震动,但不能遮挡能量条。 - 尊重 reduced motion,非必要动画可降级。 ## 测试映射 | BDD 场景 | 测试层级 | 目标文件 | 状态 | | --- | --- | --- | --- | | 玩家允许麦克风权限后进入准备倒计时 | application/component | `BarkBattleController.test.ts`, `BarkBattlePermissionPanel.test.tsx` | planned | | 玩家拒绝麦克风权限 | application/component | `BarkBattleController.test.ts`, `BarkBattlePermissionPanel.test.tsx` | planned | | 玩家发出一次有效狗叫 | unit | `BarkDetector.test.ts` | planned | | 玩家连续大声狗叫压制对手 | unit/integration | `EnergyTugOfWar.test.ts`, `BarkBattleController.test.ts` | planned | | 环境噪音低于阈值不计入叫声 | unit | `BarkDetector.test.ts` | planned | | 倒计时结束时玩家侧占优 | unit | `BarkBattleSession.test.ts` | planned | | 倒计时结束时双方接近平衡 | unit | `BarkBattleSession.test.ts` | planned | | 当前浏览器不支持麦克风 API | component | `BarkBattlePermissionPanel.test.tsx` | planned | | 移动端进入对战页面 | visual/smoke | Playwright 或人工 playtest 清单 | planned | ## 验证命令建议 具体命令以后续实际落地位置为准,建议包括: ```bash npm run test -- --run src/games/bark-battle/**/*.test.ts npm run test -- --run src/games/bark-battle/**/*.test.tsx npm run typecheck npm run check:encoding ``` 若接入 Genarrative 后端或玩法配置,还需要追加: ```bash cd server-rs && cargo check -p api-server -p shared-contracts --no-default-features npm run test -- src/components/platform-entry/platformEntryCreationTypes.test.ts ``` ## 实施阶段拆分 ### Phase 0:产品与技术定稿 - 确认玩法 ID:`bark-battle`。 - 确认 MVP 只做单机玩家 vs AI,不做实时多人。 - 确认是否只做 runtime 原型,还是接入 Genarrative 创作入口。 - 确认是否允许浏览器麦克风权限作为核心输入。 ### Phase 1:纯领域模型 - 建立 bark-battle domain。 - 按 TDD 写 `BarkDetector`、`EnergyTugOfWar`、`BarkBattleSession` 测试。 - 实现最小规则让测试通过。 ### Phase 2:麦克风输入适配 - 封装 Web Audio API。 - 支持权限请求、权限失败、环境噪音校准。 - 使用 mock input 完成自动化测试,真实麦克风做 smoke。 ### Phase 3:Phaser 2D runtime - 新建 Phaser Scene。 - 绘制或占位加载公园背景、左右狗狗、声浪特效。 - Scene 只消费 snapshot,不写规则。 - 接入 DOM HUD。 ### Phase 4:反馈与结算 - 加入拟声词、冲击波、狗狗张嘴动画。 - 加入结算面板。 - 加入再来一局与返回入口。 ### Phase 5:Genarrative 集成可选项 若要正式接入玩法类型: - 补 `shared-contracts` 中 bark-battle runtime/result DTO。 - 补前端 service 与 runtime shell。 - 补入口配置数据库 seed。 - 补作品架 / 发布 / 广场链路,若需要持久化成绩或作品。 - 按 `genarrative-play-type-integration` 执行完整闭环验证。 ## 风险与权衡 ### 麦克风权限风险 浏览器麦克风权限受 HTTPS、浏览器策略、用户设置影响。MVP 需要明确: - 本地开发可在 localhost 使用。 - 线上必须 HTTPS。 - 权限拒绝需要可恢复。 ### 声音识别准确性风险 MVP 不建议做复杂“是否真的是狗叫”的 AI 识别,否则实现成本高、误判多。建议先用: - 音量阈值 - 峰值次数 - 节奏间隔 - 环境噪音校准 后续再考虑加入频谱特征或 ML 分类。 ### 噪音作弊风险 玩家可以喊叫、拍桌子或播放音频。若是娱乐派对玩法可以接受;若要竞技公平,需要后续加入: - 频谱特征 - 输入冷却 - 异常持续噪音削弱 - 本地/服务端反作弊策略 ### 移动端兼容风险 移动端 Web Audio 可能需要用户手势激活 AudioContext。计划中需把“开始”按钮作为显式用户手势,避免自动启动失败。 ### UI 遮挡风险 视频原型中的核心可读信息非常少:倒计时、能量条、狗狗、拟声词。实现时应避免把说明文案、复杂面板长期铺在画面上。 ## 开放问题 1. MVP 是“玩家 vs AI”,还是需要从第一版开始支持双人同屏 / 联机? 2. 是否要作为 Genarrative 新玩法入口完整接入,还是先做独立 runtime 原型? 3. 是否需要记录成绩、发布作品、进入作品架和广场? 4. 狗狗与背景素材是使用临时占位、AI 生成,还是需要复用项目既有素材系统? 5. 是否允许游戏强依赖麦克风权限,还是必须提供键盘备用输入? ## 推荐下一步 建议下一步先执行 Phase 0 + Phase 1: 1. 明确 MVP 边界:单机玩家 vs AI。 2. 写 `BarkDetector` / `EnergyTugOfWar` / `BarkBattleSession` 的 BDD 对应单元测试。 3. 不接 Phaser、不接麦克风,先把核心规则用 TDD 跑通。 4. 规则稳定后再接 Web Audio 与 Phaser runtime。