Unity正交相机(Orthographic Camera)边界内鼠标平移异常问题求助
解决正交相机鼠标平移边界卡住的问题
这个问题我之前做项目时也碰到过,核心原因是你的代码在相机被边界限制后,没有同步更新拖动的基准点,导致后续的偏移计算始终基于超出边界时的错误数值,所以往回拖的时候相机会卡住不动。
问题根源分析
原代码里,你用Origin(拖动开始的世界点)和Diference(当前鼠标世界点与相机位置的差值)来计算新相机位置:
Vector3 newCameraPosition = Origin - Diference;
当相机被Mathf.Clamp限制在边界后,相机位置不再跟随鼠标移动,但Origin还是最初的拖动起点,Diference的计算会基于当前鼠标的世界点和被限制后的相机位置,这就导致newCameraPosition一直被卡在边界值,直到鼠标回到边界范围内,Diference的变化才会让计算结果脱离边界。
修复方案:基于屏幕偏移的拖动逻辑
更好的做法是用屏幕坐标的位移来计算相机移动,正交相机下屏幕位移和世界空间移动是线性对应的,而且不需要依赖Raycast的世界点(当然你可以保留Raycast判断是否点击地形)。同时,当相机被边界限制时,及时更新拖动的基准点,确保后续计算始终正确。
修改后的代码如下:
public class CameraDragMouse : MonoBehaviour { private Vector3 _dragStartScreenPos; private Vector3 _dragStartCameraPos; private bool _isDragging; private float _minPanningBoundaryX; private float _maxPanningBoundaryX; private float _minPanningBoundaryZ; private float _maxPanningBoundaryZ; private Camera _mainCamera; private void Start() { _mainCamera = GetComponentInChildren<Camera>(); CameraCenter.CenterCameraOnPosition(new Vector3(24, 0, 24)); var cameraStartPos = transform.position; _minPanningBoundaryX = cameraStartPos.x - 40; _maxPanningBoundaryX = cameraStartPos.x + 40; _minPanningBoundaryZ = cameraStartPos.z - 40; _maxPanningBoundaryZ = cameraStartPos.z + 40; } void LateUpdate() { if (Input.GetMouseButtonDown(0)) { // 仅在点击地形时允许拖动 Ray ray = _mainCamera.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, Constants.LAYER_MASK_TERRAIN)) { _isDragging = true; // 记录拖动起始的屏幕位置和相机位置 _dragStartScreenPos = Input.mousePosition; _dragStartCameraPos = transform.position; } } else if (Input.GetMouseButtonUp(0)) { _isDragging = false; } if (_isDragging) { // 计算鼠标屏幕位置的偏移量 Vector3 screenDelta = Input.mousePosition - _dragStartScreenPos; // 将屏幕偏移转换为世界空间单位(正交相机专属计算) float worldUnitsPerPixel = _mainCamera.orthographicSize * 2 / Screen.height; Vector3 worldDelta = new Vector3(screenDelta.x, 0, screenDelta.y) * worldUnitsPerPixel; // 计算新的相机位置(鼠标向右拖,相机向左移,所以取反) Vector3 targetPos = _dragStartCameraPos - worldDelta; // 限制在边界内 Vector3 clampedPos = new Vector3( Mathf.Clamp(targetPos.x, _minPanningBoundaryX, _maxPanningBoundaryX), transform.position.y, Mathf.Clamp(targetPos.z, _minPanningBoundaryZ, _maxPanningBoundaryZ) ); // 关键:如果相机被边界限制,更新拖动基准点 if (clampedPos != targetPos) { _dragStartCameraPos = clampedPos; _dragStartScreenPos = Input.mousePosition; } transform.position = clampedPos; } } }
修复要点说明
- 屏幕转世界空间的计算:利用正交相机的
orthographicSize(相机视口半高的世界单位)和屏幕高度,算出每个像素对应的世界单位,确保屏幕位移和相机移动的比例正确。 - 边界限制时更新基准点:当相机被
Clamp后,立即把当前相机位置和鼠标屏幕位置设为新的拖动起点,这样后续的偏移计算就会基于边界位置重新开始,鼠标往回拖时相机能立即响应。 - 更清晰的状态管理:用
_isDragging替代原有的Drag,变量名更具语义,逻辑也更清晰。
这样修改后,不管你拖到边界后怎么反向拖动,相机都会实时跟随鼠标移动,不会再出现卡住的情况。
内容的提问来源于stack exchange,提问作者eek




