Is it possible to toggle the "Edit Collider" mode of a Polygon Collider 2D via script?

Short description: I wanna write a script and when I’m clicking onto a GameObject in the scene or the Hierarchy that has this script attatched it should instantly trigger this object’s Polygon Collider to go into edit mode without me pressing that button: -3606653--293053--Screenshot (7).png-

Now I already built up the script’s structure so that it is [ExecuteInEditMode] but the Update portion only compiles for the Unity Editor and only runs when I’m not in playmode, the only thing I need to complete this nice little tool to help me design my game is a reference to this “Edit Collider” button.

Can I actually access the edit mode of a Polygon Collider 2D via some kind of script method or variable (like getComponent.toggleEditMode() or .setEditMode for example)?

And I know this is a very uncommon desire but let me explain myself first:
I’m using a collection of scripts from ViicEsquivel and pakfront that are taking the shape of a Polygon Collider 2D and convert it into a 2D Mesh, basically making the collider visible and renderable at runtime (the scripts can be found here How to fill polygon collider with a solid color? - Questions & Answers - Unity Discussions). This is so convenient that I decided to make nearly the entire static part (a.k.a. walls) of the world geometry for my 2D space game just by shaping Polygon Collider verticies and applying those scripts.
But needing to press the Edit Collider button everytime I want to shape a wall will most likely slow down my workflow by a lot which is why I want to write a script to do it for me. I just can’t find a way to pull this one off myself /:

3606653--293053--Screenshot (7).png
3606653--293053--Screenshot (7).png

I’m also using a similar work flow. Did you find a way to access the button, maybe using reflection?

I figured out how to do this with reflection against Unity 2018.2.21. Here’s some snippets from the code I used on my editor window tool. No guarantees it will work on different versions of Unity though.

private object m_polygonUtility = null;
private MethodInfo m_polygonUtilityStartEditing = null;
private MethodInfo m_polygonUtilityStopEditing = null;
private MethodInfo m_polygonUtilityOnSceneGUI = null;
  
public void editPolygon(GameObject obj)
{
    if (m_polygonUtility == null)
    {
        System.Type type = Assembly.LoadWithPartialName("UnityEditor").GetType("UnityEditor.PolygonEditorUtility");
        var ctors = type.GetConstructors();
        m_polygonUtility = ctors[0].Invoke(new object[] { });
        m_polygonUtilityStartEditing = type.GetMethod("StartEditing");
        m_polygonUtilityStopEditing = type.GetMethod("StopEditing");
        m_polygonUtilityOnSceneGUI = type.GetMethod("OnSceneGUI");
    }

    PolygonCollider2D collider = obj.GetComponent<PolygonCollider2D>();
    if (collider != null)
    {
        m_polygonUtilityStartEditing.Invoke(m_polygonUtility, new object[] { collider });
    }
}

void OnSceneGUI(SceneView sceneView)
{
    if (m_polygonUtilityOnSceneGUI != null)
    {
        m_polygonUtilityOnSceneGUI.Invoke(m_polygonUtility, new object[] { });
    }
}
1 Like

Thanks for this, still works in Unity 2019.4.x!

I have taken the liberty to make it into a static class for easier use. I’ve also added some workarounds for cases in which UnityEditor might crash (still does sometimes, so use with care!). Hope others will find it useful.

#if UNITY_EDITOR
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace yourCoolNamespace
{
    /// <summary>
    /// Enables to start and stop editing a PolygonCollider2D via script.
    /// Based on "infosekr"s code, see: https://discussions.unity.com/t/712436
    ///
    /// Usage:
    ///     EditPolygonCollider2D.Start( aGameObjectWithAColliderOnIt );
    ///     EditPolygonCollider2D.Stop( aGameObjectWithAColliderOnIt );
    ///
    /// Settings:
    ///     EditPolygonCollider2D.DisableColliderWhileEditing (bool, default true).
    ///       This was necessary because Unity tends to crash if edit is started via this
    ///       script but not ended via script. To avoid this we simpy disable editing on
    ///       the collider while we edit via script.
    /// </summary>
    [InitializeOnLoad]
    public static class EditPolygonCollider2D
    {
        public static bool DisableColliderWhileEditing = true;

        static object polygonUtility = null;
        static MethodInfo polygonUtilityStartEditing = null;
        static MethodInfo polygonUtilityStopEditing = null;
        static MethodInfo polygonUtilityOnSceneGUI = null;
        static bool onListenerActive = false;
        static GameObject currentlyEditedObject;
        static HideFlags currentlyEditedObjectHideFlags;

        static EditPolygonCollider2D()
        {
            cacheTypeInfosIfNecessary();
        }

        static void cacheTypeInfosIfNecessary()
        {
            if (polygonUtility == null)
            {
                System.Type type = Assembly.Load("UnityEditor").GetType("UnityEditor.PolygonEditorUtility");
                var ctors = type.GetConstructors();
                polygonUtility = ctors[0].Invoke(new object[] { });
                polygonUtilityStartEditing = type.GetMethod("StartEditing");
                polygonUtilityStopEditing = type.GetMethod("StopEditing");
                polygonUtilityOnSceneGUI = type.GetMethod("OnSceneGUI");
            }
        }

        static void setListeners( bool active )
        {
            if (active)
            {
                if (onListenerActive == false)
                {
#if UNITY_2019_1_OR_NEWER
                    SceneView.duringSceneGui += OnSceneGUI;
#else
                    SceneView.onSceneGUIDelegate += OnSceneGUI;
#endif
                    Selection.selectionChanged += OnSelectionChanged;
                }
            }
            else
            {
                if (onListenerActive == true)
                {
#if UNITY_2019_1_OR_NEWER
                    SceneView.duringSceneGui -= OnSceneGUI;
#else
                    SceneView.onSceneGUIDelegate -= OnSceneGUI;
#endif
                    Selection.selectionChanged -= OnSelectionChanged;
                }
            }
            onListenerActive = active;
        }

        private static void OnSelectionChanged()
        {
            if(currentlyEditedObject != null && Selection.activeGameObject != currentlyEditedObject)
            {
                Stop(currentlyEditedObject.transform);
            }
        }

        public static void Start(Component obj)
        {
            Start(obj.transform);
        }

        public static void Start(GameObject obj)
        {
            Start(obj.transform);
        }

        public static void Start(Transform trans)
        {
            Tools.current = Tool.None;
            currentlyEditedObject = trans.gameObject;
            cacheTypeInfosIfNecessary();
            PolygonCollider2D collider = trans.GetComponent<PolygonCollider2D>();
            if (collider != null)
            {
                polygonUtilityStartEditing.Invoke(polygonUtility, new object[] { collider });
                setListeners(true);
            }

            if(DisableColliderWhileEditing)
            {
                currentlyEditedObjectHideFlags = collider.hideFlags;
                collider.hideFlags = HideFlags.NotEditable;
            }
        }

        public static void Stop(Component obj)
        {
            Stop(obj.transform);
        }

        public static void Stop(GameObject obj)
        {
            Stop(obj.transform);
        }

        public static void Stop(Transform trans)
        {
            currentlyEditedObject = null;
            cacheTypeInfosIfNecessary();
            PolygonCollider2D collider = trans.GetComponent<PolygonCollider2D>();
            if (collider != null)
            {
                polygonUtilityStopEditing.Invoke(polygonUtility, new object[] {});
                setListeners(false);
            }

            if (DisableColliderWhileEditing)
            {
                collider.hideFlags = currentlyEditedObjectHideFlags;
            }
        }

        public static void OnSceneGUI(SceneView sceneView)
        {
            if (polygonUtilityOnSceneGUI != null)
            {
                polygonUtilityOnSceneGUI.Invoke(polygonUtility, new object[] { });
            }
        }
    }
}

#endif
1 Like

This is what I found (needs the Game Object selected)

ToolManager.SetActiveTool(Assembly.Load("UnityEditor").GetType("UnityEditor.PolygonCollider2DTool"));
1 Like

Since Unity 2022.2 UnityEditor.PolygonEditorUtility does not longer exist.

#if UNITY_EDITOR
using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEngine;

namespace Kamgam.Helpers
{
    /// <summary>
    /// Enables to start and stop editing a PolygonCollider2D via script.
    /// Based on "infosekr"s code, see: https://discussions.unity.com/t/712436
    ///
    /// Usage:
    ///     EditPolygonCollider2D.Start( aGameObjectWithAColliderOnIt );
    ///     EditPolygonCollider2D.Stop( aGameObjectWithAColliderOnIt );
    ///    
    /// Settings:
    ///     EditPolygonCollider2D.DisableColliderWhileEditing (bool, default true).
    ///       This was necessary because Unity tends to crash if edit is started via this
    ///       script but not ended via script. To avoid this we simpy disable editing on
    ///       the collider while we edit via script.
    /// </summary>
    [InitializeOnLoad]
    public static class EditPolygonCollider2D
    {
        public static bool DisableColliderWhileEditing = true;
        public static bool IsEditing { get => currentlyEditedObject != null; }

        static System.Type polygonCollider2DToolType = null;
        static bool onListenerActive = false;
        static GameObject currentlyEditedObject;
        static HideFlags currentlyEditedObjectHideFlags;
        static System.Type lastUsedToolType;
       

        static EditPolygonCollider2D()
        {
            cacheTypeInfosIfNecessary();
        }

        static void cacheTypeInfosIfNecessary()
        {
            if (polygonCollider2DToolType == null)
            {
                polygonCollider2DToolType = Assembly.Load("UnityEditor").GetType("UnityEditor.PolygonCollider2DTool");
            }
        }

        static void setListeners( bool active )
        {
            if (active)
            {
                if (onListenerActive == false)
                {
#if UNITY_2019_1_OR_NEWER
                    SceneView.duringSceneGui += OnSceneGUI;
#else
                    SceneView.onSceneGUIDelegate += OnSceneGUI;
#endif
                    Selection.selectionChanged += OnSelectionChanged;
                }
            }
            else
            {
                if (onListenerActive == true)
                {
#if UNITY_2019_1_OR_NEWER
                    SceneView.duringSceneGui -= OnSceneGUI;
#else
                    SceneView.onSceneGUIDelegate -= OnSceneGUI;
#endif
                    Selection.selectionChanged -= OnSelectionChanged;
                }
            }
            onListenerActive = active;
        }

        private static void OnSelectionChanged()
        {
            if(currentlyEditedObject != null && Selection.activeGameObject != currentlyEditedObject)
            {
                Stop(currentlyEditedObject.transform);
            }
        }

        public static void Start(Component obj)
        {
            Selection.objects = new GameObject[] { obj.gameObject };
            Start(obj.transform);
        }

        public static void Start(GameObject obj)
        {
            Selection.objects = new GameObject[] { obj };
            Start(obj.transform);
        }

        public static void Start(Transform trans)
        {
            if (trans != null && currentlyEditedObject == null)
            {
                cacheTypeInfosIfNecessary();

                lastUsedToolType = ToolManager.activeToolType;
                ToolManager.SetActiveTool(polygonCollider2DToolType);
                currentlyEditedObject = trans.gameObject;
               
                PolygonCollider2D collider = trans.GetComponent<PolygonCollider2D>();
                if (collider != null)
                {
                    setListeners(true);
                }

                if (DisableColliderWhileEditing)
                {
                    currentlyEditedObjectHideFlags = collider.hideFlags;
                    collider.hideFlags = HideFlags.NotEditable;
                }
            }
        }

        public static void Stop(Component obj)
        {
            if (obj != null)
            {
                Stop(obj.transform);
            }
        }

        public static void Stop(GameObject obj)
        {
            if (obj != null)
            {
                Stop(obj.transform);
            }
        }

        public static void Stop(Transform trans)
        {
            if (trans != null && currentlyEditedObject != null)
            {
                cacheTypeInfosIfNecessary();
                currentlyEditedObject = null;
                PolygonCollider2D collider = trans.GetComponent<PolygonCollider2D>();
                if (collider != null)
                {
                    ToolManager.SetActiveTool(lastUsedToolType);
                    setListeners(false);
                }

                if (DisableColliderWhileEditing)
                {
                    collider.hideFlags = currentlyEditedObjectHideFlags;
                }
            }
            ToolManager.SetActiveTool(lastUsedToolType);
        }

        public static void OnSceneGUI(SceneView sceneView)
        {
        }
    }
}

#endif