Ingen beskrivning
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpriteShape.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. using System;
  2. using System.Collections.Generic;
  3. namespace UnityEngine.U2D
  4. {
  5. /// <summary>
  6. /// Tangent mode for control points that defines the bezier curve.
  7. /// </summary>
  8. public enum ShapeTangentMode
  9. {
  10. /// <summary>Linear mode where tangents are zero.</summary>
  11. Linear = 0,
  12. /// <summary>Set left and right tangents so that the bezier curve is continuous.</summary>
  13. Continuous = 1,
  14. /// <summary>Set custom left and right tangents.</summary>
  15. Broken = 2,
  16. };
  17. /// <summary>
  18. /// Corner type to assign sprite.
  19. /// </summary>
  20. public enum CornerType
  21. {
  22. /// <summary>Outer top left Corner.</summary>
  23. OuterTopLeft,
  24. /// <summary>Outer top right Corner.</summary>
  25. OuterTopRight,
  26. /// <summary>Outer bottom left Corner.</summary>
  27. OuterBottomLeft,
  28. /// <summary>Outer bottom right Corner.</summary>
  29. OuterBottomRight,
  30. /// <summary>Inner top left Corner.</summary>
  31. InnerTopLeft,
  32. /// <summary>Inner top right Corner.</summary>
  33. InnerTopRight,
  34. /// <summary>Inner bottom left Corner.</summary>
  35. InnerBottomLeft,
  36. /// <summary>Inner bottom right Corner.</summary>
  37. InnerBottomRight,
  38. };
  39. /// <summary>
  40. /// Level of detail of generated SpriteShape geometry.
  41. /// </summary>
  42. public enum QualityDetail
  43. {
  44. /// <summary>Highest level of detail (16).</summary>
  45. High = 16,
  46. /// <summary>Medium level of detail (8).</summary>
  47. Mid = 8,
  48. /// <summary>Low level of detail (4).</summary>
  49. Low = 4
  50. }
  51. /// <summary>
  52. /// Corner mode that defines how corners are handled when generating SpriteShape geometry.
  53. /// </summary>
  54. public enum Corner
  55. {
  56. /// <summary>No corners.</summary>
  57. Disable = 0,
  58. /// <summary>Automatically use respective corner sprite if 1) angle is within range 2) control point and neighbours are in linear tangent mode and their heights are same.</summary>
  59. Automatic = 1,
  60. /// <summary>The sprite at this control point is used to create a curved corner.</summary>
  61. Stretched = 2,
  62. }
  63. /// <summary>
  64. /// Spline control point that holds information for constructing the Bezier curve and SpriteShape geometry.
  65. /// </summary>
  66. [System.Serializable]
  67. public class SplineControlPoint
  68. {
  69. /// <summary>Position of control point.</summary>
  70. public Vector3 position;
  71. /// <summary>Left tangent of control point.</summary>
  72. public Vector3 leftTangent;
  73. /// <summary>Right tangent of control point.</summary>
  74. public Vector3 rightTangent;
  75. /// <summary>Tangent mode of control point.</summary>
  76. public ShapeTangentMode mode;
  77. /// <summary>Height of control point used when generating SpriteShape geometry.</summary>
  78. public float height = 1f;
  79. /// <summary>Bevel cutoff for control Point. </summary>
  80. public float bevelCutoff;
  81. /// <summary>Bevel size. </summary>
  82. public float bevelSize;
  83. /// <summary>Sprite index used for rendering at start of this control point along the edge. </summary>
  84. public int spriteIndex;
  85. /// <summary>Enable corners of control point.</summary>
  86. public bool corner;
  87. [SerializeField]
  88. Corner m_CornerMode;
  89. /// <summary>Corner mode of control point.</summary>
  90. public Corner cornerMode
  91. {
  92. get => m_CornerMode;
  93. set => m_CornerMode = value;
  94. }
  95. /// <summary>
  96. /// Get hash code for this Spline control point.
  97. /// </summary>
  98. /// <returns>Hash code as int.</returns>
  99. public override int GetHashCode()
  100. {
  101. return ((int)position.x).GetHashCode() ^ ((int)position.y).GetHashCode() ^ position.GetHashCode() ^
  102. (leftTangent.GetHashCode() << 2) ^ (rightTangent.GetHashCode() >> 2) ^ ((int)mode).GetHashCode() ^
  103. height.GetHashCode() ^ spriteIndex.GetHashCode() ^ corner.GetHashCode() ^ (m_CornerMode.GetHashCode() << 2);
  104. }
  105. }
  106. /// <summary>
  107. /// Angle Range defines constraints and list of sprites to be used to render edges of SpriteShape.
  108. /// </summary>
  109. [System.Serializable]
  110. public class AngleRange : ICloneable
  111. {
  112. /// <summary>Start angle of AngleRange.</summary>
  113. public float start
  114. {
  115. get { return m_Start; }
  116. set { m_Start = value; }
  117. }
  118. /// <summary>End angle of AngleRange. Angles cannot overlap with others.</summary>
  119. public float end
  120. {
  121. get { return m_End; }
  122. set { m_End = value; }
  123. }
  124. /// <summary>Render order for this AngleRange.</summary>
  125. public int order
  126. {
  127. get { return m_Order; }
  128. set { m_Order = value; }
  129. }
  130. /// <summary>List of sprites that are used to render the edge. The sprite index of control point can be used to select the one to be used for rendering.</summary>
  131. public List<Sprite> sprites
  132. {
  133. get { return m_Sprites; }
  134. set { m_Sprites = value; }
  135. }
  136. [SerializeField]
  137. float m_Start;
  138. [SerializeField]
  139. float m_End;
  140. [SerializeField]
  141. int m_Order;
  142. [SerializeField]
  143. List<Sprite> m_Sprites = new List<Sprite>();
  144. /// <summary>
  145. /// Clone object.
  146. /// </summary>
  147. /// <returns>Cloned Angle Range Object.</returns>
  148. public object Clone()
  149. {
  150. AngleRange clone = this.MemberwiseClone() as AngleRange;
  151. clone.sprites = new List<Sprite>(clone.sprites);
  152. return clone;
  153. }
  154. /// <summary>
  155. /// Test for Equality.
  156. /// </summary>
  157. /// <param name="obj">Object to test against.</param>
  158. /// <returns>True if Equal.</returns>
  159. public override bool Equals(object obj)
  160. {
  161. var other = obj as AngleRange;
  162. if (other == null)
  163. return false;
  164. bool equals = start.Equals(other.start) && end.Equals(other.end) && order.Equals(other.order);
  165. if (!equals)
  166. return false;
  167. if (sprites.Count != other.sprites.Count)
  168. return false;
  169. for (int i = 0; i < sprites.Count; ++i)
  170. if (sprites[i] != other.sprites[i])
  171. return false;
  172. return true;
  173. }
  174. /// <summary>
  175. /// Get hash code for this AngleRange.
  176. /// </summary>
  177. /// <returns>Hash code as int.</returns>
  178. public override int GetHashCode()
  179. {
  180. int hashCode = start.GetHashCode() ^ end.GetHashCode() ^ order.GetHashCode();
  181. if (sprites != null)
  182. {
  183. for (int i = 0; i < sprites.Count; i++)
  184. {
  185. Sprite sprite = sprites[i];
  186. if (sprite)
  187. hashCode = hashCode * 16777619 ^ (sprite.GetHashCode() + i);
  188. }
  189. }
  190. return hashCode;
  191. }
  192. }
  193. /// <summary>
  194. /// Corner Sprite used to specify corner type and associated sprites.
  195. /// </summary>
  196. [System.Serializable]
  197. public class CornerSprite : ICloneable
  198. {
  199. /// <summary>Type of corner. </summary>
  200. public CornerType cornerType
  201. {
  202. get { return m_CornerType; }
  203. set { m_CornerType = value; }
  204. }
  205. /// <summary>List of sprites associated with this corner. </summary>
  206. public List<Sprite> sprites
  207. {
  208. get { return m_Sprites; }
  209. set { m_Sprites = value; }
  210. }
  211. [SerializeField]
  212. CornerType m_CornerType; ///< Set Corner type. enum { OuterTopLeft = 0, OuterTopRight = 1, OuterBottomLeft = 2, OuterBottomRight = 3, InnerTopLeft = 4, InnerTopRight = 5, InnerBottomLeft = 6, InnerBottomRight = 7 }
  213. [SerializeField]
  214. List<Sprite> m_Sprites;
  215. /// <summary>
  216. /// Clone this object.
  217. /// </summary>
  218. /// <returns>A CornerSprite clone.</returns>
  219. public object Clone()
  220. {
  221. CornerSprite clone = this.MemberwiseClone() as CornerSprite;
  222. clone.sprites = new List<Sprite>(clone.sprites);
  223. return clone;
  224. }
  225. /// <summary>
  226. /// Test for Equality.
  227. /// </summary>
  228. /// <param name="obj">Object to test against</param>
  229. /// <returns>True if objects are equal.</returns>
  230. public override bool Equals(object obj)
  231. {
  232. var other = obj as CornerSprite;
  233. if (other == null)
  234. return false;
  235. if (!cornerType.Equals(other.cornerType))
  236. return false;
  237. if (sprites.Count != other.sprites.Count)
  238. return false;
  239. for (int i = 0; i < sprites.Count; ++i)
  240. if (sprites[i] != other.sprites[i])
  241. return false;
  242. return true;
  243. }
  244. /// <summary>
  245. /// Get hash code for this CornerSprite.
  246. /// </summary>
  247. /// <returns>Hash code as int.</returns>
  248. public override int GetHashCode()
  249. {
  250. int hashCode = cornerType.GetHashCode();
  251. if (sprites != null)
  252. {
  253. for (int i = 0; i < sprites.Count; i++)
  254. {
  255. Sprite sprite = sprites[i];
  256. if (sprite)
  257. {
  258. hashCode ^= (i + 1);
  259. hashCode ^= sprite.GetHashCode();
  260. }
  261. }
  262. }
  263. return hashCode;
  264. }
  265. }
  266. /// <summary>
  267. /// SpriteShape contains the parameters that define how SpriteShape geometry is generated from a Spline.
  268. /// </summary>
  269. [HelpURLAttribute("https://docs.unity3d.com/Packages/com.unity.2d.spriteshape@latest/index.html?subfolder=/manual/SSProfile.html")]
  270. public class SpriteShape : ScriptableObject
  271. {
  272. /// <summary>List of AngleRanges. </summary>
  273. public List<AngleRange> angleRanges
  274. {
  275. get { return m_Angles; }
  276. set { m_Angles = value; }
  277. }
  278. /// <summary>Fill Texture to be used for inner geometry in case of closed shapes. The Texture wrap mode should be set to Repeat. </summary>
  279. public Texture2D fillTexture
  280. {
  281. get { return m_FillTexture; }
  282. set { m_FillTexture = value; }
  283. }
  284. /// <summary>Sprites to be used for corners. </summary>
  285. public List<CornerSprite> cornerSprites
  286. {
  287. get { return m_CornerSprites; }
  288. set { m_CornerSprites = value; }
  289. }
  290. /// <summary>Fill offset for the closed shape. </summary>
  291. public float fillOffset
  292. {
  293. get { return m_FillOffset; }
  294. set { m_FillOffset = value; }
  295. }
  296. /// <summary>Use borders of sprites when generating edge geometry. </summary>
  297. public bool useSpriteBorders
  298. {
  299. get { return m_UseSpriteBorders; }
  300. set { m_UseSpriteBorders = value; }
  301. }
  302. [SerializeField]
  303. List<AngleRange> m_Angles = new List<AngleRange>();
  304. [SerializeField]
  305. Texture2D m_FillTexture;
  306. [SerializeField]
  307. List<CornerSprite> m_CornerSprites = new List<CornerSprite>();
  308. [SerializeField]
  309. float m_FillOffset;
  310. [SerializeField]
  311. bool m_UseSpriteBorders = true;
  312. #if UNITY_EDITOR
  313. internal static event Action<SpriteShape> onReset = null;
  314. #endif
  315. private CornerSprite GetCornerSprite(CornerType cornerType)
  316. {
  317. var cornerSprite = new CornerSprite();
  318. cornerSprite.cornerType = cornerType;
  319. cornerSprite.sprites = new List<Sprite>();
  320. cornerSprite.sprites.Insert(0, null);
  321. return cornerSprite;
  322. }
  323. void ResetCornerList()
  324. {
  325. m_CornerSprites.Clear();
  326. m_CornerSprites.Insert(0, GetCornerSprite(CornerType.OuterTopLeft));
  327. m_CornerSprites.Insert(1, GetCornerSprite(CornerType.OuterTopRight));
  328. m_CornerSprites.Insert(2, GetCornerSprite(CornerType.OuterBottomLeft));
  329. m_CornerSprites.Insert(3, GetCornerSprite(CornerType.OuterBottomRight));
  330. m_CornerSprites.Insert(4, GetCornerSprite(CornerType.InnerTopLeft));
  331. m_CornerSprites.Insert(5, GetCornerSprite(CornerType.InnerTopRight));
  332. m_CornerSprites.Insert(6, GetCornerSprite(CornerType.InnerBottomLeft));
  333. m_CornerSprites.Insert(7, GetCornerSprite(CornerType.InnerBottomRight));
  334. }
  335. void OnValidate()
  336. {
  337. if (m_CornerSprites.Count != 8)
  338. ResetCornerList();
  339. }
  340. void Reset()
  341. {
  342. m_Angles.Clear();
  343. ResetCornerList();
  344. #if UNITY_EDITOR
  345. onReset?.Invoke(this);
  346. #endif
  347. }
  348. internal static int GetSpriteShapeHashCode(SpriteShape spriteShape)
  349. {
  350. // useSpriteBorders, fillOffset and fillTexture are hashChecked elsewhere.
  351. unchecked
  352. {
  353. int hashCode = (int)2166136261;
  354. hashCode = hashCode * 16777619 ^ spriteShape.angleRanges.Count;
  355. for (int i = 0; i < spriteShape.angleRanges.Count; ++i)
  356. {
  357. hashCode = hashCode * 16777619 ^ (spriteShape.angleRanges[i].GetHashCode() + i);
  358. }
  359. hashCode = hashCode * 16777619 ^ spriteShape.cornerSprites.Count;
  360. for (int i = 0; i < spriteShape.cornerSprites.Count; ++i)
  361. {
  362. hashCode = hashCode * 16777619 ^ (spriteShape.cornerSprites[i].GetHashCode() + i);
  363. }
  364. return hashCode;
  365. }
  366. }
  367. }
  368. }