feat: Player script updates - ground check, flip, animations, and study notes
This commit is contained in:
175
Q&A.md
Normal file
175
Q&A.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Q&A
|
||||
|
||||
> 学习过程中遇到的问题记录
|
||||
|
||||
---
|
||||
|
||||
## Q1:为什么保留 `rb.linearVelocity.y` 不会导致 Player 上下移动,而改变 `x` 就会左右移动?
|
||||
|
||||
### 关键理解
|
||||
|
||||
`rb.linearVelocity` 每一帧都被**完整重新赋值**,X 和 Y 的来源不同决定了它们的行为不同。
|
||||
|
||||
### X 轴:由输入主动控制
|
||||
|
||||
```csharp
|
||||
rb.linearVelocity = new Vector2(xInput * moveSpeed, rb.linearVelocity.y);
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
// 这部分的数值由你决定
|
||||
```
|
||||
|
||||
| 操作 | `xInput` | `velocity.x` | 效果 |
|
||||
|------|:--------:|:------------:|:----:|
|
||||
| 按 A / ← | -1 | -3.5 | 向左移动 |
|
||||
| 松开 | 0 | 0 | 停止 |
|
||||
| 按 D / → | 1 | 3.5 | 向右移动 |
|
||||
|
||||
每次赋值,X 都被设为**输入决定的明确值**,所以会立刻产生/停止移动。
|
||||
|
||||
### Y 轴:物理系统已经在运行
|
||||
|
||||
`rb.linearVelocity.y` 不是空的,它已经是物理引擎当前帧算好的结果:
|
||||
|
||||
| 状态 | `velocity.y` 实际值 | 保留后效果 |
|
||||
|------|:-------------------:|:----------:|
|
||||
| 站地上 | ≈ 0 | 不动(地面碰撞把 y 锁为 0) |
|
||||
| 下落中 | < 0(重力累加) | 继续下落 |
|
||||
| 跳起后 | > 0 → 逐渐减小 | 上升 → 减速 → 下落 |
|
||||
|
||||
保留 Y 的本质是 **"不去干涉"** 物理系统对垂直运动的控制,而不是"主动让角色上下动"。
|
||||
|
||||
### 反例:写死 Y 会怎样?
|
||||
|
||||
```csharp
|
||||
rb.linearVelocity = new Vector2(xInput * moveSpeed, 0); // ❌
|
||||
```
|
||||
|
||||
- 重力被清零 → 角色不会下落,飘在空中
|
||||
- 跳跃被清零 → 跳不起来
|
||||
- 地面碰撞结果被覆盖 → 可能会卡进地面
|
||||
|
||||
### 一句话总结
|
||||
|
||||
> X 轴 velocity 是你主动赋值来**命令移动**,Y 轴 velocity 是物理系统**正在运行的结果**,保留它只是不去搞破坏。
|
||||
|
||||
---
|
||||
|
||||
*2026-05-23*
|
||||
|
||||
## Q2:跳跃时直接覆盖 Y 为 `jumpForce`,和之前说的"保留 Y"不矛盾吗?为什么不用 `y + jumpForce`?
|
||||
|
||||
### 问题背景
|
||||
|
||||
之前的 Q&A 说"保留 `rb.linearVelocity.y` 不去干涉物理系统",但跳跃代码却直接覆盖:
|
||||
|
||||
```csharp
|
||||
// 平时移动:保留 Y(不去干扰物理)
|
||||
rb.linearVelocity = new Vector2(xInput * moveSpeed, rb.linearVelocity.y);
|
||||
|
||||
// 跳跃时:覆盖 Y
|
||||
rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpForce);
|
||||
```
|
||||
|
||||
直觉上会觉得应该写成 `rb.linearVelocity.y + jumpForce` 才对。
|
||||
|
||||
### 核心解答
|
||||
|
||||
**场景不同,原则不同:**
|
||||
|
||||
| 场景 | 对 Y 的操作 | 意图 |
|
||||
|------|:----------:|:----:|
|
||||
| 左右移动 | 保留 Y | **不管**物理系统的事 |
|
||||
| 跳跃 | 覆盖 Y = jumpForce | **主动干预**,跳跃本身就是这个干预 |
|
||||
|
||||
平时保留 Y 是因为"不需要管 Y",跳跃覆盖 Y 是因为"现在就要动 Y"。
|
||||
|
||||
### 为什么用 `= jumpForce` 而不是 `+= jumpForce`?
|
||||
|
||||
站在平地时 `velocity.y ≈ 0`,两者结果一样。但在以下情况加法会出问题:
|
||||
|
||||
| 场景 | velocity.y 当前值 | `= jumpForce` | `+= jumpForce` | 哪个合理 |
|
||||
|------|:--:|:--:|:--:|:--:|
|
||||
| 平地站着 | ≈ 0 | = 8 ✅ | = 8 ✅ | 一样 |
|
||||
| 在上升平台上跳 | > 0(如 +3) | = 8 ✅ | = 11 ❌ 异常高 | `=` |
|
||||
| 下落中误触跳跃 | < 0(如 -5) | = 8 ✅ | = 3 ❌ 跳不起来 | `=` |
|
||||
|
||||
- **`= jumpForce`** — 每次跳跃高度一致,可预测 ✅
|
||||
- **`+= jumpForce`** — 跳跃高度受当前 Y 速度影响,结果不稳定 ❌
|
||||
|
||||
### 总结
|
||||
|
||||
> 保留 Y = **不想管**物理的事
|
||||
> 覆盖 Y = **正在主动做跳跃这件事**
|
||||
> 用 `=` 保证每次跳跃可预测,用 `+=` 反而会让跳跃高度飘忽不定
|
||||
|
||||
---
|
||||
|
||||
## Q3:二段跳可以从哪些方面入手设计?
|
||||
|
||||
### 前提
|
||||
|
||||
第九次更新已经实现了接地检测(`isGrounded`),跳跃被限制为"只有在地上才能跳"。在此基础上扩展二段跳,需要考虑以下几个维度:
|
||||
|
||||
### 1. 核心机制 —— 如何判断"能不能跳"
|
||||
|
||||
**计数器方案(推荐,可扩展性强):**
|
||||
|
||||
```
|
||||
jumpCount = 允许的跳跃次数(例如 2)
|
||||
remainingJumps = 当前剩余次数
|
||||
|
||||
想跳时:
|
||||
1. 检查 remainingJumps > 0
|
||||
2. 是 → 跳,remainingJumps--
|
||||
3. 否 → 不跳
|
||||
|
||||
落地时:
|
||||
重置 remainingJumps = jumpCount
|
||||
```
|
||||
|
||||
- 优点:改为 3 段跳、4 段跳只需改一个数字,代码不用动
|
||||
- 问自己:`remainingJumps` 什么时候扣?什么时候重置?
|
||||
|
||||
### 2. 重置时机 —— "跳"这个状态何时结束
|
||||
|
||||
核心问题:**二段跳的"次数"在什么时候补回来?**
|
||||
|
||||
| 方案 | 行为 | 手感 |
|
||||
|------|------|------|
|
||||
| 落地重置 | 碰到地面才能再次二段跳 | 标准平台跳跃,最常用 |
|
||||
| 接触墙壁重置 | 贴墙也能补跳 | 适合有爬墙机制的游戏 |
|
||||
| 每 X 秒恢复一次 | 空中待一会儿又能跳 | 节奏较怪,很少用 |
|
||||
|
||||
> 当前项目有 `isGrounded`,落地重置是最自然的选择。
|
||||
|
||||
### 3. 跳跃力设计 —— 二段跳应该和第一段一样高吗?
|
||||
|
||||
| 方案 | 效果 | 代表游戏 |
|
||||
|------|------|---------|
|
||||
| 相同 jumpForce | 两段跳一样高,手感直接 | 空洞骑士(部分技能)|
|
||||
| 稍弱(如 jumpForce × 0.8)| 第二段更低,更真实 | 蔚蓝 Celeste |
|
||||
| 固定低值 | 二段跳只用来"续一下" | 大乱斗 |
|
||||
|
||||
> 可以先设两个独立参数 `jumpForce` 和 `doubleJumpForce`,分别调。
|
||||
|
||||
### 4. 需要考虑的边界问题
|
||||
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| **走边缘掉落** | 从平台边缘走下来(没按跳),空中能二段跳吗?通常可以 |
|
||||
| **没用第一段跳** | 跳过一次后空中还能跳一次?还是说必须先用一次跳?取决于设计 |
|
||||
| **Coyote Time** | 离开地面后很短时间(如 0.1s)内按跳还算落地跳吗?和剩余次数如何叠加? |
|
||||
| **动画反馈** | 二段跳时播放不同的动画(如翻转、翅膀),让玩家感知到"我用了二段跳" |
|
||||
| **只能一次** | 二段跳用完没落地之前,不能再获得跳跃次数 |
|
||||
|
||||
### 5. 建议的切入顺序
|
||||
|
||||
1. 先把计数器机制做出来(`jumpCount` / `remainingJumps`)
|
||||
2. `jump()` 中把 `if(isGrounded)` 改为 `if(remainingJumps > 0)`
|
||||
3. 落地时重置 `remainingJumps = jumpCount`
|
||||
4. 调 `doubleJumpForce` 找手感
|
||||
5. 加动画区分一段跳和二段跳
|
||||
|
||||
---
|
||||
|
||||
*2026-05-25*
|
||||
Reference in New Issue
Block a user