6.0 KiB
6.0 KiB
Q&A
学习过程中遇到的问题记录
Q1:为什么保留 rb.linearVelocity.y 不会导致 Player 上下移动,而改变 x 就会左右移动?
关键理解
rb.linearVelocity 每一帧都被完整重新赋值,X 和 Y 的来源不同决定了它们的行为不同。
X 轴:由输入主动控制
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 会怎样?
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 不去干涉物理系统",但跳跃代码却直接覆盖:
// 平时移动:保留 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. 建议的切入顺序
- 先把计数器机制做出来(
jumpCount/remainingJumps) jump()中把if(isGrounded)改为if(remainingJumps > 0)- 落地时重置
remainingJumps = jumpCount - 调
doubleJumpForce找手感 - 加动画区分一段跳和二段跳
2026-05-25