如何通过单击而不拖动对象在场景视图中的鼠标点处创建对象?

How can I create an object at the mouse point in scene view by clicking not dragging the object?

一般情况下,大部分物体都是通过拖动什么的方式放置在场景视图中的。我想右键单击鼠标(不拖动对象)在场景视图中创建一个对象。我知道这需要一些编辑器编码,但我不确定如何去做。

更新

经过深思熟虑后,我意识到使用 MenuItem 非常适合我。下面是我的代码:

SLMenuItems:

public class SLMenuItems : MonoBehaviour {

public bool canClickSceneViewToCreatePath = false;

void Start()
{

}

[MenuItem("Component/Create Custom Object")]
static void CreateObject()  {
   Debug.Log("menu item selected");
    canClickSceneViewToCreatePath = true;
} 
}

SLMenuItemsEditor:

    [CustomEditor(typeof(SLMenuItems))]
public class SLMenuItemsEditor : Editor {
    SLMenuItems slMenuItems;


    void OnEnable()
    {
        slMenuItems = (SLMenuItems)target;

    }


    void OnSceneGUI()
        {
            if (slMenuItems.canClickSceneViewToCreatePath)  {
                Vector3 pointsPos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin;

                if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
                {

                    // create object here at pointsPos

                    slMenuItems.canClickSceneViewToCreatePath = false;
                }
            }

        }
    }

我不断收到以下错误:

Assets/SLMenuItems.cs(23,9): error CS0120: An object reference is required to access non-static member `SLMenuItems.canClickSceneViewToCreatePath'

指向行:

canClickSceneViewToCreatePath = true;

SLMenuItems.

您的 CreateObject 方法是 static 但您的 canClickSceneViewToCreatePath 值不是。

它与编辑器脚本无关,而是与您的 class SlMenuItems 本身有关。

static 方法未实例化,或者换句话说,它在该组件类型的所有实例之间共享,而每个组件的 non-static 值可能不同。

那么静态方法——对所有实例都相同——"know",它应该访问哪些实例值?

所以要么使方法 non-static 要么使变量静态。取决于您的进一步需求。

因为 MenuItem 需要一个静态方法,所以也使变量成为静态的。


我建议您使 class 完全不继承自 MonoBehaviour,因为它对 GameObject 没有任何行为。它只带来了一些编辑器功能,因此宁愿将其设为静态 class,可以 "live" 在资产中,而无需实例化。

您可以使用 SceneView.onSceneGUIDelegateOnSceneGUI 注册回调,而无需为此执行编辑器脚本:

private static GameObject lastCreated;

private static bool isCreating;

public static class SLMenuItems
{   
    [MenuItem("Component/Create Custom Object")]
    private static void CreateObject() 
    {
        Debug.Log("menu item selected");

        isCreating = true;
        lastCreated = null;

        // Add a callback for SceneView update
        SceneView.onSceneGUIDelegate -= UpdateSceneView;
        SceneView.onSceneGUIDelegate += UpdateSceneView;
    }

    private static void UpdateSceneView(SceneView sceneView)
    {
        if(lastCreated)
        {
            // Keep lastCreated focused
            Selection.activeGameObject = lastCreated;
        }

        if(isCreating)
        {  
            if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
            {
                Vector3 pointsPos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin;

                //Todo create object here at pointsPos
                lastCreated = Instantiate(somePrefab);

                // Avoid the current event being propagated
                // I'm not sure which of both works better here
                Event.current.Use();
                Event.current = null;

                // Keep the created object in focus
                Selection.activeGameObject = lastCreated;

                // exit creation mode
                isCreating = false;
            }
        } 
        else
        {
            // Skip if event is Layout or Repaint
            if(e.type == EventType.Layout || e.type == EventType.Repaint)
            {
                Selection.activeGameObject = lastCreated;
                return;
            }

            // Prevent Propagation
            Event.current.Use();
            Event.current = null;
            Selection.activeGameObject = lastCreated;
            lastCreated = null;

            // Remove the callback
            SceneView.onSceneGUIDelegate -= UpdateSceneView;
        }      
    }
}

但我建议您更改问题标题,因为这实际上不是您之前描述的 "task" 的解决方案。