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

Unity中基于Raycast的碰撞检测偏移问题求助

Unity 3D角色Raycast碰撞检测偏移&穿模问题解决

我在Unity开发3D游戏时,用Raycast搭建的碰撞检测系统出现偏移:调整playerSize参数后,角色无法贴合测试立方体,还会出现单侧部分穿入的情况。原代码如下:

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

public class Player : MonoBehaviour {
    [SerializeField] private float movementSpeed = 7f;
    [SerializeField] private float rotationSpeed = 10f;
    [SerializeField] private float playerSize = .7f;

    [SerializeField] private GameInput gameInput;

    private bool isWalking;

    private void Update() {
        Vector2 inputVector = gameInput.GetMovementVectorNormalized();

        Vector3 moveDir = new Vector3 (inputVector.x, 0f, inputVector.y).normalized;

        bool canMove = !Physics.Raycast(transform.position, moveDir, playerSize);

        if (canMove) {
            transform.position += moveDir * movementSpeed * Time.deltaTime;
        }

        isWalking = moveDir != Vector3.ze
        transform.forward = Vector3.Slerp(transform.forward, moveDir, Time.deltaTime *      rotationSpeed);
    }
}

问题原因

  1. 单点Raycast的局限性:Raycast是从角色原点发射的单射线,只能检测直线上的单点碰撞,无法模拟角色的实际体积,斜向移动或碰撞体边缘不规则时极易出现检测偏移。
  2. 未覆盖移动步长:代码仅检测playerSize长度内的碰撞,但角色每帧实际移动距离为movementSpeed * Time.deltaTime,若该距离大于剩余碰撞间隙,会直接穿模。
  3. 语法错误:isWalking = moveDir != Vector3.ze拼写不完整,应为Vector3.zero,会导致编译失败。

解决方案

  • 改用SphereCast模拟体积碰撞:SphereCast发射球形检测体,更贴合角色体积,避免单点检测的偏移问题。
  • 扩展检测范围:将检测长度设为角色半径 + 当前帧移动步长,覆盖完整移动路径,防止穿模。
  • 修正语法错误:补全Vector3.zero拼写。

修改后的代码

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

public class Player : MonoBehaviour {
    [SerializeField] private float movementSpeed = 7f;
    [SerializeField] private float rotationSpeed = 10f;
    [SerializeField] private float playerRadius = .7f; // 改为radius更贴合SphereCast语义
    [SerializeField] private GameInput gameInput;
    [SerializeField] private CapsuleCollider playerCollider; // 引用角色碰撞体

    private bool isWalking;

    private void Update() {
        Vector2 inputVector = gameInput.GetMovementVectorNormalized();
        Vector3 moveDir = new Vector3(inputVector.x, 0f, inputVector.y).normalized;

        float moveDistance = movementSpeed * Time.deltaTime;
        // 从碰撞体中心发射SphereCast,检测范围包含移动步长
        bool canMove = !Physics.SphereCast(playerCollider.bounds.center, playerRadius, moveDir, moveDistance + playerRadius);

        if (canMove) {
            transform.position += moveDir * moveDistance;
        }

        isWalking = moveDir != Vector3.zero;
        transform.forward = Vector3.Slerp(transform.forward, moveDir, Time.deltaTime * rotationSpeed);
    }
}

额外优化建议

  • 若未使用CapsuleCollider,可通过transform.position + Vector3.up * playerHeight/2设置检测起点(假设角色中心在半高处),避免从模型底部发射检测。
  • 给碰撞体添加PhysicsMaterial,将Dynamic Friction和Static Friction设为0,减少摩擦导致的移动卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 09:51:09