游戏阶段流程
TuringHunt 基于**阿瓦隆(Avalon)**规则,游戏通过 phase 字段驱动 UI 切换。
阶段状态机
waiting
└─► speaking
└─► team_select
└─► team_vote
├─► (approved) mission
│ ├─► (未决) team_select (下一任务)
│ └─► (邪恶 3 胜) assassin
│ └─► game_over
└─► (rejected × 5) game_over好人方完成 3 次任务且进入
assassin阶段后,若刺客猜中梅林,邪恶方仍可翻盘。
各阶段说明
waiting — 等待房间
组件:WaitingRoom.tsx
玩家列表实时展示所有已加入的玩家。房主(或任意玩家)点击"开始游戏"后,服务端分配角色并广播 ROLE_ASSIGNED 消息。
关键交互:
- 发送
{ type: "START_GAME", data: null }
speaking — 发言阶段
组件:SpeakingPhase.tsx
玩家按顺序依次发言,每次只有当前 currentSpeakerId 的玩家可以输入内容。发言内容经服务端广播后,所有人的 SpeechHistorySidebar 实时更新。
状态字段:
isSpeaker— 当前轮是否轮到自己发言currentSpeakerId— 正在发言的玩家 IDspeeches— 本轮实时发言流
关键交互:
- 发送
{ type: "SPEECH", data: { content } }提交发言 - 发送
{ type: "END_SPEECH", data: null }结束本人发言
team_select — 组队阶段
组件:TeamSelectPhase.tsx
当前领袖(leaderId)从玩家列表中选择 requiredTeamSize 名成员组成任务队伍。
状态字段:
leaderId— 当前领袖的 user_idrequiredTeamSize— 本任务所需队员人数
关键交互(仅领袖可操作):
- 发送
{ type: "SUBMIT_TEAM", data: { team: string[] } }
team_vote — 队伍投票阶段
组件:TeamVotePhase.tsx
所有玩家对提议的队伍进行公开投票(赞成/反对)。服务端收集全部投票后广播 TEAM_VOTE_RESULT。
连续 5 次投票失败(consecutiveVoteFailures === 5)时游戏直接结束,邪恶方获胜。
关键交互:
- 发送
{ type: "VOTE", data: { vote: boolean } }
结果展示:VoteResult.tsx overlay 临时显示后自动消失。
mission — 任务执行阶段
组件:MissionPhase.tsx
只有被选中的队员可以操作。好人队员只能投成功票;邪恶队员可以选择成功或失败。投票结果通过 MISSION_RESULT 广播(只显示失败票数,不公开具体投票人)。
关键交互(仅任务队员):
- 发送
{ type: "VOTE", data: { vote: boolean } }—true代表成功,false代表破坏
结果展示:MissionResult.tsx + MissionTracker.tsx 顶部进度更新。
assassin — 刺杀阶段
组件:AssassinPhase.tsx
好人方已赢得 3 次任务,但游戏尚未结束。刺客玩家(role === "assassin")需要从好人阵营中指定一名玩家,若猜中梅林(Merlin),邪恶方翻盘获胜。
关键交互(仅刺客):
- 发送
{ type: "ASSASSIN_CHOOSE", data: { target_id: string } }
game_over — 游戏结束
组件:GameOver.tsx
服务端推送 GAME_OVER 消息,包含:
winner—"good"或"evil"reason— 胜利原因role_reveal— 全员身份公开映射表
阶段切换动画
每次 phase 变更时,PhaseAnnouncement.tsx 组件会在全屏弹出一个 framer-motion 动画公告,持续约 2 秒后自动消失,避免玩家错过阶段切换提示。