Unity相机水平旋转Clamping失效:左转卡顿循环问题求助
问题解决:相机水平旋转限制卡顿问题
问题根源
你的代码存在两个核心问题:
- 角度范围冲突:无限制时
rotation.x是0-360循环,但限制时用了-15到15的范围,向左旋转时rotation.x接近360,被Clamp强制拉到15,随后xQuat.eulerAngles.y又把它拉回360附近,形成卡顿循环 - 限制逻辑顺序错误:限制应该基于玩家当前朝向的基准值,而非全局角度范围
修正方案
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
相关产品推荐
相关产品推荐

