LegacyCollider.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.U2D;
  5. using ExtrasClipperLib;
  6. #if UNITY_EDITOR
  7. using UnityEditor;
  8. #endif
  9. public enum ColliderCornerType
  10. {
  11. Square,
  12. Round,
  13. Sharp
  14. }
  15. [ExecuteAlways]
  16. public class LegacyCollider : MonoBehaviour
  17. {
  18. [SerializeField]
  19. ColliderCornerType m_ColliderCornerType = ColliderCornerType.Square;
  20. [SerializeField]
  21. float m_ColliderOffset = 1.0f;
  22. [SerializeField]
  23. bool m_UpdateCollider = false;
  24. const float s_ClipperScale = 100000.0f;
  25. int m_HashCode = 0;
  26. // Start is called before the first frame update
  27. void Start()
  28. {
  29. }
  30. // Update is called once per frame
  31. void Update()
  32. {
  33. if (m_UpdateCollider)
  34. Bake(gameObject, false);
  35. }
  36. static void SampleCurve(float colliderDetail, Vector3 startPoint, Vector3 startTangent, Vector3 endPoint, Vector3 endTangent, ref List<IntPoint> path)
  37. {
  38. if (startTangent.sqrMagnitude > 0f || endTangent.sqrMagnitude > 0f)
  39. {
  40. for (int j = 0; j <= colliderDetail; ++j)
  41. {
  42. float t = j / (float)colliderDetail;
  43. Vector3 newPoint = BezierUtility.BezierPoint(startPoint, startTangent + startPoint, endTangent + endPoint, endPoint, t) * s_ClipperScale;
  44. path.Add(new IntPoint((System.Int64)newPoint.x, (System.Int64)newPoint.y));
  45. }
  46. }
  47. else
  48. {
  49. Vector3 newPoint = startPoint * s_ClipperScale;
  50. path.Add(new IntPoint((System.Int64)newPoint.x, (System.Int64)newPoint.y));
  51. newPoint = endPoint * s_ClipperScale;
  52. path.Add(new IntPoint((System.Int64)newPoint.x, (System.Int64)newPoint.y));
  53. }
  54. }
  55. public static void Bake(GameObject go, bool forced)
  56. {
  57. var sc = go.GetComponent<SpriteShapeController>();
  58. var lc = go.GetComponent<LegacyCollider>();
  59. if (sc != null)
  60. {
  61. List<IntPoint> path = new List<IntPoint>();
  62. int splinePointCount = sc.spline.GetPointCount();
  63. int pathPointCount = splinePointCount;
  64. ColliderCornerType cct = ColliderCornerType.Square;
  65. float co = 1.0f;
  66. if (lc != null)
  67. {
  68. int hashCode = sc.spline.GetHashCode() + lc.m_ColliderCornerType.GetHashCode() + lc.m_ColliderOffset.GetHashCode();
  69. if (lc.m_HashCode == hashCode && !forced)
  70. return;
  71. lc.m_HashCode = hashCode;
  72. cct = lc.m_ColliderCornerType;
  73. co = lc.m_ColliderOffset;
  74. }
  75. if (sc.spline.isOpenEnded)
  76. pathPointCount--;
  77. for (int i = 0; i < pathPointCount; ++i)
  78. {
  79. int nextIndex = SplineUtility.NextIndex(i, splinePointCount);
  80. SampleCurve(sc.colliderDetail, sc.spline.GetPosition(i), sc.spline.GetRightTangent(i), sc.spline.GetPosition(nextIndex), sc.spline.GetLeftTangent(nextIndex), ref path);
  81. }
  82. if (co != 0f)
  83. {
  84. List<List<IntPoint>> solution = new List<List<IntPoint>>();
  85. ClipperOffset clipOffset = new ClipperOffset();
  86. EndType endType = EndType.etClosedPolygon;
  87. if (sc.spline.isOpenEnded)
  88. {
  89. endType = EndType.etOpenSquare;
  90. if (cct == ColliderCornerType.Round)
  91. endType = EndType.etOpenRound;
  92. }
  93. clipOffset.ArcTolerance = 200f / sc.colliderDetail;
  94. clipOffset.AddPath(path, (ExtrasClipperLib.JoinType)cct, endType);
  95. clipOffset.Execute(ref solution, s_ClipperScale * co);
  96. if (solution.Count > 0)
  97. path = solution[0];
  98. }
  99. List<Vector2> pathPoints = new List<Vector2>(path.Count);
  100. for (int i = 0; i < path.Count; ++i)
  101. {
  102. IntPoint ip = path[i];
  103. pathPoints.Add(new Vector2(ip.X / s_ClipperScale, ip.Y / s_ClipperScale));
  104. }
  105. var pc = go.GetComponent<PolygonCollider2D>();
  106. if (pc)
  107. {
  108. pc.pathCount = 0;
  109. pc.SetPath(0, pathPoints.ToArray());
  110. }
  111. var ec = go.GetComponent<EdgeCollider2D>();
  112. if (ec)
  113. {
  114. if (co > 0f || co < 0f && !sc.spline.isOpenEnded)
  115. pathPoints.Add(pathPoints[0]);
  116. ec.points = pathPoints.ToArray();
  117. }
  118. }
  119. }
  120. #if UNITY_EDITOR
  121. [MenuItem("SpriteShape/Generate Legacy Collider", false, 358)]
  122. public static void BakeLegacyCollider()
  123. {
  124. if (Selection.activeGameObject != null)
  125. LegacyCollider.Bake(Selection.activeGameObject, true);
  126. }
  127. #endif
  128. }