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的输入坐标系和子物体变换会受父物体缩放影响,尤其是相机作为子物体时,很容易出现视角/输入方向的异常反转。 - 起身时弹飞:当你恢复原物体缩放时,碰撞体突然变大,会和地面产生物理重叠,引擎会自动把角色“推”开,导致弹跳效果。
修复方案
核心思路是不要缩放整个玩家物体,而是单独调整胶囊碰撞体的参数,同时优化输入逻辑和物理交互:
- 替换缩放逻辑:修改
CapsuleCollider的height和center,而非直接缩放transform,避免影响子物体和物理交互。 - 添加头顶检测:起身前检查头顶是否有障碍物,避免强行起身导致的碰撞问题。
- 修正输入绑定和状态切换逻辑:修复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); } }
额外配置提示
- PlayerInput组件:确保你的玩家物体上已经挂载了PlayerInput组件,并正确绑定了输入动作(Movement、Sprint、Crouch、Jump)。
- 检测点位置:
groundCheck建议放在角色脚底附近,用于检测是否落地。headCheck建议放在角色头顶位置,用于检测起身时是否有障碍物。
- 输入设置:在Input System的Action Map中,将Crouch设置为"Press"触发(而非"Hold"),或者根据你的操作习惯调整逻辑。
这样修改后,鼠标输入反转和起身弹跳的问题都会解决,蹲伏机制也会更流畅符合预期~




