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

如何修复Unity角色控制器的碰撞跳跃异常Bug?

问题描述

我有一个Player对象,子对象包含用于显示的Cylinder、MainCamera,以及用于地面检测的checkGround对象。现有两个功能脚本:

  • playerMovement:负责玩家移动、跳跃与重力模拟,大部分功能正常,但特定条件下会出现跳跃异常
  • mouseMovement:实现第一人称视角旋转(直接旋转Player对象),并将X轴旋转限制在-45°到45°之间,控制抬头/低头视角

异常表现:
当Player旋转到特定角度时,向视角倾斜的反方向移动,会出现轻微的碰撞式跳跃;此时按下跳跃键,跳跃高度会翻倍;向倾斜方向移动时,跳跃高度则会减半。


问题根源分析
  1. GroundCheck位置计算错误
    在mouseMovement中,initialGroundCheckLocalPosition变量未初始化,却被用于计算GroundCheck的世界位置,同时错误地将Player的抬头/低头旋转(X轴)应用到了整个Player对象上,导致GroundCheck的检测点偏离了Player脚底:

    • 术语解释:Transform.localPosition是子对象相对于父对象的本地坐标,不受父对象旋转影响;若错误使用未初始化的变量进行坐标转换,会导致检测点位置完全偏离预期。
    • 当GroundCheck被旋转到Player前方/后方时,反向移动会让Player脚底离开地面,但GroundCheck仍检测到地面,此时isGrounded保持为true,velocity.y被强制重置为-2,叠加移动产生的向上分量后就会出现“假跳跃”;按跳跃键时,错误的isGrounded状态会让跳跃速度被重复添加,最终导致高度翻倍。
  2. CharacterController移动逻辑冲突
    CharacterController.Move()方法会直接修改对象位置,当GroundCheck检测错误时,velocity.y的重置逻辑会与移动的Y轴分量叠加,进一步放大跳跃高度的异常:

    • 术语解释:CharacterController是Unity专为角色移动设计的组件,自带碰撞检测,Move()的参数为世界空间下的位移量,若同时处理水平移动与重力,需确保Y轴逻辑不会出现冲突。

修复方案

1. 修正mouseMovement脚本的旋转与GroundCheck逻辑

核心问题是将Player的抬头/低头旋转与左右旋转分离,同时固定GroundCheck的检测位置:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class mouseMovement : MonoBehaviour
{
    public float mouseSensitivity = 500f;

    float xRotation = 0f;
    float yRotation = 0f;

    public Transform groundCheck;
    private Vector3 initialGroundCheckLocalPosition;

    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        // 初始化GroundCheck的本地相对位置(相对于Player的坐标)
        initialGroundCheckLocalPosition = groundCheck.localPosition;
    }

    void Update()
    {
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        // 抬头/低头逻辑:仅让Camera单独旋转X轴
        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -45f, 45f);
        Camera.main.transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);

        // 左右旋转逻辑:仅让Player旋转Y轴
        yRotation += mouseX;
        transform.localRotation = Quaternion.Euler(0f, yRotation, 0f);

        // 固定GroundCheck的本地位置,不受Player旋转影响
        groundCheck.localPosition = initialGroundCheckLocalPosition;
    }
}

关键修改说明

  • 分离Player与Camera的旋转:第一人称视角的标准实现是Player只负责左右转向(Y轴旋转),Camera单独负责抬头/低头(X轴旋转),避免Player整体倾斜导致的移动方向与检测点偏移。
  • 固定GroundCheck位置:通过groundCheck.localPosition = initialGroundCheckLocalPosition确保检测点始终在Player脚底的相对位置,不会随旋转偏移。

2. 优化playerMovement脚本的地面检测与跳跃逻辑

提升地面检测的准确性,避免错误触发跳跃:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class playerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float speed = 5f;
    public float gravity = -9.81f * 2;
    public float jumpHeight = 3f;

    public Transform groundCheck;
    public float groundDistance = 0.5f;
    public LayerMask groundMask;

    Vector3 velocity;
    bool isGrounded;

    void Update()
    {
        // 使用SphereCast替代CheckSphere,仅检测脚底向下的地面接触
        isGrounded = Physics.SphereCast(groundCheck.position, groundDistance, Vector3.down, out _, groundDistance, groundMask);

        if (isGrounded && velocity.y < 0)
        {
            // 重置Y轴速度为0,避免不必要的下沉叠加
            velocity.y = 0f;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        // 基于Player的Y轴旋转计算移动方向(忽略X轴旋转)
        Vector3 move = transform.right * x + transform.forward * z;
        // 归一化移动向量,避免斜向移动速度过快
        if (move.magnitude > 1f) move.Normalize();
        controller.Move(move * speed * Time.deltaTime);

        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }

        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}

关键修改说明

  • 使用SphereCast检测地面:Physics.SphereCast从检测点向下发射球形射线,仅当射线击中地面时才判定为接地,避免了CheckSphere误检测到Player侧面地面的问题。
  • 归一化移动向量:确保斜向移动时的速度与前后左右移动速度一致,避免速度叠加导致的异常。
  • 重置Y轴速度为0:替代之前的-2f设置,更符合物理逻辑,避免不必要的下沉。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:10:13