You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity 2D角色水平跳跃偶尔失效问题求助

问题分析与修复方案

问题根源

  1. 水平速度被意外重置:按下空格触发跳跃后,isJumping设为true,导致horizontal被强制清零。由于物理帧与逻辑帧的同步延迟,跳跃触发后的几帧内IsGrounded仍会返回true,FixedUpdate中的代码会将刚体水平速度重置为0,直接抵消Jump方法添加的水平力。
  2. 跳跃输入处理冗余混乱:单独维护jumpingHorizontal变量,在多处重复获取输入,易因帧时序问题丢失正确的水平输入值。
  3. 跳跃蓄力逻辑不严谨:当前判断最大蓄力的条件等价于判断按住时长超过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;
    }
}

关键修改说明

  1. 水平输入逻辑:移除isJumping时的水平输入清零操作,确保跳跃过程中能持续获取方向输入,解决水平速度被重置的问题。
  2. 跳跃触发方式:用直接设置rb.velocity替代AddForce,避免物理力与速度设置的冲突,保证跳跃时的水平速度不会被抵消。
  3. 蓄力逻辑优化:新增maxJumpHoldTime变量直观控制最大蓄力时长,通过Mathf.Min限制蓄力时间,让跳跃力计算更合理可控。
  4. 空中控制优化:在FixedUpdate中添加空中水平加速度逻辑,让角色在空中也能平滑调整方向(不需要可删除该部分代码)。

内容的提问来源于stack exchange,提问作者edgzoah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:35:59