如何为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
相关产品推荐
相关产品推荐

