Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Say you have a trivial prefab, "Box", which we'll say is nothing more than a standard meter cube.

  • 1 - The prefab Box is in your Project panel

  • 2 - Drag it to the Scene

  • 3 - Obviously it now appears in the Hierarchy panel also, and probably selected and shown in Inspector

To be clear, game is NOT Play when you do this, you're only in ordinary Editor mode.

Is it possible to make a script (an "Editor script"?) so that,

  • when you do "1" and "2" above, (again this is in Editor mode, not during a game)

  • when 3 happens, we can affect the new Box item in the scene

  • So, simple example: we will set the Z position to "2" always, no matter where you drop it.

In short: Editor code so that every time you drag a prefab P to the scene, it sets the position z to 2.0.

Is this possible in Unity? I know nothing of "editor scripts".

It seems very obvious this should be possible.

like image 809
Fattie Avatar asked Aug 29 '18 05:08

Fattie


2 Answers

You can add a custom window editor which implements OnHierarchyChange to handle all the changes in the hierarchy window. This script must be inside the Editor folder. To make it work automatically make sure you have this window opened first.

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

I attached the following script to the box:

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

Note that OnHierarchyChange is called twice (once when you start dragging the box onto the scene, and once when you release the mouse button) so isAdded is defined as an int to enable its comparison with 2. So you can also have initialization logic when x.isAdded < 1

like image 105
Bizhan Avatar answered Sep 20 '22 16:09

Bizhan


You could thy this:

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
}

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


Analysis:

  1. This does in fact work!

  2. One problem! It happens when the object starts to exist, so, when you are dragging it to the scene, but before you let go. So in fact, if you specifically want to adjust the position in some way (snapping to a grid - whatever) it is not possible using this technique!

So, for example, this will work perfectly:

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 + "°";
    }
}

enter image description here

Note that this works correctly, that is to say it does "not run" when you actually Play the game. If you hit "Play" it won't then again set random spins :)

Great stuff

like image 34
ikkentim Avatar answered Sep 21 '22 16:09

ikkentim