You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
        }
    }
}

最后验证步骤

  1. 运行前先在Inspector给touchInputMask勾选目标物体的Layer。
  2. 确认目标物体有启用的非触发器Collider。
  3. 检查相机标签为"MainCamera"或者已经正确引用相机。
  4. 测试触摸和鼠标操作,看控制台的print输出是否能命中物体。

内容的提问来源于stack exchange,提问作者tamtoum1987

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:33:56