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

Unity相机水平旋转Clamping失效:左转卡顿循环问题求助

问题解决:相机水平旋转限制卡顿问题

问题根源

你的代码存在两个核心问题:

  1. 角度范围冲突:无限制时rotation.x是0-360循环,但限制时用了-15到15的范围,向左旋转时rotation.x接近360,被Clamp强制拉到15,随后xQuat.eulerAngles.y又把它拉回360附近,形成卡顿循环
  2. 限制逻辑顺序错误:限制应该基于玩家当前朝向的基准值,而非全局角度范围

修正方案

1. 优化玩家碰撞检测(可选但推荐)

给射线检测添加层掩码,忽略玩家自身的碰撞体,避免误判:

// 玩家移动脚本中
public bool isTouchingObj;
// 提前在Inspector中赋值玩家层
public LayerMask playerLayer;

void Update()
{
    // 从玩家位置稍高处发射射线,避免地面误触
    Vector3 rayOrigin = transform.position + Vector3.up * 0.5f;
    // 计算射线检测的层掩码:排除玩家层
    int mask = ~playerLayer.value;
    isTouchingObj = Physics.Raycast(rayOrigin, transform.forward, 2f, mask);
}

2. 重构相机旋转限制逻辑

统一使用相对角度差做限制,避免0-360和-180-180的范围冲突:

// 相机控制脚本中
public PlayerMovement playerMovement;
public float sensitivity = 2f;
// 存储玩家初始朝向(触发限制时的基准角度)
private float baseRotationY;
private Vector2 rotation;

void DoNormalCameraControls()
{
    Vector2 mouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));

    // 处理垂直旋转(保持原有逻辑)
    rotation.y += mouseDelta.y * sensitivity;
    rotation.y = Mathf.Clamp(rotation.y, -90f, 90f);
    var yQuat = Quaternion.AngleAxis(rotation.y, Vector3.left);

    // 处理水平旋转
    if (playerMovement.isTouchingObj)
    {
        // 首次触发限制时记录基准角度
        if (!playerMovement.isTouchingObjLastFrame)
        {
            baseRotationY = player.transform.eulerAngles.y;
        }

        // 计算当前鼠标输入带来的角度增量
        float deltaRotation = mouseDelta.x * sensitivity;
        // 计算相对于基准角度的总旋转量
        float currentRelativeRotation = Mathf.DeltaAngle(baseRotationY, player.transform.eulerAngles.y + deltaRotation);
        // 限制相对旋转在±15度内
        float clampedDelta = Mathf.Clamp(currentRelativeRotation, -15f, 15f) - Mathf.DeltaAngle(baseRotationY, player.transform.eulerAngles.y);
        
        // 更新玩家旋转
        float newRotationY = player.transform.eulerAngles.y + clampedDelta;
        var xQuat = Quaternion.Euler(0, newRotationY, 0);
        player.transform.rotation = xQuat;
    }
    else
    {
        // 无限制时的正常旋转逻辑
        rotation.x += mouseDelta.x * sensitivity;
        rotation.x = Mathf.Repeat(rotation.x, 360f); // 替代原有0-360循环逻辑
        var xQuat = Quaternion.AngleAxis(rotation.x, Vector3.up);
        player.transform.rotation = xQuat;
    }

    // 应用相机垂直旋转
    transform.localRotation = yQuat;
}

补充:PlayerMovement中添加状态记录

在玩家移动脚本中添加变量记录上一帧的触碰状态,用于触发限制时初始化基准角度:

// PlayerMovement脚本中
public bool isTouchingObj;
public bool isTouchingObjLastFrame;

void Update()
{
    // 先记录上一帧状态
    isTouchingObjLastFrame = isTouchingObj;
    // 然后执行射线检测赋值isTouchingObj
    // ...(原有检测代码)
}

关键说明

  • 使用Mathf.DeltaAngle计算角度差,自动处理360度循环的问题,无需手动调整0-360范围
  • 限制逻辑基于玩家触发碰撞时的初始朝向,而非全局角度,符合“靠近物体时限制旋转范围”的需求
  • 分离水平和垂直旋转的处理逻辑,避免相互干扰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 02:12:55