Unity触摸/鼠标移动物体故障:Physics.Raycast未进入判断分支
解决Physics.Raycast未触发及触摸/鼠标移动物体的问题
看起来你遇到的核心问题是Physics.Raycast完全没命中目标,不管是触摸还是鼠标操作都走不通移动物体的逻辑。我帮你梳理几个最可能的原因和修复方案:
1. 先排查最容易踩坑的LayerMask问题
这是Raycast失效最常见的原因:
- 确保你的目标物体所在的Layer,已经在
touchInputMask的勾选列表里(在Inspector面板找到这个变量,展开LayerMask选择对应的层)。 - 检查目标物体的Layer设置,确实和你勾选的一致,别选错了层。
- 额外提醒:如果是代码里动态设置LayerMask,要注意位运算的正确性,比如
touchInputMask = 1 << LayerMask.NameToLayer("YourLayerName");,别直接赋值数字导致掩码错误。
2. 确认目标物体有有效的碰撞体
Raycast只能检测带Collider组件的物体:
- 给需要拖动的物体添加合适的Collider(比如BoxCollider、SphereCollider),并且不要勾选
Is Trigger(默认Raycast会忽略触发器,除非你用Physics.Raycast的重载参数指定检测触发器)。 - 调整Collider的大小,确保它完全覆盖你要点击的物体区域,避免因为Collider太小导致射线碰不到。
3. 检查Camera.main是否有效
代码里用了Camera.main,它只会找到**标签为"MainCamera"**的相机:
- 打开场景里的相机,在Inspector的Tag下拉菜单里确认它的标签是"MainCamera",否则
Camera.main会返回null,射线根本生成不了。 - 更稳妥的方式是直接在脚本里引用相机对象(拖到Inspector的变量栏),避免依赖
Camera.main的查找开销和潜在的空引用问题。
4. 修复代码里的关键错误
你的代码里有几个明显的问题,直接导致逻辑无法执行:
问题A:nbTouches变量未赋值
你在判断if (nbTouches > 0),但代码里没有给这个变量赋值!应该替换成Input.touchCount,也就是:
int nbTouches = Input.touchCount; if (nbTouches > 0) { // 原触摸逻辑... }
问题B:没有处理鼠标输入
你提到鼠标点击也有问题,但当前代码完全没写鼠标操作的逻辑,补充这部分:
// 处理鼠标输入(单点) if (Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, Mathf.Infinity, touchInputMask)) { GameObject recipient = hit.transform.gameObject; // 记录鼠标拖动的初始数据,用固定的fingerId=0代表鼠标 objectst tempobj = new objectst(); tempobj.screenPoint = Camera.main.WorldToScreenPoint(recipient.transform.position); tempobj.offset = recipient.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, tempobj.screenPoint.z)); // 先移除可能存在的鼠标记录,再添加 if (touchobjects.ContainsKey(0)) touchobjects.Remove(0); touchobjects.Add(0, tempobj); } } if (Input.GetMouseButton(0)) { if (touchobjects.ContainsKey(0)) { objectst tempobj = touchobjects[0]; Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, tempobj.screenPoint.z); Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + tempobj.offset; // 找到当前鼠标命中的物体 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, Mathf.Infinity, touchInputMask)) { hit.transform.position = curPosition; } } } if (Input.GetMouseButtonUp(0)) { if (touchobjects.ContainsKey(0)) { touchobjects.Remove(0); } }
问题C:TouchPhase.Ended里的位置计算错误
在触摸结束时,你写的位置计算会导致物体跳回错误位置,其实拖动结束时物体已经在正确位置了,只需要移除对应的触摸记录即可:
if (touch.phase == TouchPhase.Ended) { print("#### touch ended"); if (touchobjects.ContainsKey(touch.fingerId)) { touchobjects.Remove(touch.fingerId); } }
修复后的完整Update示例
public LayerMask touchInputMask; private static List<GameObject> touchList = new List<GameObject>(); public static Dictionary<int, objectst> touchobjects = new Dictionary<int, objectst>(); private GameObject[] touchesOld; private RaycastHit hit; public GUIText Count, IndexLift; private Vector3 targetPos; public struct objectst { public Vector3 screenPoint; public Vector3 offset; } void Update(){ // 处理触摸输入 int nbTouches = Input.touchCount; if (nbTouches > 0) { touchesOld = new GameObject[touchList.Count]; touchList.CopyTo(touchesOld); touchList.Clear(); for (int i = 0; i < nbTouches; i++) { Touch touch = Input.GetTouch(i); Ray ray = Camera.main.ScreenPointToRay(touch.position); if (Physics.Raycast(ray, out hit, Mathf.Infinity, touchInputMask)) { GameObject recipient = hit.transform.gameObject; print("#### touch hit name object "+recipient.name); touchList.Add(recipient); if (touch.phase == TouchPhase.Began) { print("#### touch begin"); objectst tempobj = new objectst(); tempobj.screenPoint = Camera.main.WorldToScreenPoint(recipient.transform.position); tempobj.offset = recipient.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, tempobj.screenPoint.z)); // 先移除旧的记录,避免重复添加 if (touchobjects.ContainsKey(touch.fingerId)) touchobjects.Remove(touch.fingerId); touchobjects.Add(touch.fingerId, tempobj); } if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved) { print("#### touch stationary or moved"); if (touchobjects.ContainsKey(touch.fingerId)) { objectst tempobj = touchobjects[touch.fingerId]; Vector3 curScreenPoint = new Vector3(touch.position.x, touch.position.y, tempobj.screenPoint.z); Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + tempobj.offset; print("#### object should move to x = "+curPosition.x+" y = "+curPosition.y); recipient.transform.position = curPosition; } } if (touch.phase == TouchPhase.Ended) { print("#### touch ended"); if (touchobjects.ContainsKey(touch.fingerId)) { touchobjects.Remove(touch.fingerId); } } } } } // 处理鼠标输入 if (Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, Mathf.Infinity, touchInputMask)) { GameObject recipient = hit.transform.gameObject; objectst tempobj = new objectst(); tempobj.screenPoint = Camera.main.WorldToScreenPoint(recipient.transform.position); tempobj.offset = recipient.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, tempobj.screenPoint.z)); if (touchobjects.ContainsKey(0)) touchobjects.Remove(0); touchobjects.Add(0, tempobj); } } if (Input.GetMouseButton(0)) { if (touchobjects.ContainsKey(0)) { objectst tempobj = touchobjects[0]; Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, tempobj.screenPoint.z); Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + tempobj.offset; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, Mathf.Infinity, touchInputMask)) { hit.transform.position = curPosition; } } } if (Input.GetMouseButtonUp(0)) { if (touchobjects.ContainsKey(0)) { touchobjects.Remove(0); } } }
最后验证步骤
- 运行前先在Inspector给
touchInputMask勾选目标物体的Layer。 - 确认目标物体有启用的非触发器Collider。
- 检查相机标签为"MainCamera"或者已经正确引用相机。
- 测试触摸和鼠标操作,看控制台的
print输出是否能命中物体。
内容的提问来源于stack exchange,提问作者tamtoum1987
相关产品推荐
相关产品推荐

