坐标与相机:为什么指针到了,物品却没跟上
拖拽功能里,玩家手指在屏幕上移动,物品却出现在角落,这是最常见的入门问题之一。通常不是数学太难,而是把两种坐标当成了一种。
每次读写位置之前,先问:这是哪个空间里的位置?
四种常见位置
| 坐标 | 表达什么 | 常见入口 |
|---|---|---|
| 屏幕坐标 | 指针在屏幕上的像素位置 | 输入事件的位置 |
| 世界坐标 | 对象在场景中的位置 | Transform.position |
| 本地坐标 | 相对父对象的位置 | Transform.localPosition |
| UI 布局坐标 | 相对锚点等布局规则的位置 | RectTransform.anchoredPosition |
同样是数字 (100, 100),在不同空间里的含义完全不同。父对象缩放、旋转或锚点变化,也会改变局部位置最终显示的结果。
相机怎样参与转换
场景视图像开发者自由移动的观察工具;Game 视图主要展示游戏摄像机的输出。你能在 Scene 中看见一个物品,并不保证它在摄像机可见范围、正确层级或正确深度内。
2D 常用正交相机,物品不会随离相机远近而缩小;透视相机会产生近大远小。把屏幕点转换到世界点时,深度或射线命中的平面也要明确,不能只传入 x 和 y 然后假定结果就在棋盘上。
Canvas 拖拽的推荐思路
UI 物品建议通过 RectTransformUtility 把屏幕位置转成目标父节点的局部位置。下面是思路片段,假设拖拽物体是父 RectTransform 的直接子节点,使用一致的锚点设置;实际工程需保留按下时的抓取偏移。
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
parentRect, eventData.position, eventData.pressEventCamera,
out Vector2 localPoint))
{
itemRect.localPosition = new Vector3(localPoint.x, localPoint.y, 0f);
}
eventData 来自 UI 指针事件。Screen Space - Overlay 场景下转换相机通常为 null;Camera / World Space 模式要使用正确事件相机。不要随意填 Camera.main 来“试试”。
localPosition 与 anchoredPosition 也不是任意锚点下都可互换。工程里应固定一种布局约定,并在转换函数旁说明约束。
父子关系还影响什么
把物品从棋盘移动到拖拽层,能让它显示在其他控件前面,但会改变父坐标空间。重新设置父节点后,要决定是否保留世界位置,并重新计算局部位置。
放下时,不要从像素位置直接推断存档格子。由棋盘布局或命中结果得到格子编号,再交给规则判断。业务状态保存的是“第几格”,视图负责把格子映射到画面位置。
验收时改变环境
至少试竖屏、超长屏、不同 Canvas 缩放和棋盘父节点缩放;从物品边缘抓取,确认没有瞬移到手指中心。给 AI 的任务里写清 Canvas 模式、锚点、父子层级和目标坐标空间,能减少大量来回修补。