Unity 2D角色水平跳跃偶尔失效问题求助
问题分析与修复方案
问题根源
- 水平速度被意外重置:按下空格触发跳跃后,
isJumping设为true,导致horizontal被强制清零。由于物理帧与逻辑帧的同步延迟,跳跃触发后的几帧内IsGrounded仍会返回true,FixedUpdate中的代码会将刚体水平速度重置为0,直接抵消Jump方法添加的水平力。 - 跳跃输入处理冗余混乱:单独维护
jumpingHorizontal变量,在多处重复获取输入,易因帧时序问题丢失正确的水平输入值。 - 跳跃蓄力逻辑不严谨:当前判断最大蓄力的条件等价于判断按住时长超过1秒,逻辑不够直观,也没有可配置的最大蓄力时长变量。
修复步骤
- 移除
isJumping时清零horizontal的逻辑,允许跳跃过程中保持水平移动(若不需要空中移动,可改为保留跳跃触发瞬间的水平输入)。 - 删除冗余的
jumpingHorizontal变量,直接使用horizontal处理跳跃的水平方向,简化逻辑。 - 将跳跃力施加方式从
AddForce改为直接设置rb.velocity,避免与FixedUpdate中的速度设置逻辑冲突。 - 新增
maxJumpHoldTime变量,明确控制最大蓄力时长,优化蓄力判断逻辑。 - 调整
Flip方法触发条件,支持空中转向(可根据游戏需求修改)。
修改后的完整代码
using UnityEngine; public class PlayerMovement : MonoBehaviour { private float horizontal; [SerializeField] private float speed = 8f; [SerializeField] private float maxJumpingPower = 10f; [SerializeField] private float maxJumpHoldTime = 0.5f; // 最大蓄力时长 private bool isFacingRight = true; private bool isJumping = false; private float jumpStartTime; [SerializeField] private Rigidbody2D rb; [SerializeField] private Transform groundCheck; [SerializeField] private LayerMask groundLayer; void Update() { // 始终获取水平输入,包括跳跃过程中 horizontal = Input.GetAxisRaw("Horizontal"); // 触发跳跃蓄力 if (Input.GetKeyDown(KeyCode.Space) && IsGrounded()) { jumpStartTime = Time.time; isJumping = true; } // 松开空格或达到最大蓄力时长时触发跳跃 if ((Input.GetKeyUp(KeyCode.Space) || Time.time - jumpStartTime >= maxJumpHoldTime) && isJumping) { float holdTime = Mathf.Min(Time.time - jumpStartTime, maxJumpHoldTime); float jumpPower = maxJumpingPower * (holdTime / maxJumpHoldTime); // 按比例计算跳跃力 Jump(jumpPower); } Flip(); } private void FixedUpdate() { // 地面移动时设置水平速度,空中保持/平滑调整水平速度 if (IsGrounded()) { rb.velocity = new Vector2(horizontal * speed, rb.velocity.y); } else { // 可选:空中添加水平加速度,提升操作手感 rb.velocity = new Vector2(Mathf.MoveTowards(rb.velocity.x, horizontal * speed, speed * 2 * Time.fixedDeltaTime), rb.velocity.y); } } private bool IsGrounded() { return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer); } private void Flip() { // 支持空中转向,若不需要可恢复原有的IsGrounded判断 if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f) { isFacingRight = !isFacingRight; Vector3 localScale = transform.localScale; localScale.x *= -1f; transform.localScale = localScale; } } private void Jump(float jumpPower) { // 直接设置速度,确保水平方向不会被覆盖 rb.velocity = new Vector2(rb.velocity.x, jumpPower); isJumping = false; } }
关键修改说明
- 水平输入逻辑:移除
isJumping时的水平输入清零操作,确保跳跃过程中能持续获取方向输入,解决水平速度被重置的问题。 - 跳跃触发方式:用直接设置
rb.velocity替代AddForce,避免物理力与速度设置的冲突,保证跳跃时的水平速度不会被抵消。 - 蓄力逻辑优化:新增
maxJumpHoldTime变量直观控制最大蓄力时长,通过Mathf.Min限制蓄力时间,让跳跃力计算更合理可控。 - 空中控制优化:在
FixedUpdate中添加空中水平加速度逻辑,让角色在空中也能平滑调整方向(不需要可删除该部分代码)。
内容的提问来源于stack exchange,提问作者edgzoah
相关产品推荐
相关产品推荐

