Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Feature Request Making edge colliders and polygon colliders snap to grid.

Discussion in '2D Experimental Preview' started by Tony-Tonijn, Sep 6, 2016.

  1. Tony-Tonijn

    Tony-Tonijn

    Joined:
    Nov 13, 2013
    Posts:
    7
    I think the title says it all. During development of a platformer type of game I have used the edge collider and polygon collider quite extensively and trough its use I have programmed a little script that automatically snaps all the points on both of the colliders to the nearest grid point. It would be great if the normal functionality of holding "control to snap to whole units" would also work for these components while editing the points on the collider. Maybe a smart check that sees if it should snap to the grid instead if applicable?

    The script I use right now is posted below for everyone else to use:

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. [RequireComponent(typeof(PolygonCollider2D))]
    7. public class PolygonColliderSnapper : MonoBehaviour {
    8.  
    9.     public PolygonCollider2D polygon;
    10.  
    11.     // Use this for initialization
    12.     void Start () {
    13.         if (polygon == null)
    14.             polygon = GetComponent<PolygonCollider2D>();
    15.     }
    16.    
    17.     // Update is called once per frame
    18.     void Update () {
    19.    
    20.     }
    21.  
    22.     public void Snap()
    23.     {
    24.         int counter = 0;
    25.         for (int pathIndex = 0; pathIndex < polygon.pathCount; pathIndex++)
    26.         {
    27.             Vector2[] path = polygon.GetPath(pathIndex);
    28.             for (long pointIndex = 0; pointIndex < path.Length; pointIndex++)
    29.             {
    30.                 counter++;
    31.                 Vector2 point = path[pointIndex];
    32.                 path[pointIndex] = new Vector2(Mathf.RoundToInt(point.x), Mathf.RoundToInt(point.y));
    33.             }
    34.             polygon.points = path;
    35.             polygon.SetPath(pathIndex, path);
    36.         }
    37.         print("Snapped " + counter + " points.");
    38.     }
    39. }
    40.  
    41. // Editor button script
    42. using UnityEngine;
    43. using System.Collections;
    44. using UnityEditor;
    45.  
    46. [CustomEditor(typeof(PolygonColliderSnapper))]
    47. public class ObjectBuilderEditor : Editor
    48. {
    49.     public override void OnInspectorGUI()
    50.     {
    51.         DrawDefaultInspector();
    52.  
    53.         PolygonColliderSnapper snapper = (PolygonColliderSnapper)target;
    54.         if (GUILayout.Button("Snap Points"))
    55.         {
    56.             snapper.Snap();
    57.         }
    58.     }
    59. }
    60.  
     
    Stardog likes this.
  2. Johaness_Reuben

    Johaness_Reuben

    Joined:
    Jan 27, 2016
    Posts:
    253
    Yes, something to look into.
     
  3. legoblaster1234

    legoblaster1234

    Joined:
    Aug 7, 2017
    Posts:
    27
    noob question: how do i use the script?
     
  4. nyanginator

    nyanginator

    Joined:
    Jul 16, 2019
    Posts:
    1
    Thanks for the script, Tony-Tonijn. legoblaster1234, I got it to work like this:
    1. Right click in Project tab to create 2 scripts, "PolygonColliderSnapper" and "ObjectBuilderEditor".
    2. Copy the respective code to their own script files (Lines 1-39 to PolygonColliderSnapper, and Lines 40-60 to ObjectBuilderEditor).
    3. Add the PolygonColliderSnapper script to whatever GameObject you have your collider on. Drag the GameObject from the Hierarchy onto the Polygon slot of the Polygon Collider Snapper (Script) component in the Inspector.
    4. Click on Snap Points and the collider points should update.
     
  5. Desoro

    Desoro

    Joined:
    Apr 30, 2016
    Posts:
    9
    For those that don't want to add a bunch of components in the scene to achieve this:

    Code (CSharp):
    1. [MenuItem("Tools/Snap Poly Paths")]
    2. static void SnapPolyPaths()
    3. {
    4.     var gos = EditorSceneManager.GetActiveScene().GetRootGameObjects();
    5.     var count = 0;
    6.  
    7.     for (var i = 0; i < gos.Length; i++)
    8.     {
    9.         var go = gos[i];
    10.         var polys = go.GetComponentsInChildren<PolygonCollider2D>(true);
    11.  
    12.         foreach (var poly in polys)
    13.         {
    14.             for (var n = 0; n < poly.pathCount; n++)
    15.             {
    16.                 var path = poly.GetPath(n);
    17.  
    18.                 for (var p = 0; p < path.Length; p++)
    19.                 {
    20.                     var v2 = path[p];
    21.                     var x = Mathf.Round(v2.x * 2f) / 2f; // Snaps every 0.5f
    22.                     var y = Mathf.Round(v2.y * 2f) / 2f; // Snaps every 0.5f
    23.  
    24.                     path[p] = new Vector2(x, y);
    25.                 }
    26.  
    27.                 poly.SetPath(n, path);
    28.             }
    29.  
    30.             count++;
    31.         }
    32.     }
    33.  
    34.     EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    35.  
    36.     Debug.LogWarningFormat("Snapped {0} poly colliders.", count);
    37. }
     
    Last edited: Oct 19, 2019
    Tony-Tonijn likes this.
  6. nixsnake

    nixsnake

    Joined:
    Aug 26, 2015
    Posts:
    4
    A little changes for peoples in 2020 :D Make a c# script file with name: "MenuTest". Create empty gameobject in Hierarchy and attach file script to gameobject. A new menu with name "MyMenu" will appear in Unity.

    Code (CSharp):
    1. using UnityEditor;
    2.  
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5. public class MenuTest : MonoBehaviour
    6. {
    7.     // Add a menu item named "Do Something" to MyMenu in the menu bar.
    8.     [MenuItem("MyMenu/Collider")]
    9.     static void SnapPolyPaths()
    10.     {
    11.         var gos = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().GetRootGameObjects();
    12.         var count = 0;
    13.  
    14.         for (var i = 0; i < gos.Length; i++)
    15.         {
    16.             var go = gos[i];
    17.             var polys = go.GetComponentsInChildren<PolygonCollider2D>(true);
    18.  
    19.             foreach (var poly in polys)
    20.             {
    21.                 for (var n = 0; n < poly.pathCount; n++)
    22.                 {
    23.                     var path = poly.GetPath(n);
    24.  
    25.                     for (var p = 0; p < path.Length; p++)
    26.                     {
    27.                         var v2 = path[p];
    28.                         var x = Mathf.Round(v2.x * 2f) / 2f; // Snaps every 0.5f
    29.                         var y = Mathf.Round(v2.y * 2f) / 2f; // Snaps every 0.5f
    30.  
    31.                         path[p] = new Vector2(x, y);
    32.                     }
    33.  
    34.                     poly.SetPath(n, path);
    35.                 }
    36.  
    37.                 count++;
    38.             }
    39.         }
    40.  
    41.         UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
    42.  
    43.         Debug.LogWarningFormat("Snapped {0} poly colliders.", count);
    44.     }
    45.  
    46. }
     
    Last edited: Mar 31, 2020
    Tony-Tonijn likes this.
  7. the_Simian

    the_Simian

    Joined:
    Mar 13, 2011
    Posts:
    37
    Hey what is up in 2020!
    Here is a modified version of this script that I use for myself. It is based on the top post but it adds menu items for both
    PolygonCollider2d
    as well as
    EdgeCollider2d
    ! I keep it in my editor folder as ColliderSnapper.cs

    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using UnityEditor.SceneManagement;
    5. public class MenuTest : MonoBehaviour
    6. {
    7.     [MenuItem("Assets/Simiancraft/PolygonCollider2D Snapper")]
    8.     private static void SnapPolyPaths()
    9.     {
    10.         var gos = EditorSceneManager.GetActiveScene().GetRootGameObjects();
    11.         var polygonCount = 0;
    12.         var pathCount = 0;
    13.         for (var i = 0; i < gos.Length; i++)
    14.         {
    15.             var go = gos[i];
    16.             var polys = go.GetComponentsInChildren<PolygonCollider2D>(true);
    17.             foreach (var poly in polys)
    18.             {
    19.                 for (var n = 0; n < poly.pathCount; n++)
    20.                 {
    21.                     var path = poly.GetPath(n);
    22.                     for (var p = 0; p < path.Length; p++)
    23.                     {
    24.                         var v2 = path[p];
    25.                         var x = Mathf.Round(v2.x * 2f) / 2f;
    26.                         var y = Mathf.Round(v2.y * 2f) / 2f;
    27.                         path[p] = new Vector2(x, y);
    28.                         pathCount++;
    29.                     }
    30.                     poly.SetPath(n, path);
    31.                 }
    32.                 polygonCount++;
    33.             }
    34.         }
    35.         EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    36.         Debug.LogFormat("Snapped {0} paths across {1} poly colliders.", pathCount, polygonCount);
    37.     }
    38.  
    39.     [MenuItem("Assets/Simiancraft/EdgeCollider2D Snapper")]
    40.     private static void SnapEdgePoints()
    41.     {
    42.         var gos = EditorSceneManager.GetActiveScene().GetRootGameObjects();
    43.         var edgeColliderCount = 0;
    44.         var pointCount = 0;
    45.         for (var i = 0; i < gos.Length; i++)
    46.         {
    47.             var go = gos[i];
    48.             var edges = go.GetComponentsInChildren<EdgeCollider2D>(true);
    49.             foreach (var edge in edges)
    50.             {
    51.                 var points = edge.points;
    52.                 Vector2[] newPoints = new Vector2[points.Length];
    53.                 for (int pi = 0; pi < points.Length; pi++)
    54.                 {
    55.                     var pt = points[pi];
    56.                     var x = Mathf.Round(pt.x * 2f) / 2f;
    57.                     var y = Mathf.Round(pt.y * 2f) / 2f;
    58.                     newPoints[pi] = new Vector2(x, y);
    59.                     pointCount++;
    60.                 }
    61.                 edge.points = newPoints;
    62.                 edgeColliderCount++;
    63.             }
    64.         }
    65.         EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    66.         Debug.LogFormat("Snapped {0} points across {1} edge colliders.", pointCount, edgeColliderCount);
    67.     }
    68. }
    69.