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

如何为Unity正交相机设置上下旋转移动的角度范围

正交相机绕玩家旋转俯仰范围限制实现

问题描述

正在制作采用正交相机(orthographic camera)的游戏,预期交互逻辑为按住鼠标时相机可绕玩家旋转,同时支持上下俯仰移动,要求俯仰移动仅能在较小的角度区间内进行。当前无法正确实现俯仰角度范围限制,直接对偏移坐标做钳制会导致相机到达阈值时位置异常、直接飞走。

原有实现代码如下:

void LateUpdate () {
    if (Input.GetMouseButtonDown(0))
    {
        RotateAroundPlayer = true;
    }
    else if (Input.GetMouseButtonUp(0))
    {
        RotateAroundPlayer = false;
    }

    if (RotateAroundPlayer)
    {
        Quaternion camTurnAngle =
            Quaternion.AngleAxis(Input.GetAxis("Mouse X") * RotationsSpeed, Vector3.up);
        Quaternion camUpDown =
            Quaternion.AngleAxis(Input.GetAxis("Mouse Y") * RotationsSpeed, transform.right);
       
        _cameraOffset = camUpDown * camTurnAngle * _cameraOffset;
        
    }
    Vector3 newPos = PlayerTransform.position + _cameraOffset;
    transform.position = Vector3.Slerp(transform.position, newPos, SmoothFactor);

    if (LookAtPlayer || RotateAroundPlayer)
        transform.LookAt(PlayerTransform);
}

错误尝试

曾尝试直接对相机偏移的Y坐标做钳制实现角度限制,代码如下:

_cameraOffset.y = Mathf.Clamp(_cameraOffset.y,  minViewingAngle,maxViewingAngle);

该方案问题:_cameraOffset.y是空间位置坐标值,和角度值量纲不统一,直接用角度阈值钳制坐标会导致空间位置计算错乱,触发相机位置飞离的异常。

正确实现方案

实现逻辑

  • 单独维护水平旋转角、俯仰角两个数值变量,不再直接对偏移向量连续做四元数乘法累加旋转
  • 每次读取鼠标输入时仅累加对应角度值,累加后直接对俯仰角做范围钳制,从根源上限制角度区间
  • 用钳制后的角度值重新计算相机相对玩家的偏移向量,保持相机和玩家的距离始终和初始值一致,不会出现距离跳变
  • 该方案对正交相机、透视相机通用,和相机投影模式无关

完整实现代码

首先在类中补充所需变量:

// 原有可配置参数
public float RotationsSpeed = 200f;
public float SmoothFactor = 10f;
public Transform PlayerTransform;
public bool LookAtPlayer = true;
public float minViewingAngle = -20f; // 最小俯角,单位为度,建议不低于-80
public float maxViewingAngle = 45f;  // 最大仰角,单位为度,建议不高于80

private Vector3 _cameraOffset;
private bool RotateAroundPlayer;

// 新增:存储当前轨道旋转角度
private float _currentYaw;   // 水平绕玩家Y轴的旋转角
private float _currentPitch; // 上下俯仰角

在初始化函数(Start/Awake)中计算初始角度,避免开局相机位置跳变:

void Start()
{
    // 记录初始相机偏移
    _cameraOffset = transform.position - PlayerTransform.position;
    float offsetDistance = _cameraOffset.magnitude;
    // 从初始偏移换算初始水平旋转角
    _currentYaw = Mathf.Atan2(_cameraOffset.x, _cameraOffset.z) * Mathf.Rad2Deg;
    // 从初始偏移换算初始俯仰角
    float horizontalDist = Mathf.Sqrt(_cameraOffset.x * _cameraOffset.x + _cameraOffset.z * _cameraOffset.z);
    _currentPitch = Mathf.Atan2(_cameraOffset.y, horizontalDist) * Mathf.Rad2Deg;
}

修正后的LateUpdate逻辑:

void LateUpdate () {
    if (Input.GetMouseButtonDown(0))
    {
        RotateAroundPlayer = true;
    }
    else if (Input.GetMouseButtonUp(0))
    {
        RotateAroundPlayer = false;
    }

    if (RotateAroundPlayer)
    {
        // 读取鼠标输入累加角度
        float mouseX = Input.GetAxis("Mouse X") * RotationsSpeed * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * RotationsSpeed * Time.deltaTime;
        
        _currentYaw += mouseX;
        _currentPitch -= mouseY; // 鼠标上移对应仰角增加,方向不符可调整此处正负号
        // 核心:直接钳制俯仰角度,不会出现坐标计算错乱
        _currentPitch = Mathf.Clamp(_currentPitch, minViewingAngle, maxViewingAngle);

        // 根据角度重新计算偏移向量,保持和玩家的距离不变
        float offsetDistance = _cameraOffset.magnitude;
        float yawRad = _currentYaw * Mathf.Deg2Rad;
        float pitchRad = _currentPitch * Mathf.Deg2Rad;
        
        _cameraOffset.x = offsetDistance * Mathf.Sin(yawRad) * Mathf.Cos(pitchRad);
        _cameraOffset.y = offsetDistance * Mathf.Sin(pitchRad);
        _cameraOffset.z = offsetDistance * Mathf.Cos(yawRad) * Mathf.Cos(pitchRad);
    }

    Vector3 newPos = PlayerTransform.position + _cameraOffset;
    transform.position = Vector3.Slerp(transform.position, newPos, SmoothFactor * Time.deltaTime);

    if (LookAtPlayer || RotateAroundPlayer)
        transform.LookAt(PlayerTransform);
}

调优说明

  • 如果出现旋转方向和预期不符,调整_currentPitch -= mouseY处的正负号即可
  • 角度阈值不要设置超过[-90,90]区间,否则会出现相机翻转到玩家正上/正下方的穿模问题
  • 代码中补充了Time.deltaTime缩放旋转速度和插值速度,保证不同帧率下旋转手感一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:57:19