# 《张雪峰快跑》游戏修复与物理手感调优记录

本项目是一个基于 HTML5 Canvas 的网页跑酷小游戏。以下是本次针对该游戏的“运行修复”、“资源同步”以及“物理手感调优”的完整实施记录。

---

## 一、 运行故障诊断与资源修复

在修复前，游戏由于资源缺失和路径配置错误，处于无法启动的白屏/卡死状态。

### 1. 资源路径纠正与目录重建
* **问题**：代码中引用的音频路径为 `assets/bgm.m4a` 和 `assets/death.mp3`，但原项目根目录下只有这两个音频文件，并没有 `assets` 文件夹，导致找不到资源。
* **解决**：在本地创建了 `assets/` 与 `assets/generated/` 目录，并将 `bgm.m4a` 和 `death.mp3` 移动到 `assets/` 中。

### 2. 爬取并同步目标网站原生资源
根据要求，我们从官方目标网站（`https://ottomate.games/zxf/`）爬取并完整覆盖了以下资源，确保本地体验与线上版本 100% 一致：
* **核心代码**：
  * 重写了 `index.html`（网页入口）
  * 重写了 `index.css`（样式表布局）
  * 重写了 `index.js`（游戏主逻辑代码）
* **原生媒体资源**（已通过脚本批量抓取并存储于本地）：
  * 主角跑步帧：`assets/generated/zhang-runner.png`
  * 主角下蹲帧：`assets/generated/zhang-duck.png`
  * 障碍物巧乐滋雪糕 A：`assets/generated/qiaolezi.png`
  * 障碍物巧乐滋雪糕 B：`assets/generated/qiaolezi-alt.png`
  * 飞行的雪碧瓶障碍：`assets/generated/sprite-bottle.png`

### 3. 提取并应用游戏开始音效
* **提取过程**：用户在 `assets/` 目录下放置了视频/音频文件 `start.mp4`。我们利用系统中的 `FFmpeg` 工具，执行剪辑命令，精准提取了该文件**前 1 秒的音轨并进行音频编码转换**，输出为了轻量高效的网页音频文件 [start.mp3](file:///d:/wang4/Desktop/zxf/assets/start.mp3)。
* **集成应用**：在 `index.js` 中声明了 `startSound` 对象，并挂载于 `startGame()` 开始流程中。每当玩家点击“开始/重来”进入游戏时，会立即播放这 1 秒的专属起跑音效，极大丰富了游戏开场的氛围。

---

## 二、 物理手感与跳跃控制调优

为了解决“玩着不舒服，不跟手”的问题，我们在 `index.js` 的物理引擎和事件响应中做出了几项深度的控制参数调优：

### 1. 增加单击跳跃的最小高度
* **优化前**：单击若松手太快，角色很容易因为高度不足撞上 144 像素高的巧乐滋障碍。
* **优化后**：将跳跃初速度 `jumpVelocity` 从 `-820` 加大为 **`-880`**，且**移除了释放按键时对上升速度的强制截断**。现在即使极快地“单击一次”，惯性也会确保角色跳起至 **164 像素** 左右的高度，保证单击也可以稳稳飞跃常规障碍物。

### 2. 腾空下落时按上键“滑翔滞空”
* **优化后**：在 `update` 函数中加入了重力削减判断。当角色腾空并且速度开始向下（`vy > 0`）时，如果玩家**长按或按住“上键”/“空格”**，重力加速度将直接**削减为原来的 40%**。这大大减缓了坠落速度，产生出极佳的滞空滑翔操作手感。

### 3. 上升期按下键“即时终止上升并加速下坠”
* **优化后**：重构了 `setDuck` 函数在空中的响应机制。在角色起跳并向上冲的阶段（`vy < 0`），如果玩家按下了**“下键”**（下蹲键）：
  * 瞬间将向上的速度**强制截断为 0**，完全打消上升势头。
  * 给予一个向下的初速度（`vy += 420`），并结合空中下蹲重力（`3900`）使角色**瞬间极速落地**。

### 4. 优化二次起跳判定（解决吞键与禁止自动连跳的冲突）
* **一直按住不连跳**：加入了按键状态记录，如果起跳后玩家手指从始至终就没松开过，落地时**不会**触发二次跳跃，角色将保持在地面奔跑。
* **松开后提前按缓冲判定**：引入了 **120毫秒智能落地缓冲器**。如果玩家在空中跳跃的后半段松开过按键并再次按下，即使此时角色**还没有落地**，系统也会记录这次输入。在落地瞬间，角色会**秒起跳**，彻底解决了“空中提前按键导致被吞”而“有时候起不来”的问题，衔接极其灵敏丝滑。

---

## 三、 碰撞箱判定优化与调试系统

为了解决“明明没有碰到障碍物就被判定撞到/死亡”的问题，我们在项目中优化了碰撞机制，并增加了一个非常实用的调试功能：

### 1. 宽容碰撞体积（Shrinked Hitbox）
* **优化原因**：张雪峰以及各类障碍物图片的四周包含透明像素，原版的矩形判定范围过于庞大并几乎贴满边缘，导致空气判定过多（视觉上还没碰到，但矩形边缘已经重合导致死亡）。
* **优化措施**：
  * **角色碰撞箱（Player Hitbox）**：左右边界向内收缩 **22 像素**；站立状态的顶部缩进 **18 像素**，底端脚部收缩 **14 像素**（即高度判定总计缩小了 32 像素）。
  * **障碍物碰撞箱（Obstacle Hitbox）**：巧乐滋雪糕、雪碧瓶在计算物理碰撞判定时，边缘内收幅度人为扩大了 **1.5 ~ 1.8 倍**，完美避开了冰棒木棍以及多余透明边缘的物理检测。
  * **效果**：使游戏判定完全符合玩家的肉眼直观感受，轻微擦边和贴地掠过时拥有极佳的容错空间。

### 2. Hitbox 实时可视化调试器（Hitbox Debugger）
* **调试机制**：在游戏运行（或处于准备状态）时，按下键盘上的 **`D` 键**，即可实时在屏幕上切换是否绘制真实的碰撞判定矩形。
* **画面表示**：
  * 🔴 **红色矩形**：张雪峰当前的真实碰撞区（自动同步人物跳跃时上下抖动的偏移）。
  * 🔵 **蓝色矩形**：巧乐滋雪糕与雪碧瓶当前的真实物理碰撞区。
  * 玩家可通过该可视化功能随时观察碰撞箱贴合度。

---

## 四、 多生命值系统（HP System）

根据测试与趣味性需求，项目新增了自定义初始生命值功能，提供了更友好的容错和连续挑战体验：

### 1. 开始前生命值选择界面
* **UI 交互**：在遮罩层（Overlay）中增加了“选择初始生命值”面板，包含：
  * **`1`**：默认血量，维持原版碰壁即死的一击必杀难度。
  * **`41 (可自定义)`**：默认 41 滴血。点击该按钮时，会自动滑出数字输入框并**自动聚焦和全选输入框内容**。玩家可直接按键打字修改此数值，也可以不作修改直接以 41 滴血开局。
* **样式表现**：为选择面板配置了和谐的绿色极简 Segment 按钮组与输入焦点态动画，响应式布局良好。

### 2. HUD 头部生命值展示
* **显示机制**：在游戏状态栏（HUD）的中央顶端新增了实时血量标签（`HP: X`）。
* **视觉警告**：当生命值大于 1 时，生命标签显示为**安全健康绿**；当生命降为 1 滴血时，会自动切换为**危险警示红**，提醒玩家进入危机状态。

### 3. 受击扣血与 1.5 秒无敌保护
* **伤害结算**：当角色触碰障碍物时，如果 `HP > 1`：
  * 生命值扣减 1 点，并实时更新 HUD。
  * 会播放由新视频最后 4 秒提取的**专属扣血音效 [hurt.mp3](file:///d:/wang4/Desktop/zxf/assets/hurt.mp3)**；原版的 **`death`（大喊“你跑不过我你信吗！”）** 音频则专用于玩家最后一滴血归零、游戏彻底结束时播放。
  * 角色会获得 **`1.5` 秒的无敌保护时间**，避免刚受击后再次连环撞击导致的直接暴毙。
* **无敌闪烁特效**：在 1.5 秒无敌期间，角色会以 **`0.15` 秒为周期交替执行半透明（`opacity: 0.25 ~ 0.75`）的视觉闪烁特效**，为玩家提供非常直观的物理无敌状态反馈。
* **生命归零结算**：只有当 `HP === 1` 且再次碰撞时，才会真正触发游戏结束（`endGame`）并弹出重来面板。

---

## 五、 主动退出系统 (Exit Game System)

为了避免在高生命值（例如 41 滴血）下，玩家必须等待 41 次碰撞才能退回主菜单的情况，项目新增了中途“主动退出”的功能：

### 1. 退出按钮显示与隐藏时机
* **动态控制**：退出按钮（`Exit Button`）只在游戏处于游戏进行中状态（`state === "playing"`）时在 HUD 中央显示，一旦游戏结束（`endGame`）或处于准备就绪状态，此按钮会自动隐藏，以保持页面清爽。
* **高颜值交互**：按钮样式高度融入现有的 HUD。在 hover 时，边框和字体会过渡变为**警示红（`color: #b32d2d`）**以提醒玩家。

### 2. 状态与音频的完美重置
* 点击退出按钮后，会调用核心退出逻辑 `exitGame()`：
  * **状态变更**：将游戏运行状态恢复至 `ready`（准备中）。
  * **音频重设**：瞬间**暂停背景音乐 BGM** 并将其播放进度**归零重置**（`bgm.currentTime = 0`）。
  * **画布净化**：重置玩家状态、得分数据与所有在场障碍物（`resetGame()`），并将 Canvas 画面**重新刷至就绪第一帧**。
  * **主界面回归**：滑入主菜单遮罩层（Overlay），供玩家重新进行生命值选项配置与再次挑战。

---

## 六、 本地测试与运行建议

由于现代浏览器的跨域资源共享策略限制（CORS），直接双击 `index.html` 可能会遇到图片或音频加载失败的报错。推荐在项目根目录下通过本地服务器运行：

1. **若您使用 Node.js**（推荐）：
   ```bash
   npx serve .
   ```
   然后访问控制台输出的本地端口（例如 `http://localhost:3000`）。

2. **若您使用 Python**：
   ```bash
   python -m http.server 8080
   ```
   然后通过浏览器打开 `http://localhost:8080` 进行测试。
