Files
CodeLikeDemo/03-技术架构关键路径.md
2026-03-27 18:21:29 +08:00

7.3 KiB
Raw Permalink Blame History

🏗️ 《Project Vibe: Ship It!》技术架构与关键路径文档

一、 技术栈选型 (Tech Stack)

强烈建议在 Prompt 开头向 AI 明确这些技术栈,防止它自由发挥引入不兼容的库。

  • 前端框架: React 18 + Vite (纯前端单页应用,无需复杂后端)。
  • 开发语言: TypeScript (极其重要!严格的类型定义是 VibeCoding 不翻车的绝对保障)。
  • 状态管理: Zustand (极其推荐!比 Redux 轻量,比 Context 性能好,非常适合做游戏的状态机更新)。
  • 样式方案: Tailwind CSS (方便 AI 快速生成好看的 UI 卡片)。
  • 拖拽与动画: framer-motion (处理卡牌平滑移动和翻转动画) + 原生 Pointer Events (处理自由桌面坐标 x,y不要用基于网格的 dnd-kit,因为我们要的是类似操作系统的无网格自由堆叠)。

二、 核心数据模型 (Data Models - TypeScript Interfaces)

这是整个系统的灵魂。第一步请先让 AI 生成并完善这些类型定义文件 types.ts。有了它AI 后续写的逻辑就不会乱。

// 1. 卡牌基础模型
export interface Card {
  id: string;              // 唯一实例ID (uuid)
  templateId: string;      // 对应配置表中的模板ID (如 'dirty_code', 'developer')
  name: string;
  type: 'resource' | 'actor' | 'module' | 'crisis' | 'warning'; 
  tags: string[];          // 用于危机判定 (如 ['need_test', 'human'])
  position: { x: number; y: number }; // 桌面绝对坐标
  status: 'idle' | 'dragging' | 'processing' | 'locked'; 
  processEndTime?: number; // 如果在合成中/危机倒计时中,记录结束的绝对时间戳
}

// 2. 合成配方模型 (静态配置)
export interface Recipe {
  id: string;
  inputs: string[];        // 需要堆叠在一起的 templateId 列表
  timeMs: number;          // 合成所需时间 (毫秒)
  outputs: Array<{ templateId: string; chance: number }>; // 产物及概率
}

// 3. 全局状态模型 (Zustand Store)
export interface GameState {
  // --- 资源状态 ---
  funds: number;           // 项目资金
  sprintTimeRemaining: number; // 当前 Sprint 倒计时
  sprintNumber: number;    // 当前处于第几个 Sprint
  
  // --- 实体状态 ---
  cards: Card[];           // 桌面上的所有卡牌
  
  // --- 核心方法 (Actions) ---
  moveCard: (id: string, x: number, y: number) => void;
  checkCraftingOverlap: (cardId: string) => void; // 碰撞检测核心逻辑
  tick: () => void;        // 游戏主循环 (Game Loop),每帧/每秒更新状态
  triggerCrisis: (crisisData: any) => void; // LLM 返回后触发危机
}

三、 系统架构设计图 (单向数据流)

游戏的架构必须是数据驱动的。UI 层只负责渲染 cards 数组和捕获鼠标事件。

 [ 玩家操作 (拖拽/松开) ] 
         │
         ▼
 [ 操作意图 (Pointer Events) ]  ──发起请求──> [ LLM 危机生成器 (异步 Hook) ]
         │                                        │ (返回JSON/超时Fallback)
         ▼                                        ▼
 [ 碰撞检测算法 (Overlap Check) ]               [ 触发预警卡/危机卡生成 ]
         │                                        │
         ▼ (匹配 Recipe)                          │
 [ 状态机引擎 (Zustand Store) ] <─────────────────┘
   ├─ 更新卡牌坐标 (x, y)
   ├─ 锁定卡牌状态 (status: 'processing')
   └─ 结算资金/时间 (funds, sprintTime)
         │
         ▼ (响应式数据)
 [ React 渲染层 (UI Components) ]
   ├─ <DesktopBoard /> (渲染桌面)
   ├─ <CardItem /> (渲染实体卡、倒计时进度条)
   └─ <HudPanel /> (渲染顶部资金与时间)

四、 VibeCoding 关键开发路径 (Critical Paths)

千万不要让 AI “一口气写一个游戏”。请严格按照以下 4 个阶段向 AI 提需求 (Prompting),每完成一个阶段就运行测试,确保无误后再进入下一阶段。

🚩 Path 1: 静态桌面与全局状态 (The Dumb Board)

  • 目标: 能在屏幕上看到几张卡牌,资金数值能够显示。
  • AI 任务:
    1. 初始化 Vite + React + TS 项目,安装 Zustand 和 Tailwind。
    2. 创建 types.ts(使用上面提供的模型)。
    3. 创建 useGameStore.ts (Zustand),初始化几个假数据卡牌 (Mock Data)。
    4. 编写 <DesktopBoard><CardItem> 组件。卡牌通过绝对定位 absolute 渲染在对应的 x, y 坐标上。

🚩 Path 2: 自由拖拽与物理碰撞 (Drag & Collision)

  • 目标: 卡牌可以被鼠标拖拽,松开鼠标时,能判断两张卡是否重叠。
  • AI 任务:
    1. <CardItem> 添加 onPointerDown, onPointerMove, onPointerUp 事件。
    2. 拖拽时,调用 Store 的 moveCard 更新坐标。
    3. 核心算法要求: 松开鼠标时,写一个 checkOverlap(cardA, cardB) 函数(通过判断两个矩形的边界 bounding box 是否相交)。如果重叠率超过 50%,则判定为“堆叠成功”。

🚩 Path 3: 核心主循环与合成引擎 (Game Loop & Crafting)

  • 目标: 两张配方卡重叠 -> 出现进度条 -> 读条结束产出新卡。
  • AI 任务:
    1. 创建一个静态的 recipes.json(包含 2-3 个基础配方,如 开发+脏代码=模块)。
    2. 在 Store 中创建一个 requestAnimationFramesetInterval(..., 100) 驱动的 tick() 函数(这就是游戏的心跳)。
    3. 合成逻辑: 当卡牌重叠,匹配 JSON 成功后,将这两张卡的 status 改为 processing,并设置 processEndTime = Date.now() + timeMs
    4. 心跳检测: tick() 函数不断检查当前时间是否超过 processEndTime。如果超过,删除旧卡,在原坐标 push 新产物卡。

🚩 Path 4: LLM 异步危机总线 (The AI Director)

  • 目标: 每隔一段时间,根据桌面状态调用大模型,生成危机并处理延迟。
  • AI 任务:
    1. 编写一个独立的服务 llmService.ts
    2. 编写 useCrisisDirector 自定义 Hook。内部设置一个定时器如每 30 秒触发一次)。
    3. 时序逻辑编写:
      • 触发时:立刻在 Store 中推入一张 status 为 processing 的【预警卡】。
      • 发起 fetch 请求调用 OpenAI/DeepSeek API附带当前桌面状态。
      • 使用 Promise.race 实现 5 秒超时控制。
      • 请求 Resolve (或超时 Fallback) 时将那张【预警卡】的数据替换为真实的【危机卡】JSON 数据,并开始倒计时。

💡 给开发者的 VibeCoding 避坑指南 (Tips)

  1. 这是一个自由摆放的桌面,没有列表,只需要纯粹的 x,y 坐标更新和基于宽高的 AABB (Axis-Aligned Bounding Box) 碰撞检测。”
  2. 在 Zustand store 里统一管理所有状态。不要<CardItem> 组件内部用 useState 去管理倒计时!所有的进度条渲染都应该基于 processEndTime - Date.now() 实时计算得出,这样即使组件卸载/重新渲染,进度也不会丢失。
  3. Mock First 在写 LLM 接入时,用 setTimeout 模拟一个假的大模型返回。把游戏跑通了,最后再填入真实的 API Key 和 fetch 请求。