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

求助:如何在鼠标位置实例化Prefab?拖拽2D精灵生成3D物体位置异常

解决Canvas拖拽2D精灵并在鼠标位置实例化3D物体的问题

核心问题其实是屏幕坐标到3D世界坐标的转换——你从Canvas拿到的鼠标位置是2D屏幕空间的,而3D物体需要的是世界空间坐标,直接用屏幕坐标生成自然会跑到默认位置。下面是我整理的落地解决方案,亲测可行:

实现步骤

1. 理清坐标转换逻辑

不同相机类型的转换方式不一样,得先搞清楚你用的是哪种:

  • 透视相机(Perspective Camera):需要指定一个「放置平面」(比如地面的Y轴高度),通过射线检测获取鼠标在这个平面上的世界坐标。
  • 正交相机(Orthographic Camera):转换更直接,直接把屏幕坐标转成世界坐标就行,Z轴可以按需调整。

2. 完整可复用代码

把下面的脚本挂在你的Canvas精灵上(或者单独的管理器对象),直接填好参数就能用:

using UnityEngine;
using UnityEngine.EventSystems;

public class DragSpawn3DPrefab : MonoBehaviour, IDragHandler, IEndDragHandler
{
    [Header("生成配置")]
    public GameObject targetPrefab; // 要生成的3D预制体
    public Camera mainCamera; // 拖拽用的相机(直接拖入场景里的主相机)
    public float spawnYHeight = 0f; // 透视相机下的放置平面高度(比如地面Y值)

    // 拖拽过程可以加预览逻辑,不需要就删掉
    public void OnDrag(PointerEventData eventData)
    {
        if (targetPrefab == null) return;
        Vector3 previewPos = GetMouseWorldPos();
        // 这里可以放预览物体的代码,比如临时显示一个半透明预制体
    }

    // 松开鼠标时生成物体
    public void OnEndDrag(PointerEventData eventData)
    {
        if (targetPrefab == null || mainCamera == null) return;
        
        Vector3 spawnPos = GetMouseWorldPos();
        Instantiate(targetPrefab, spawnPos, Quaternion.identity);
    }

    // 核心:把鼠标屏幕坐标转成3D世界坐标
    private Vector3 GetMouseWorldPos()
    {
        Vector3 mouseScreenPos = Input.mousePosition;
        Vector3 worldPos;

        if (mainCamera.orthographic)
        {
            // 正交相机转换逻辑
            worldPos = mainCamera.ScreenToWorldPoint(new Vector3(mouseScreenPos.x, mouseScreenPos.y, mainCamera.nearClipPlane));
            worldPos.z = 0f; // 按需调整Z轴,比如保持预制体默认Z值
        }
        else
        {
            // 透视相机用射线检测找平面交点
            Ray ray = mainCamera.ScreenPointToRay(mouseScreenPos);
            Plane spawnPlane = new Plane(Vector3.up, new Vector3(0, spawnYHeight, 0));
            
            if (spawnPlane.Raycast(ray, out float distance))
            {
                worldPos = ray.GetPoint(distance);
            }
            else
            {
                // 射线没击中平面时的 fallback 位置
                worldPos = mainCamera.ScreenToWorldPoint(new Vector3(mouseScreenPos.x, mouseScreenPos.y, mainCamera.farClipPlane / 2));
            }
        }

        return worldPos;
    }
}

3. 关键注意事项

  • 确保你的2D精灵有碰撞体组件(比如BoxCollider2D),否则无法触发拖拽事件。
  • 不要用Camera.main,直接把场景里的主相机拖入脚本参数,避免每帧查找相机的性能损耗。
  • 如果Canvas是Screen Space - Camera模式,脚本里的mainCamera必须和Canvas的渲染相机一致。

测试流程

  1. 把脚本挂在Canvas中的2D精灵上。
  2. 拖入你的3D预制体和主相机到脚本的参数面板。
  3. 运行游戏,拖拽精灵后松开,3D物体就会精准生成在鼠标对应的世界位置了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:17:35