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

Unity第三人称角色遇地形/墙体碰撞卡顿:无法侧向移动

Unity第三人称角色物理交互问题排查与修复

问题描述

我在Unity中开发第三人称角色,采用Rigidbody+Capsule Collider实现物理交互,移动与动画整体运行正常,但遇到两个核心问题:

  • 台阶/地形高差:角色接触台阶或地形高度差时,无法跳跃越过障碍,直接卡在障碍底部
  • 墙体/障碍物:角色碰撞墙体或其他障碍物后,无法进行左右侧向移动,仅能向后移动,机动性严重受限

已尝试调整物理材质摩擦力、修改Rigidbody参数、调整移动脚本等方案,均未解决问题。当前使用的部分移动脚本如下:

private void Update() {
    if(gameInput.isJumping() && isGrounded) {
        Jumping();
        isGrounded = false;
    } else {
        isGrounded = true;
    }
}

private void FixedUpdate() {
    Vector2 inputVector = gameInput.GetMovementVectorNormalized();
    bool isSprinting = gameInput.isSprinting();

    Vector2 scaledInputVector = ScaleInputVector(inputVector, isSprinting);

    animator.SetFloat("horizontal", scaledInputVector.x);
    animator.SetFloat("vertical", scaledInputVector.y);

    Vector3 targetVelocity = new Vector3(scaledInputVector.x, 0, scaledInputVector.y);

    if(isSprinting) {
        addForceToRigidbody(sprint, targetVelocity);
    } else {
        addForceToRigidbody(walk, targetVelocity);
    }
}

private Vector2 ScaleInputVector(Vector2 inputVector, bool isSprinting) {
    if(!isSprinting) {
        inputVector.x = Mathf.Clamp(inputVector.x, -0.5f, 0.5f);
        inputVector.y = Mathf.Clamp(inputVector.y, -0.5f, 0.5f);
    }
    return inputVector;
}

private void addForceToRigidbody(float speed, Vector3 targetVelocity) {
    targetVelocity = transform.TransformDirection(targetVelocity) * speed;

    Vector3 velocity = rb.velocity;
    Vector3 velocityChange = (targetVelocity - velocity);
    velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
    velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
    velocityChange.y = 0;

    rb.AddForce(velocityChange, ForceMode.VelocityChange);
}

private bool canJump() {
    bool canJump = Physics.Raycast(transform.position, Vector3.down, 1.5f);
    return canJump;
}

private void Jumping() {
    rb.AddForce(0f, jump, 0f, ForceMode.Impulse);
}

问题修复方案

1. 台阶/地形高差跳不过问题

  • 修复接地检测逻辑:当前Update中isGrounded的赋值逻辑完全错误,应使用canJump()的射线检测结果实时判断是否接地:
    private void Update() {
        isGrounded = canJump(); // 用射线检测实时更新接地状态
        if(gameInput.isJumping() && isGrounded) {
            Jumping();
        }
    }
    
  • 调整跳跃参数:检查jump冲量值,第三人称角色通常需要8-12的数值(根据Rigidbody质量微调),确保力度足够越过常规台阶。
  • 优化碰撞体与刚体设置:将Capsule Collider底部调整至略低于角色模型脚部,避免射线检测误判;开启Rigidbody的Interpolate选项,提升移动平滑度,减少碰撞卡顿。
  • 添加台阶辅助逻辑:在FixedUpdate中加入胶囊体检测,当检测到前方低矮障碍时,给角色施加微小向上力辅助爬坡:
    // 放在FixedUpdate内
    CapsuleCollider col = GetComponent<CapsuleCollider>();
    float stepCheckDistance = 0.3f;
    float stepUpForce = 2f;
    if(Physics.CapsuleCast(col.bounds.center, 
                           col.bounds.center + Vector3.up * col.height,
                           col.radius, 
                           transform.forward, 
                           stepCheckDistance)) {
        rb.AddForce(Vector3.up * stepUpForce, ForceMode.Impulse);
    }
    

2. 撞墙后无法侧向移动问题

  • 修正移动力投影逻辑:当前移动力直接按角色朝向施加,撞墙后会被物理引擎完全抵消。修改addForceToRigidbody,将目标速度投影到碰撞平面上:
    private void addForceToRigidbody(float speed, Vector3 targetVelocity) {
        targetVelocity = transform.TransformDirection(targetVelocity) * speed;
    
        // 获取接触面法线,将速度投影到水平平面
        RaycastHit hit;
        Vector3 groundNormal = Vector3.up;
        if(Physics.Raycast(transform.position, Vector3.down, out hit, 2f)) {
            groundNormal = hit.normal;
        }
        targetVelocity = Vector3.ProjectOnPlane(targetVelocity, groundNormal);
    
        Vector3 velocity = rb.velocity;
        Vector3 velocityChange = (targetVelocity - new Vector3(velocity.x, 0, velocity.z));
        velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
        velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
        velocityChange.y = 0;
    
        rb.AddForce(velocityChange, ForceMode.VelocityChange);
    }
    
  • 调整Rigidbody参数:关闭除Freeze Rotation X/Y/Z外的所有冻结选项;将Drag设为0.5-1,避免速度骤降;Angular Drag设为5左右,防止角色旋转过度。
  • 优化物理材质:给角色和障碍物的碰撞体使用低摩擦力(0.1-0.3)的物理材质,减少侧向移动时的阻力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:27:25