Can I detect the 2D scene view mode button in the editor through script and toggle the UI layer?

I’ve realized that in my currect project and nearly all my other projects that I never want to see my UI when I’m in 3D mode and I never want to see my game objects when I’m 2D mode. So I want to make an editor script which turns off the UI layer when I’m in 3D mode and turns off a specified list of game objects when I’m in 2D mode. How do? :stuck_out_tongue:

I’ve figured out through google and trial and error that this lets me know if I’ve clicked the 2D button or not:

But most of the time I get a null reference or nothing at all, but I assume that’s because I’m using the wrong callback to detect it.

Where should I put the script? Do I have to write a custom inspector or make a monobehaviour that I put on a game object? Or is it possible to just write a script that lies in my project folder and works from there? The latter is what I want.

SceneView for example has no scripting documentation and I’m really struggling with finding examples of something similar to what I want. Every example I find is for a custom inspector and I just want this script to work on it’s own by just existing in a project, if possible of course.

After some more trial and error this is what I have at the moment:

using UnityEngine;
using UnityEditor;

[ExecuteInEditMode]
public class SceneViewToggle : MonoBehaviour {

    public GameObject[] objectsToHideIn2dMode;

    bool lastModeWas2d;

    void Update() {
        if (SceneView.lastActiveSceneView == null) {
            return;
        }

        if (SceneView.lastActiveSceneView.in2DMode && !lastModeWas2d) {
            ShowUI();
        }
        else if (!SceneView.lastActiveSceneView.in2DMode && lastModeWas2d) {
            HideUI();
        }
    }

    void HideUI() {
        lastModeWas2d = false;

        foreach (GameObject obj in objectsToHideIn2dMode) {
            obj.SetActive(true);
        }
    }

    void ShowUI() {
        lastModeWas2d = true;

        foreach (GameObject obj in objectsToHideIn2dMode) {
            obj.SetActive(false);
        }
    }
}

It has to be put on a game object which is not what I want and Update() is apparently only called in the editor when something is changed so I have to move or change a game object for this to work. I also don’t know how I can access the layers and hide/show the UI layer from script similar to clicking the eye-icon in the upper right corner of the Editor.

Anyone able to point me in the right direction?

Edit: Hmm, now that I think about it I guess I need to have it on a game object to be able to assign the objects I want to hide. But I guess that part could be solved better by hiding all other layers or something like that. This is just a rough first attempt at the problem.

For anyone else looking to do this, I used Twiik’s code as a starting point and took a slightly different approach that that doesn’t require adding any components or modifying your scene in any way. The toggling of visibility is tailored pretty specifically to how my scenes are setup, but I may do another pass and use Tools.visibleLayers to toggle visibility using the UI layer. That should make things work in a much more generic way, and remove the need for the play mode change handler that resets the active flag on objects that were disabled before play mode starts up.

Anyway, I have this as an editor script and it’s been working pretty well for me:

using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;

/// <summary>
/// Automatically manages visibility of UI and 3D objects based on whether the editor is in 2D or 3D mode.
/// </summary>
[InitializeOnLoad]
internal class UIVisibilityToggle
{
    private static bool sLastModeWas2D;

    static UIVisibilityToggle()
    {
        if (SceneView.lastActiveSceneView != null)
            sLastModeWas2D = SceneView.lastActiveSceneView.in2DMode;

        EditorApplication.update += Update;
        EditorApplication.playModeStateChanged += OnPlayModeChange;
    }

    private static void Update()
    {
        var sceneView = SceneView.lastActiveSceneView;
        if (sceneView == null)
            return;

        if(!EditorApplication.isPlayingOrWillChangePlaymode)
        {
            if (sceneView.in2DMode && !sLastModeWas2D)
                SetUIVisibility(true, EditorSceneManager.GetActiveScene());
            else if (!sceneView.in2DMode && sLastModeWas2D)
                SetUIVisibility(false, EditorSceneManager.GetActiveScene());
        }

        sLastModeWas2D = sceneView.in2DMode;
    }

    private static void SetUIVisibility(bool uiVisbility, Scene scene)
    {
        if (scene == null)
            return;

        var objects = scene.GetRootGameObjects();
        foreach(var obj in objects)
        {
            var canvas = obj.GetComponent<Canvas>();
            bool isUI = canvas != null && canvas.renderMode != RenderMode.WorldSpace;
            obj.SetActive(isUI ? uiVisbility : !uiVisbility);
        }
    }

    private static void ShowAllObjects(Scene scene)
    {
        if (scene == null)
            return;

        // Restore all top-level objects
        var objects = scene.GetRootGameObjects();
        foreach (var obj in objects)
        {
            obj.SetActive(true);
        }
    }

    private static void OnPlayModeChange(PlayModeStateChange state)
    {
        if (state == PlayModeStateChange.ExitingEditMode)
        {
            ShowAllObjects(EditorSceneManager.GetActiveScene());
        }
        else if (state == PlayModeStateChange.EnteredEditMode)
        {
            SetUIVisibility(sLastModeWas2D, EditorSceneManager.GetActiveScene());
        }
    }
}
1 Like