using System.Collections; using System.Collections.Generic; using Unity.Collections; using UnityEngine; using UnityEngine.Experimental.U2D; using UnityEngine.U2D; #if UNITY_EDITOR using UnityEditor; #endif [ExecuteAlways] public class GeometryCollider : MonoBehaviour { [SerializeField] bool m_UpdateCollider = false; int m_HashCode = 0; void Start() { } // Update is called once per frame void Update() { if (m_UpdateCollider) Bake(gameObject, false); } static public void Bake(GameObject go, bool forced) { var spriteShapeController = go.GetComponent(); var spriteShapeRenderer = go.GetComponent(); var polyCollider = go.GetComponent(); var geometryCollider = go.GetComponent(); if (spriteShapeController != null && polyCollider != null) { var spline = spriteShapeController.spline; if (geometryCollider != null) { int splineHashCode = spline.GetHashCode(); if (splineHashCode == geometryCollider.m_HashCode && !forced) return; geometryCollider.m_HashCode = splineHashCode; } NativeArray indexArray; NativeSlice posArray; NativeSlice uv0Array; NativeArray geomArray; spriteShapeRenderer.GetChannels(65536, out indexArray, out posArray, out uv0Array); geomArray = spriteShapeRenderer.GetSegments(spline.GetPointCount() * 8); NativeArray indexArrayLocal = new NativeArray(indexArray.Length, Allocator.Temp); List points = new List(); int indexCount = 0, vertexCount = 0, counter = 0; for (int u = 0; u < geomArray.Length; ++u) { if (geomArray[u].indexCount > 0) { for (int i = 0; i < geomArray[u].indexCount; ++i) { indexArrayLocal[counter] = (ushort)(indexArray[counter] + vertexCount); counter++; } vertexCount += geomArray[u].vertexCount; indexCount += geomArray[u].indexCount; } } Debug.Log(go.name + " : " + counter); OuterEdges(polyCollider, indexArrayLocal, posArray, indexCount); } } // Generate the outer edges from the Renderer mesh. Based on code from www.h3xed.com static void OuterEdges(PolygonCollider2D polygonCollider, NativeArray triangles, NativeSlice vertices, int triangleCount) { // Get just the outer edges from the mesh's triangles (ignore or remove any shared edges) Dictionary> edges = new Dictionary>(); for (int i = 0; i < triangleCount; i += 3) { for (int e = 0; e < 3; e++) { int vert1 = triangles[i + e]; int vert2 = triangles[i + e + 1 > i + 2 ? i : i + e + 1]; string edge = Mathf.Min(vert1, vert2) + ":" + Mathf.Max(vert1, vert2); if (edges.ContainsKey(edge)) { edges.Remove(edge); } else { edges.Add(edge, new KeyValuePair(vert1, vert2)); } } } // Create edge lookup (Key is first vertex, Value is second vertex, of each edge) Dictionary lookup = new Dictionary(); foreach (KeyValuePair edge in edges.Values) { if (lookup.ContainsKey(edge.Key) == false) { lookup.Add(edge.Key, edge.Value); } } // Create empty polygon collider polygonCollider.pathCount = 0; // Loop through edge vertices in order int startVert = 0; int nextVert = startVert; int highestVert = startVert; List colliderPath = new List(); while (true) { // Add vertex to collider path colliderPath.Add(vertices[nextVert]); // Get next vertex nextVert = lookup[nextVert]; // Store highest vertex (to know what shape to move to next) if (nextVert > highestVert) { highestVert = nextVert; } // Shape complete if (nextVert == startVert) { // Add path to polygon collider polygonCollider.pathCount++; polygonCollider.SetPath(polygonCollider.pathCount - 1, colliderPath.ToArray()); colliderPath.Clear(); // Go to next shape if one exists if (lookup.ContainsKey(highestVert + 1)) { // Set starting and next vertices startVert = highestVert + 1; nextVert = startVert; // Continue to next loop continue; } // No more verts break; } } } #if UNITY_EDITOR [MenuItem("SpriteShape/Generate Geometry Collider", false, 358)] public static void BakeGeometryCollider() { if (Selection.activeGameObject != null) GeometryCollider.Bake(Selection.activeGameObject, true); } #endif }