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

Unity移动端相机绕玩家旋转穿墙遮挡问题求助(附代码)

解决Unity相机被遮挡的问题(基于Raycast动态调整位置)

你的思路完全正确——通过Raycast检测相机到玩家pivot之间的遮挡物,然后动态调整相机位置靠近pivot,就能避免被墙体挡住看不到玩家的情况。我帮你修改了代码,实现这个功能,同时修正了一些小问题:

修改后的完整代码

using UnityEngine;

public class CameraController : MonoBehaviour
{
    public Transform target1;
    public Transform pivot;
    protected ButtonLeft buttonLeft;
    protected ButtonRight buttonRight;
    public Vector3 offset;
    public bool useOffsetValues;
    public float rotateSpeed;
    private float originalDistance; // 存储相机到pivot的原始距离
    public float minDistance = 0.5f; // 相机能靠近的最小距离(避免贴脸穿模)

    private void Start()
    {
        buttonLeft = FindObjectOfType<ButtonLeft>();
        buttonRight = FindObjectOfType<ButtonRight>();

        if (!useOffsetValues)
        {
            offset = target1.position - transform.position;
        }
        // 初始化相机到pivot的原始距离
        originalDistance = offset.magnitude;

        pivot.position = target1.position;
        pivot.parent = null;
    }

    private void Update()
    {
        pivot.position = target1.position;

        // 处理左右旋转输入
        if (buttonLeft.Pressed)
        {
            pivot.Rotate(0, -90 * Time.deltaTime, 0);
            Debug.Log("rotate left");
        }
        if (buttonRight.Pressed)
        {
            pivot.Rotate(0, 90 * Time.deltaTime, 0);
            Debug.Log("rotate right"); // 修正原代码的日志错误
        }

        // 计算当前旋转后的相机目标位置(无遮挡时的位置)
        float desiredYAngle = pivot.eulerAngles.y;
        float desiredXAngle = pivot.eulerAngles.x;
        Quaternion rotation = Quaternion.Euler(desiredXAngle, desiredYAngle, 0);
        Vector3 desiredPosition = target1.position - (rotation * offset);

        // 发射射线检测遮挡:从pivot指向相机的目标位置
        Ray ray = new Ray(pivot.position, desiredPosition - pivot.position);
        RaycastHit hit;

        // 忽略玩家层,避免把玩家自身当成遮挡物(请确保你的玩家在"Player"层)
        LayerMask ignorePlayerMask = ~LayerMask.GetMask("Player");

        if (Physics.Raycast(ray, out hit, originalDistance, ignorePlayerMask))
        {
            // 计算新的相机距离,确保不小于最小距离
            float newDistance = Vector3.Distance(pivot.position, hit.point) - 0.1f;
            newDistance = Mathf.Max(newDistance, minDistance);

            // 根据新距离调整相机位置,避免贴墙
            transform.position = pivot.position + ray.direction * newDistance;
        }
        else
        {
            // 无遮挡时,回到原始位置
            transform.position = desiredPosition;
        }

        // 始终让相机看向玩家
        transform.LookAt(target1);
    }
}

关键改动说明

  • 新增原始距离变量:originalDistance记录相机到pivot的初始距离,作为射线检测的最大范围,确保检测只在相机正常活动区域内进行。
  • 完善射线检测逻辑:
    • 发射从pivot到相机目标位置的射线,精准检测路径上的遮挡物
    • 使用LayerMask忽略玩家层,防止相机把玩家自身误判为遮挡物
    • 命中遮挡物时,将相机移动到命中点前方一点(减去0.1f避免贴墙),同时通过minDistance限制最小距离,防止相机穿模到玩家体内
  • 修正细节错误:原代码中右键旋转的日志写成了"rotate left",现在改成了正确的"rotate right"
  • 添加距离保护:minDistance可以根据游戏需求调整,保证相机始终保持合理的最近视野

使用注意事项

  1. 确保你的玩家对象被分配到Player层,否则射线可能会误检测到玩家自身
  2. 可以根据场景大小和玩家模型尺寸,调整minDistance的值,平衡视野和防穿模效果
  3. 如果场景中有透明物体需要忽略,可以在LayerMask中添加对应的层

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 21:17:57