You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity角色蹲伏机制Bug排查求助:鼠标输入反转+起身弹跳异常

Unity角色蹲伏机制Bug排查求助:鼠标输入反转+起身弹跳异常

Hey there! Let's break down why your crouch mechanic is causing those weird issues and fix them step by step.

问题原因分析

  • 鼠标输入反转:你当前直接修改transform.localScale.y来实现蹲伏高度变化,这会缩放整个玩家物体(包括相机、Rigidbody等子物体)。Unity的输入坐标系和子物体变换会受父物体缩放影响,尤其是相机作为子物体时,很容易出现视角/输入方向的异常反转。
  • 起身时弹飞:当你恢复原物体缩放时,碰撞体突然变大,会和地面产生物理重叠,引擎会自动把角色“推”开,导致弹跳效果。

修复方案

核心思路是不要缩放整个玩家物体,而是单独调整胶囊碰撞体的参数,同时优化输入逻辑和物理交互:

  1. 替换缩放逻辑:修改CapsuleColliderheightcenter,而非直接缩放transform,避免影响子物体和物理交互。
  2. 添加头顶检测:起身前检查头顶是否有障碍物,避免强行起身导致的碰撞问题。
  3. 修正输入绑定和状态切换逻辑:修复PlayerInput的错误初始化,调整蹲伏/起身的触发逻辑。

修改后的完整代码

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    [Header("Movement Settings")]
    public float moveSpeed = 5f;
    public float sprintSpeed = 8f;
    public float jumpForce = 5f;
    public float crouchSpeed = 2.5f;
    public float crouchHeight = 1f; // 蹲伏时胶囊碰撞体的高度
    private float originalColliderHeight;
    private float originalColliderCenterY;
    private bool isCrouching = false;

    [Header("Ground & Head Check")]
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public Transform headCheck;
    public float headCheckDistance = 0.2f;
    public LayerMask groundMask;

    private Rigidbody rb;
    private CapsuleCollider capsuleCollider;
    private Vector2 moveInput;
    private bool isGrounded;
    private bool isSprinting;
    private PlayerInput playerInput;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        capsuleCollider = GetComponent<CapsuleCollider>();
        // 正确获取挂载在物体上的PlayerInput组件,而非new一个新的
        playerInput = GetComponent<PlayerInput>();

        // 保存碰撞体的原始参数
        originalColliderHeight = capsuleCollider.height;
        originalColliderCenterY = capsuleCollider.center.y;
    }

    void Update()
    {
        CheckGround();
    }

    private void FixedUpdate()
    {
        MovePlayer();
    }

    void OnJump()
    {
        if (isGrounded)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
    }

    void CheckGround()
    {
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
    }

    public void OnMovement(InputValue value)
    {
        moveInput = value.Get<Vector2>();
    }

    public void OnSprint(InputValue value)
    {
        isSprinting = value.isPressed;
    }

    public void OnCrouch(InputValue value)
    {
        bool crouchPressed = value.isPressed;

        // 按下蹲伏键时进入蹲伏(未蹲伏状态)
        if (crouchPressed && !isCrouching)
        {
            StartCrouch();
        }
        // 松开蹲伏键时尝试起身(当前蹲伏且头顶无障碍物)
        else if (!crouchPressed && isCrouching)
        {
            if (!Physics.CheckSphere(headCheck.position, headCheckDistance, groundMask))
            {
                StopCrouch();
            }
        }
    }

    void StartCrouch()
    {
        isCrouching = true;
        // 调整胶囊碰撞体:保持底部位置不变,只缩短高度并上移中心
        capsuleCollider.height = crouchHeight;
        capsuleCollider.center = new Vector3(0, crouchHeight / 2, 0);
    }

    void StopCrouch()
    {
        isCrouching = false;
        // 恢复碰撞体的原始参数
        capsuleCollider.height = originalColliderHeight;
        capsuleCollider.center = new Vector3(0, originalColliderCenterY, 0);
    }

    void MovePlayer()
    {
        // 优先使用蹲伏速度,再判断冲刺状态
        float currentSpeed = isCrouching ? crouchSpeed : 
                             (isSprinting && isGrounded && moveInput.y > 0f ? sprintSpeed : moveSpeed);

        Vector3 direction = transform.right * moveInput.x + transform.forward * moveInput.y;
        direction.Normalize();

        // 只修改XZ平面的速度,保留Y轴的重力/跳跃速度
        rb.velocity = new Vector3(direction.x * currentSpeed, rb.velocity.y, direction.z * currentSpeed);
    }
}

额外配置提示

  1. PlayerInput组件:确保你的玩家物体上已经挂载了PlayerInput组件,并正确绑定了输入动作(Movement、Sprint、Crouch、Jump)。
  2. 检测点位置
    • groundCheck建议放在角色脚底附近,用于检测是否落地。
    • headCheck建议放在角色头顶位置,用于检测起身时是否有障碍物。
  3. 输入设置:在Input System的Action Map中,将Crouch设置为"Press"触发(而非"Hold"),或者根据你的操作习惯调整逻辑。

这样修改后,鼠标输入反转和起身弹跳的问题都会解决,蹲伏机制也会更流畅符合预期~

火山引擎 最新活动