OutRun 伪 3D 复刻 —— Canvas 2D 伪 3D 街机赛车,TypeScript + Vite 构建,Vitest 单测 + bot 自动跑圈校验。
npm install # 安装依赖
npm run dev # 开发服务器 (http://localhost:5173)
npm run build # 类型检查 + 生产构建 (dist/)
npm run preview # 预览生产构建线上地址:https://joyful-d6glfqzna80c9f036-1252524693.tcloudbaseapp.com/ai-racing-games/
npm run build # 类型检查 + 生产构建(dist/)
npm run deploy # 上传 dist/ 至 CloudBase 静态托管 ai-racing-games/部署脚本 scripts/deploy-cloudbase.mjs 基于官方 @cloudbase/manager-node 静态托管 API 逐文件上传(等价原「CloudBase AI 工具 uploadFiles」语义:localPath=dist/xxx → cloudPath=ai-racing-games/xxx),认证信息全部来自环境变量,脚本不读写任何凭据文件:
$env:TCB_ENV_ID = 'joyful-d6glfqzna80c9f036' # 云开发环境 ID
$env:TENCENTCLOUD_SECRETID = '<你的 SecretId>' # 腾讯云 API 密钥(控制台 cam/capi 获取)
$env:TENCENTCLOUD_SECRETKEY = '<你的 SecretKey>'
npm run deploy # 也可指定目录:node scripts/deploy-cloudbase.mjs <localDir> <cloudPrefix>部署要点:
vite.config.ts已设置base: './'(相对路径)——静态托管部署在子目录ai-racing-games/下,绝对路径资源引用(/assets/xxx)会 404,相对路径任意子目录均可用- 上传内容含 PWA 全套(
sw.js/manifest.webmanifest/图标)与微信分享卡share-card-v2.png(og:image 引用完整 URL);旧版本 hashed 资源残留不影响访问,可按需在控制台清理 index.html含 no-cache meta;发布后用?v=<date>加随机参数访问可绕过浏览器/CDN 缓存验证新版本;菜单底部版本标签(copy.tsAPP_VERSION)可直观确认线上版本- PWA
manifest的start_url/scope已用相对路径./,与子目录部署兼容 - CloudBase 环境:
joyful-d6glfqzna80c9f036(ap-shanghai,静态托管域名joyful-d6glfqzna80c9f036-1252524693.tcloudbaseapp.com) - 安全:密钥仅注入当前终端会话环境变量,勿写入
.env/代码并入库;长期密钥建议用后轮换,或使用子账号临时密钥
npm run typecheck # tsc --noEmit
npm run lint # eslint
npm test # vitest run(单元测试)
npm run bot # bot 自动跑圈(输出圈速与违规报告)npm run bot 输出示例(classic 赛道,3 圈,实测值):
{
"laps": 3,
"lapTimesSec": [26.083, 51.05, 76.017],
"totalTimeSec": 76.017,
"avgSpeed": 3631.7,
"violations": 0,
"offRoadTimeSec": 0,
"passed": true
}另有性能与安全工具:
npm run bench # 性能基准(投影/漂移/输入热路径帧分配与耗时,--reuse 对比复用路径)
npm run scan # 安全静态扫描(innerHTML/监听器对称性/定时器/类型泄漏)- 任意键:开始游戏
- W / ↑:油门 S / ↓:刹车 A/D 或 ←/→:转向
- BOOST 氮气:P1 Space / P2 Enter(加速冲刺);蓄力 ≥80% 释放为完美氮气(加速度 +20%)
- 漂移小喷:漂移结束时按蓄力档位自动触发短时加速(蓝火短喷 / 橙火长喷)
- 贴身超车:高速贴近超越 NPC 车流获得 NEAR MISS 得分 + 蓄能(独立计分,不污染漂移榜);HUD 右上角合并显示「碰撞 ×N · 超车 ×M」
- 赛道奖牌:完赛总用时达到 bot 基准门槛即获 S/A/B 级奖牌(结算与菜单展示,只升不降)
- 成就系统:首次氮气/完美爆发/连击/贴身超车/雨天与夜晚完赛等 8 项成就,结算展示新解锁
- 挑战检查站:挑战模式每圈设检查点,提前通过 +2s 剩余时间(检查站制赚时间博弈)
- 随机天气:
?weather=random每局开局骰子决定晴/雨/夜;?weather=rain/?weather=sunny/?weather=night固定变体(影响雨天物理、雨声与渲染色板) - 车流橡皮筋:
?traffic=static关闭动态车流(固定速度);缺省 dynamic 车流随玩家速度平滑调整(快→提速保持挑战,慢→减速便于追赶) - Game Feel 强化:漂移得分飘字(+N 上浮渐隐,高连击 ≥5 时放大+橙色高亮)、near-miss 屏幕边缘脉冲线、完美氮气金色闪光、漂移小喷蓝色闪光、BOOST 速度线强化(更长更亮+金色叠加,呼应「冲刺」)、碰撞白色闪帧(高速撞击瞬时增强)、触发式短效反馈
- 路线模式:
?route=1|2|3|<id>进入 OutRun 式分段递进(每段跑 1 圈触发岔路选择,左/右切换下一段赛道;终点段跑完完赛;累计总用时与漂移得分;3 条预设路线:经典之旅 / 高手之旅 / 极限之旅;岔路选择时画面渲染左/右分叉引导带——OutRun 式视觉分叉带 + 0.3s 淡入动画 + 阶段预览展示左右下一段赛道名称与难度星级) - 导航辅助线:
?guide=1开启半透明青色引导线(沿道路中心线绘制,新手辅助过弯;缺省关闭资深玩家零视觉负担) - 每日挑战:菜单展示「今日挑战 · 赛道名 · 完成状态 · 连续 N 天」(基于日期确定性选择赛道,同日所有玩家同一挑战,跨日自动轮换);在今日赛道完赛即完成挑战并累计 streak(断签归 1);结算行追加「今日挑战完成」提示;
?daily=0关闭 - 菜单中按 1-9:切换赛道(9 条赛道,难度星级随赛道);分屏模式 P2 用 Shift+1-9
- Escape:暂停菜单(音量 / 音乐 / 音效三滑块 + 重开);R:返回菜单
- 完成所选赛道圈数后显示结算(热座模式回车交棒)
- 音效为 WebAudio 实时合成(含引擎音效、漂移摩擦/胎噪与 chiptune 背景音乐)
- 最佳圈速自动存档(localStorage);刷新页面后仍保留
- 漂移得分:高速急转蓄力进入 DRIFT 状态持续累计得分,结算展示
- 车流碰撞:赛道上有循环行驶的 NPC 车辆,碰撞大幅减速(1 秒冷却)
- 移动端触控:四分区映射 + 虚拟摇杆,多点并发;触屏可暂停
- 触屏提示适配:倒计时操作提示按设备显示——键盘玩家显示 WASD/方向键/空格,触屏玩家显示摇杆指引(分屏显示四分区指引,不误导「右下角摇杆」)
- 双人分屏:
http://localhost:5173/?split=1(P1 = WASD,P2 = 方向键) - 热座模式:
http://localhost:5173/?hotseat=1(两人交替,完赛回车交棒) - 挑战模式:
http://localhost:5173/?challenge=1(60 秒限时刷分,目标 5000 分) - PWA 离线:构建产物可安装并离线游玩(vite-plugin-pwa,自动更新)
| 里程碑 | 内容 | 状态 |
|---|---|---|
| M1 | 渲染骨架:伪 3D 路面分段投影、直道滚动、60fps 循环 | ✅ |
| M2 | 车辆物理:速度/加速度/转向、路缘限制、出界减速 | ✅ |
| M3 | 赛道系统:弯道分段路点、视差远山/天空、可配置赛道数据 | ✅ |
| M4 | bot 跑圈:沿路点自动行驶、圈速与违规报告(npm run bot) |
✅ |
| M5 | HUD、音效合成、启动画面、胜利结算、发布构建 | ✅ |
| 扩展 | 平滑弯道(控制点插值)、路边景物(树木/路灯)、漂移系统、双人分屏、最佳圈速存档 | ✅ |
| 扩展 2 | 车流与碰撞、漂移得分、关卡选单(3 赛道)、chiptune 背景音乐、移动端触控 | ✅ |
| M6-M7 | GameLoop 重构(DOM/初始化/流程控制/每帧编排下沉 game/ 层)、阶段 FSM 下沉 |
✅ |
| M8 | 双人 HUD 扩展(单屏 P2 BEST、热座玩家标签)、赛道自定义车流密度 | ✅ |
| M9 | 9 条赛道 + 难度星级选单、胜场统计、漂移得分 TOP10 排行榜 | ✅ |
| M10 | 车流避让 AI、各赛道 BEST 汇总、主音量调节、漂移连击倍率 | ✅ |
| M11 | 夜晚赛道(车灯/尾灯)、分屏对局 TOP10、触屏暂停、雨声/碰撞音、雨滴离屏渲染、得分 MAX 标记 | ✅ |
| M12 | 挑战模式(60s 限时刷分)、雨天物理、BOOST 氮气、车灯随变道转向、音乐/音效分轨音量 | ✅ |
| M13 | H 系列打磨:挑战计分加成、BOOST 音效与尾焰粒子、漂移连击入榜、lastLap 直返、碰撞音强度、9 赛道 bot 矩阵回归 | ✅ |
| M14 | 性能优化批次:曲率段离屏缓存(road-strip.ts)、小地图/赛道进度指示器(minimap.ts);死代码清理(collidePlayers 移除、仅测试导出迁移 tests/helpers/) |
✅ |
| M15 | 架构重构(mode-strategy/finish-accounting/frame-update/frame-render 下沉)、漂移摩擦声/胎噪、PWA 离线发布、菜单/结算动画升级、UI/UX 修复、CI 工程化(eslint/prettier/husky/lint-staged) | ✅ |
| M16 | 运行时实测修复(天空条纹/热座 P2 渲染/菜单光晕/移动端适配)、碰撞反馈增强(屏幕红闪 vignette + HUD 碰撞计数 + 双层碰撞音 + 横向弹开)、道路视觉优化(路面 9 带渐变 + 颗粒噪点)、倒计时提示文案与 README 同源(copy.ts)、shouldScheduleNextFrame 纯函数化、Playwright 视觉回归(npm run test:e2e,桌面 1280×720 + 移动横屏 812×375) |
✅ |
| M17 | 环境差异化(TrackDef.environment + environment.ts 配置,9 赛道天空/草地/远山/景物差异化)、差异化景物形状(cactus/palm/snowpile + rotation 随机化 + 沙漠小仙人掌)、地形扩展(沙漠沙丘/海岸海面波浪/峡谷岩壁锯齿顶线) |
✅ |
| M18 | UI/UX 深度打磨:可访问性(榜单卡片键盘展开 + focus-visible + ARIA + prefers-reduced-motion 降级)、颜色令牌化、屏幕切换过渡、碰撞/BOOST/漂移得分反馈增强、环境渲染细节(精灵限高/车灯色/路缘立体感)、文案 copy.ts 同源、移动端触屏引导浮层 | ✅ |
| M19 | 潜在改进点收尾:debug 钩子生产剥离(DEV 门控死码消除)、输入采集去重(collectSteerInputs 下沉 mode-strategy)、ui/gamestate 死层删除、e2e 玩法链路扩展(BOOST 蓄能 + 碰撞反馈,双 project) | ✅ |
| M20 | 运行期实测修复(大屏布局根因/portrait 旋转同步/路灯缩放上限/噪点降密度/暂停文案去重/视口缩放放宽)、HUD 行驶期修复(BOOST 条 bottom-center、速度线淡蓝白)、榜单菜单优化 v1-v3(独立展开/整体控制/dashboard 容器)、M20 收尾批次(HUD 脏值比对/roadStrip 宽度守卫/音频节点释放/样式三文件拆分/菜单专项测试)、CI e2e 大屏 1920×1080 project | ✅ |
| M21 | 菜单沉浸感优化与部署修复(2026-08-07):菜单修复批次(竖屏标题重叠归零/hover 预览联动/竖屏榜单默认收起/320 字号收敛/按钮 hover 光晕/榜单对比度)、赛道预览背景层(宽屏全屏赛道 SVG 背景 + 响应式降级 + 中央/背景双写联动)、菜单响应式布局修复(审计驱动:低高度桌面分支/移动横屏紧凑化/竖屏 rotate-hint 上移)、菜单整体感优化(#start-screen 背景叠加割裂修复)、静态托管子路径部署修复(vite base 相对路径 './');M21 收尾(2026-08-08):部署可见版本号(copy.ts APP_VERSION/APP_VERSION_DATE + index.html meta app-version + #app-version 菜单标签 + .version-tag 样式 + copy.test 版本断言 4 用例);验证:typecheck + lint + format:check + 938 用例 + bot 9 赛道 0 违规 + build PWA + e2e 40 通过 0 失败 |
✅ |
| M22 | P0 可玩性 v1(技巧与反馈):near-miss 贴身超车(独立计分 + 蓄能 + HUD 弹出 + 音效)、完美氮气(蓄力 ≥80% 释放 → 加速度 ×0.72 金色反馈)、漂移小喷(蓝火短喷/橙火长喷按蓄力档位 + 尾焰粒子)、NearMissSound 合成音效 | ✅ |
| M23 | P0 可玩性 v2(目标与长线):赛道 S/A/B 奖牌(bot 基准门槛 + 结算/菜单/赛道卡展示 + 只升不降存档)、成就系统(8 项成就 + 对局统计 + 结算新解锁展示 + 菜单进度)、挑战模式检查站(每圈 2 检查点 +2s 时间奖励,倒计时/完赛/HUD/结算同步纳入) | ✅ |
| M24 | P0 可玩性 v3(随机天气变体):?weather= 参数驱动(random 每局骰子晴/雨/夜三选一 + sunny/rain/night 固定变体)、lighting.resolveWeatherPhase 单一真源、渲染(雨滴/夜晚色板/车灯)与物理(wet 雨天制动转向/雨声/挑战加成)与成就(rain/night-finish)全链路对齐、菜单天气徽章 + debug 钩子 weatherOverride/weatherMode |
✅ |
| M25 | P0 可玩性 v4(车流橡皮筋动态难度):?traffic=static 关闭 / 缺省 dynamic、trafficRubberTarget 纯函数(speed/maxSpeed 线性映射 clamp [0.85,1.15])、PlayerState.trafficRubber 平滑收敛、updateTraffic 可选 speedFactor(缺省 1 零破坏 simulate/bot 确定性)、debug 钩子 trafficRubber/trafficDynamic |
✅ |
| M26 | P0 可玩性 v5(Game Feel 强化):漂移得分浮动飘字(+N 上浮渐隐,updateDriftPopup 纯函数)、near-miss 屏幕边缘脉冲线、完美氮气金色闪光、漂移小喷蓝色闪光(均触发式短效,非触发帧零绘制不破坏 e2e 天空像素断言)、viewFor 第 9 尾参 gameFeel 透传(分屏 P1/P2 各自特效) | ✅ |
| M27 | 运行时实测修复:经典赛道道路中央松树(ROAD_SIDE_OFFSET 1.4→1.55,同步 sprites.test 断言)、NEAR MISS! 飘字移到屏幕中央顶部(position:fixed 避开 HUD 区)、挑战 HUD 非 RACING 阶段防御性隐藏;M27 收尾批次:HUD 碰撞与 NEAR MISS 计数合并展示「碰撞 ×N · 超车 ×M」(热座感知当前玩家 nearMissCount)、菜单榜单「未知赛道」惰性清理(save.ts pruneDriftTop/pruneMatchTop,仅发现无效 trackId 时写回) | ✅ |
| M28 | P0 方案 9:OutRun 式分支路线模式(?route=1 | 2 |
| M28-b | P0 方案 10:导航辅助线(?guide=1 开启)——guide-line.ts 纯函数沿道路中心线投影(复用 bot 决策器走线语义 + curveOffsetAtZ 曲率偏移 + project 投影)绘制半透明青色引导线(近端实 0.55×strength → 远端 0 渐隐),RenderView 新增 guideStrength 字段透传,缺省 0 关闭零绘制(e2e 视觉零影响);FrameRenderContext 同步扩展,分屏/单屏/热座均透传;debug 钩子 guideStrength getter 供自动化验证 | ✅ |
| M29 | P2 方案 14:每日挑战 / 签到 streaks(轻量 live-ops)——daily.ts 纯函数模块(基于日期字符串确定性哈希选今日赛道 + createDailyState/rollDailyToToday/markDailyFinished 状态机);save.ts 加 DAILY_KEY 版本化存档(field 校验 + 损坏降级);finish-accounting 接入 daily 完成判定并返回 dailyDoneToday;菜单 #daily-progress 展示「今日挑战 · 赛道 · 状态 · 连续 N 天」;结算 #finish-daily 追加「今日挑战完成!连续签到 +1 天」;debug 钩子 dailyState getter;?daily=0 关闭开关 | ✅ |
| M30 | P0 方案 12 二次打磨(Game Feel 强化):① BOOST 速度线强化(drawSpeedLines boosting 参数:speedRatio 1 时基础层 len×1.6 + alpha×1.5 + 金色叠加层 alpha×0.5,呼应「冲刺」替代「镜头后拉」低风险方案);② 飘字 combo 联动(DriftPopup.combo 字段 + drawDriftPopup 高连击 ≥5 时 scale×1.35 + 字号 26→30px + 橙色 rgba(255,150,60) 高亮,强化连击成长反馈);PlayerState/frame-pure/gameFeelFor 同步扩展 combo 可选字段;零物理/确定性回归(纯 Canvas 特效层) | ✅ |
| M31 | P0 方案 9 深化(视觉分叉渲染)——guide-line.ts 新增 drawRouteFork 纯函数 + RouteFork 接口(道路末端向前 8 段开始分叉,左/右分支各向左右弯曲 6 世界单位偏移,60 段长度内投影采样 ~50 个点,模拟道路路面 28px 粗 stroke + 3px 亮色描边;颜色左青右橙与 #route-choice 按钮配色一致);RenderView.routeFork + FrameRenderContext.routeFork 字段透传;GameLoop.beginRouteChoice 计算 leftOffset/rightOffset(±6 = 3 倍车道宽),chooseRouteBranch/applyPhase 清除 routeFork;#route-choice 移除整屏遮罩改用面板级毛玻璃(让 Canvas 分叉引导带在覆盖层下方可见);guide-line.test.ts 4 测试 + frame-render.test 透传测试 | ✅ |
| M32 | P0 方案 9 与方案 12 三次打磨——① 方案 9 分叉淡入动画:GameLoop 维护 routeForkAlpha(routeChoosing 期间 dt*3.5 逐帧递增至 1,约 0.3s 淡入),RenderView/FrameRenderContext/frame-pure 同步透传,renderer 调用 drawRouteFork 时乘以 forkAlpha,beginRouteChoice 重置为 0;② 方案 9 阶段预览:岔路选择覆盖层新增 #route-choice-preview 元素,beginRouteChoice 填充「左路:<赛道名> · <★...> 右路:<赛道名> · <★...>」(难度星级从 TrackDef.difficulty 读取);③ 方案 12 碰撞白闪:screen-effects 新增 drawCollisionWhiteFlash 纯函数(flash²×0.18 全屏 fillRect,叠加红色 vignette 增强「撞击感」,研究报告「卡肉感」的低风险替代——不冻结帧/不影响 raceTime/bot 确定性),renderer 在 drawCollisionVignette 后调用;debug-hook 新增 routeForkAlpha getter 供自动化验证;新增测试:screen-effects 白闪 3 + frame-render 透传 1 + game-loop-integration 淡入 1(driver driveUntilChoice 辅助方法) | ✅ |
| M33 | 2026-08-08 运行实测修复批次(agent-browser 全量实测 + 小米 13 Ultra 横屏 1067×480 触屏专项):① 引导线 z-order 修复(renderer 移到车流之下防穿透车身,宽度 4→5px、近端 alpha 0.55→0.5);② 岔路提示与 BOOST 条间距(.route-choice-hint margin-bottom 28px);③ 路灯双层光晕(drawLamp 纯色圆方案,不污染 M16 vignette 计数断言);④ 分屏 P2 独立 BOOST 条(index.html #boost-bar-2 + frame-update splitMode 双条更新 + game-loop boostBar2 缓存透传 + CSS 左右半屏布局);⑤ 倒计时操作提示触屏适配(copy.ts COUNTDOWN_HINTS_TOUCH / COUNTDOWN_HINTS_TOUCH_SPLIT,countdown.ts 第 2 参 hints,game-loop 按 detectTouchPrimaryInput + splitMode 选择;copy.test 三态断言 + README 同源);验证:typecheck + lint + 934 用例 + bot 9 赛道 0 违规 + build PWA + e2e 40 通过 0 失败 + obs 视觉复核零回归 | ✅ |
| M34 | 2026-08-15 game-loop 第二轮瘦身(1490→1133 行):六组逻辑下沉为带单测的兄弟模块——game-params.ts(URL 模式解析纯函数)、menu-setup.ts(菜单静态装饰装配)、route-choice.ts(路线模式集中化:原散落 startGame/beginRouteChoice/chooseRouteBranch/frame/applyPhase 五处的段末检测/岔路选择/分支切换收敛为单一真源)、boost-feedback.ts(BOOST 未蓄能红闪纯状态机 + 300ms 冷却)、track-cards.ts(赛道卡构建 + 方向键网格导航)、pause-controls.ts(暂停控件注入式绑定);另加 shared/timer.ts unrefSafeTimeout(收敛两处重复 unref 兼容计时)、ui/screens.ts applyPauseBranding(暂停标题按玩家标注)/revealRacingTouchHint、top-refresh.ts refreshMenuBoard(构造器与回菜单两处同源刷新消重);applyPhase 由 159 行瘦至 ~90 行;新增 7 个单测文件 60 用例,行为逐字节等价(game-loop-integration 全链路回归锁定),对外 API(initGame/re-export 兼容层)不变;验证:typecheck + lint + 998 用例 + bot 9 赛道矩阵 0 违规 + build PWA + e2e 40 通过 0 失败 + 8 视口条件跳过 |
✅ |
| M35 | 2026-08-22 QA 实测修复与打磨批次——批次 A 模式 HUD 信息补全:挑战模式实时得分文案改「得分 N / 目标 5000」(CHALLENGE_TARGET_SCORE 自 shared/constants 导入)+ 新增 #daily-badge 每日挑战徽章(frame-update 按 isDailyTrack 显隐,路线模式保守隐藏);批次 B 移动端触控体验:.track-stars nowrap + flex-shrink 0、max-height:480 下 .track-option min-height 28→44px(Apple HIG 触摸目标)、(hover:none) 下 #pause-btn bottom 16→32px(与摇杆拉开 ≥16px 安全边距);批次 C 六项视觉打磨:.daily-progress 字号 12→13px + 提亮、雨滴密度 ×1.4(RAIN_DROPS_MULT)+ 每滴 ±4° 确定性角度抖动(RAIN_ANGLE_JITTER_DEG,mulberry32(2026))、分屏分隔线 4→6px、HEADLIGHT_CORE #ffe08a→#fff0c0、路灯光晕更黄更弥散(半径 2.6→2.9 / 1.9→2.1)、canyon grassLight 22→20、小地图背景 alpha 0.72→0.6、#near-miss top 22%→42%;批次 D 技术债:screens-finish-panel.test.ts 新增 17 用例(经 applyPhaseToScreens 覆盖私有 fillFinishPanel 各分支)、GameLoop.destroy() 幂等生命周期(destroyed 标志 + 全监听清理;game-loop.test.ts +4 用例)、docs/reports/pwa-update-assessment.md PWA 更新策略评估(维持 registerType 'prompt');尾灯修复(用户反馈驱动):night 车流双尾灯收敛——核心灯 0.15w×0.07h 镜像对称(原 0.2w×0.25h 且右灯贴边不对称)+ 外层 rgba(255,59,48,0.25) 光晕层;验证:typecheck + lint + 1026 用例 + bot 9 赛道矩阵 0 违规 + build PWA + e2e 46 通过 0 失败 + 8 视口条件跳过 |
✅ |
| M36 | 模式选择卡片(来源:5007a79 内 src/style.base.css:404「M36 模式选择卡片样式」注释——.mode-selector/.mode-card 九卡样式,为 M38 模式设置面板的前置 UI 层;git 历史无独立 M36 提交,提交 message 亦无 M36 标记,归属按该注释标注) |
✅ |
| M37 | M35 之后、M38 之前的两笔独立修复提交(来源 2aab8c2 / 4d9e9cc,message 均无 M37 标记,归属为按提交序列推断):① 夜间车流尾灯收敛(traffic-draw.ts 1 文件——核心灯 0.15w×0.07h 镜像对称 + 外层光晕层,消除右灯贴边不对称);② P0 多圈车流失效与远山缓存退化修复(traffic.ts 新增 ringForwardDistance/ringDelta 环形距离单一真源 + renderer 景深归并 + rebuildMountains 统一重建;新增 traffic-ring.test.ts 10 例与 renderer-mountain-env.test.ts 2 例,含缺陷原貌锁定) | ✅ |
| M38 | 2026-09-04 模式设置面板落地与收口 + frame-update 九步拆分 + near-miss 飘字修复——#mode-selector 九张模式卡片(原 URL 手输参数暴露为可点击卡片:weather/traffic/guide/route/challenge/daily 六卡热应用、split/hotseat/perf 三卡 reload 重建);mode-settings.ts 272 行 + bindModeSelector 返回 ModeSelectorHandle(消除 URL 与卡片双真源)+ isMenuPhase 守卫(非菜单阶段忽略点击)+ cycleRouteValue 上界改 ROUTE_DEFS.length + .mode-card--selected 类名修正(inset box-shadow 防换行抖动);frame-update 九步拆分(updateFrame 421→约 147 行,主体退化为纯编排:stepEnvironment/stepChallengeHud/stepDailyBadge/stepTraffic/stepInputs/stepBoost/stepCollision/stepGameFeel/stepDriveAudio,经 51 个既有单测间接覆盖,全量单测耗时 59s→27s);near-miss 飘字常驻修复(NEAR_MISS_POPUP_SEC=0.8 + advanceNearMiss 纯函数);新增 mode-settings.test.ts 431 行 + game-loop-integration +210 行(applyRuntimeParams 集成用例 5 个,此前零覆盖);验证:typecheck + lint + test + bot + build + e2e |
✅ |
- 单元测试:
npm test(Vitest) - E2E 视觉回归:
npm run test:e2e(Playwright,需先npx playwright install chromium)- 覆盖:菜单光晕不遮挡赛道卡片、标题与副标题不叠影、天空无高频条纹(canvas 像素级)、倒计时提示同源填充、热座 P1 HUD 标签、移动端横屏开始按钮在视口内、大屏 1920×1080 内容居中
- 实测基线:48 执行 = 40 通过 + 8 视口条件跳过(大屏/移动端专属断言仅在对应 project 执行,属设计行为,0 失败)
- bot 跑圈:
npm run bot(9 赛道矩阵回归,0 违规) - 全量 CI:typecheck → lint → format:check → test → bot → build → e2e(见
.github/workflows/ci.yml)
src/
engine/ # 伪3D投影、路面分段渲染、视差山景、路边景物(含环境差异化形状)、漂移烟雾、车流渲染、赛道定义(tracks.ts)、环境配置、玩家车渲染、导航引导线/岔路分叉带(guide-line.ts)
physics/ # 车辆运动学、漂移、双人按键映射
game/ # GameLoop 主循环(29 文件)、帧更新/渲染纯函数、模式策略、结算统计、阶段 FSM、碰撞、赛道上下文、常量(re-export shared)、成就/每日挑战/贴身超车/路线模式
ai/ # bot 决策器、圈速模拟器
shared/ # 独立共享层:游戏常量(constants)、阶段(phase/phase-logic)、圈数(lap)、奖牌(medal)唯一真源(解环 game↔ui)
ui/ # HUD、格式化、游戏状态机、启动/结算画面、存档、触屏摇杆、四分区触控、小地图
audio/ # WebAudio 合成:引擎音效(漂移摩擦/胎噪)、背景音乐
tests/
unit/ # Vitest 单测(68 文件 1096 用例;连同 tests/bench 冒烟合计 69 文件 1097 用例)
e2e/ # Playwright 视觉回归(visual.spec.ts,桌面/移动横屏/大屏三 project)
bot/ # bot 跑圈校验脚本(run-bot.ts,9 赛道矩阵)
__mocks__/ # canvas mock
helpers/ # 测试辅助
docs/ # 计划档案、视觉分析、superpowers plans
- 伪 3D 投影:分段路面梯形投影,
scale = depth / (z - camera.z),相机 z 随行进同步 - 曲线赛道:每段
curve值累计中心线偏移,控制点线性插值生成平滑弯道,支持环形赛道与回环约束 - 漂移系统:急转蓄力触发漂移,转向增强 + 轻微减速,漂移烟雾粒子随车尾生成
- 分屏渲染:单 Renderer 区域渲染(
renderRegion),双车独立物理与 HUD,URL 参数开关 - bot 决策:前瞻窗口检测弯道(|Σcurve| 阈值),弯道降速 + 横向回中转向
- 验证闭环:每个里程碑经 typecheck + lint + test + build + bot 全量验证后提交