Unity,编辑器时脚本,在添加到场景事件的游戏对象上

Unity, editor-time script, On GameObject Added to Scene Event

假设您有一个普通的预制件,"Box",我们会说它只不过是一个标准的立方体。

需要说明的是,当您执行此操作时,游戏并未开始运行,您仅处于普通编辑器模式。

是否可以制作一个脚本("Editor script"?)以便

简而言之:编辑器代码,以便每次将预制件 P 拖到场景中时,它都会将位置 z 设置为 2.0。

这在 Unity 中可行吗?我对 "editor scripts".

一无所知

很明显这应该是可能的。

Monobehaviours 有一个 Reset 方法,该方法 仅在编辑器模式下被调用 ,每当您重置 或首次实例化 一个对象。

public class Example : MonoBehaviour
{
    void Reset()
    {
        transform.position =
           new Vector3(transform.position.x, 2.22f, transform.position.z);
        Debug.Log("Hi ...");
    }
}

你可以这样做:

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteInEditMode]
public class PrintAwake : MonoBehaviour
{
    #if UNITY_EDITOR
    void Awake()  .. Start() also works perfectly
    {
        if(!EditorApplication.isPlaying)
            Debug.Log("Editor causes this Awake");
    }
    #endif
}

https://docs.unity3d.com/ScriptReference/ExecuteInEditMode.html


分析:

  1. 这确实有效!

  2. 一个问题!它发生在对象开始存在时,因此,当您将其拖动到场景中,但您放手之前。所以事实上,如果你特别想以某种方式调整 position(捕捉到网格 - 无论如何),使用这种技术是不可能的!

因此,例如,这将完美地工作:

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteInEditMode]
public class PrintAwake : MonoBehaviour
{
    #if UNITY_EDITOR
    void Start() {
        if(!EditorApplication.isPlaying) {
            Debug.Log("Editor causes this START!!");
            RandomSpinSetup();
            }
    }
    #endif
    private void RandomSpinSetup() {
        float r = Random.Range(3,8) * 10f;
        transform.eulerAngles = new Vector3(0f, r, 0f);
        name = "Cube: " + r + "°";
    }
}

请注意,这可以正常工作,也就是说 "not run" 当您实际玩游戏时它可以正常工作。如果您点击 "Play",它将不会再次设置随机旋转:)

很棒的东西

您可以添加实现 OnHierarchyChange 的自定义 window 编辑器来处理层次结构 window 中的所有更改。该脚本必须位于 Editor 文件夹中。要使其自动运行,请确保先打开此 window。

using System.Linq;
using UnityEditor;
using UnityEngine;

public class HierarchyMonitorWindow : EditorWindow
{
    [MenuItem("Window/Hierarchy Monitor")]
    static void CreateWindow()
    {
        EditorWindow.GetWindow<HierarchyMonitorWindow>();
    }

    void OnHierarchyChange()
    {
        var addedObjects = Resources.FindObjectsOfTypeAll<MyScript>()
                                    .Where(x => x.isAdded < 2);

        foreach (var item in addedObjects)
        {
            //if (item.isAdded == 0) early setup
            
            if (item.isAdded == 1) {
                
                // do setup here,
                // will happen just after user releases mouse
                // will only happen once
                Vector3 p = transform.position;
                item.transform.position = new Vector3(p.x, 2f, p.z);
            }

            // finish with this:
            item.isAdded++;
        }
    }
}

我在盒子里附上了以下脚本:

public class MyScript : MonoBehaviour {
    public int isAdded { get; set; }
}

请注意,OnHierarchyChange 被调用了两次(一次是在您开始将框拖到场景中,一次是在您释放鼠标按钮时),因此 isAdded 被定义为一个 int 以使其与 2 进行比较。所以你也可以在 x.isAdded < 1

时有初始化逻辑