Brak opisu
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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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>Sprite index used for rendering at start of this control point along the edge. </summary>
  80. public int spriteIndex;
  81. /// <summary>Enable corners of control point.</summary>
  82. public bool corner;
  83. [SerializeField]
  84. Corner m_CornerMode;
  85. /// <summary>Corner mode of control point.</summary>
  86. public Corner cornerMode
  87. {
  88. get => m_CornerMode;
  89. set => m_CornerMode = value;
  90. }
  91. /// <summary>
  92. /// Get hash code for this Spline control point.
  93. /// </summary>
  94. /// <returns>Hash code as int.</returns>
  95. public override int GetHashCode()
  96. {
  97. return ((int)position.x).GetHashCode() ^ ((int)position.y).GetHashCode() ^ position.GetHashCode() ^
  98. (leftTangent.GetHashCode() << 2) ^ (rightTangent.GetHashCode() >> 2) ^ ((int)mode).GetHashCode() ^
  99. height.GetHashCode() ^ spriteIndex.GetHashCode() ^ corner.GetHashCode() ^ (m_CornerMode.GetHashCode() << 2);
  100. }
  101. }
  102. /// <summary>
  103. /// Angle Range defines constraints and list of sprites to be used to render edges of SpriteShape.
  104. /// </summary>
  105. [System.Serializable]
  106. public class AngleRange : ICloneable
  107. {
  108. /// <summary>Start angle of AngleRange.</summary>
  109. public float start
  110. {
  111. get { return m_Start; }
  112. set { m_Start = value; }
  113. }
  114. /// <summary>End angle of AngleRange. Angles cannot overlap with others.</summary>
  115. public float end
  116. {
  117. get { return m_End; }
  118. set { m_End = value; }
  119. }
  120. /// <summary>Render order for this AngleRange.</summary>
  121. public int order
  122. {
  123. get { return m_Order; }
  124. set { m_Order = value; }
  125. }
  126. /// <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>
  127. public List<Sprite> sprites
  128. {
  129. get { return m_Sprites; }
  130. set { m_Sprites = value; }
  131. }
  132. [SerializeField]
  133. float m_Start;
  134. [SerializeField]
  135. float m_End;
  136. [SerializeField]
  137. int m_Order;
  138. [SerializeField]
  139. List<Sprite> m_Sprites = new List<Sprite>();
  140. /// <summary>
  141. /// Clone object.
  142. /// </summary>
  143. /// <returns>Cloned Angle Range Object.</returns>
  144. public object Clone()
  145. {
  146. AngleRange clone = this.MemberwiseClone() as AngleRange;
  147. clone.sprites = new List<Sprite>(clone.sprites);
  148. return clone;
  149. }
  150. /// <summary>
  151. /// Test for Equality.
  152. /// </summary>
  153. /// <param name="obj">Object to test against.</param>
  154. /// <returns>True if Equal.</returns>
  155. public override bool Equals(object obj)
  156. {
  157. var other = obj as AngleRange;
  158. if (other == null)
  159. return false;
  160. bool equals = start.Equals(other.start) && end.Equals(other.end) && order.Equals(other.order);
  161. if (!equals)
  162. return false;
  163. if (sprites.Count != other.sprites.Count)
  164. return false;
  165. for (int i = 0; i < sprites.Count; ++i)
  166. if (sprites[i] != other.sprites[i])
  167. return false;
  168. return true;
  169. }
  170. /// <summary>
  171. /// Get hash code for this AngleRange.
  172. /// </summary>
  173. /// <returns>Hash code as int.</returns>
  174. public override int GetHashCode()
  175. {
  176. int hashCode = start.GetHashCode() ^ end.GetHashCode() ^ order.GetHashCode();
  177. if (sprites != null)
  178. {
  179. for (int i = 0; i < sprites.Count; i++)
  180. {
  181. Sprite sprite = sprites[i];
  182. if (sprite)
  183. hashCode = hashCode * 16777619 ^ (sprite.GetHashCode() + i);
  184. }
  185. }
  186. return hashCode;
  187. }
  188. }
  189. /// <summary>
  190. /// Corner Sprite used to specify corner type and associated sprites.
  191. /// </summary>
  192. [System.Serializable]
  193. public class CornerSprite : ICloneable
  194. {
  195. /// <summary>Type of corner. </summary>
  196. public CornerType cornerType
  197. {
  198. get { return m_CornerType; }
  199. set { m_CornerType = value; }
  200. }
  201. /// <summary>List of sprites associated with this corner. </summary>
  202. public List<Sprite> sprites
  203. {
  204. get { return m_Sprites; }
  205. set { m_Sprites = value; }
  206. }
  207. [SerializeField]
  208. CornerType m_CornerType; ///< Set Corner type. enum { OuterTopLeft = 0, OuterTopRight = 1, OuterBottomLeft = 2, OuterBottomRight = 3, InnerTopLeft = 4, InnerTopRight = 5, InnerBottomLeft = 6, InnerBottomRight = 7 }
  209. [SerializeField]
  210. List<Sprite> m_Sprites;
  211. /// <summary>
  212. /// Clone this object.
  213. /// </summary>
  214. /// <returns>A CornerSprite clone.</returns>
  215. public object Clone()
  216. {
  217. CornerSprite clone = this.MemberwiseClone() as CornerSprite;
  218. clone.sprites = new List<Sprite>(clone.sprites);
  219. return clone;
  220. }
  221. /// <summary>
  222. /// Test for Equality.
  223. /// </summary>
  224. /// <param name="obj">Object to test against</param>
  225. /// <returns>True if objects are equal.</returns>
  226. public override bool Equals(object obj)
  227. {
  228. var other = obj as CornerSprite;
  229. if (other == null)
  230. return false;
  231. if (!cornerType.Equals(other.cornerType))
  232. return false;
  233. if (sprites.Count != other.sprites.Count)
  234. return false;
  235. for (int i = 0; i < sprites.Count; ++i)
  236. if (sprites[i] != other.sprites[i])
  237. return false;
  238. return true;
  239. }
  240. /// <summary>
  241. /// Get hash code for this CornerSprite.
  242. /// </summary>
  243. /// <returns>Hash code as int.</returns>
  244. public override int GetHashCode()
  245. {
  246. int hashCode = cornerType.GetHashCode();
  247. if (sprites != null)
  248. {
  249. for (int i = 0; i < sprites.Count; i++)
  250. {
  251. Sprite sprite = sprites[i];
  252. if (sprite)
  253. {
  254. hashCode ^= (i + 1);
  255. hashCode ^= sprite.GetHashCode();
  256. }
  257. }
  258. }
  259. return hashCode;
  260. }
  261. }
  262. /// <summary>
  263. /// SpriteShape contains the parameters that define how SpriteShape geometry is generated from a Spline.
  264. /// </summary>
  265. [HelpURLAttribute("https://docs.unity3d.com/Packages/com.unity.2d.spriteshape@latest/index.html?subfolder=/manual/SSProfile.html")]
  266. public class SpriteShape : ScriptableObject
  267. {
  268. /// <summary>List of AngleRanges. </summary>
  269. public List<AngleRange> angleRanges
  270. {
  271. get { return m_Angles; }
  272. set { m_Angles = value; }
  273. }
  274. /// <summary>Fill Texture to be used for inner geometry in case of closed shapes. The Texture wrap mode should be set to Repeat. </summary>
  275. public Texture2D fillTexture
  276. {
  277. get { return m_FillTexture; }
  278. set { m_FillTexture = value; }
  279. }
  280. /// <summary>Sprites to be used for corners. </summary>
  281. public List<CornerSprite> cornerSprites
  282. {
  283. get { return m_CornerSprites; }
  284. set { m_CornerSprites = value; }
  285. }
  286. /// <summary>Fill offset for the closed shape. </summary>
  287. public float fillOffset
  288. {
  289. get { return m_FillOffset; }
  290. set { m_FillOffset = value; }
  291. }
  292. /// <summary>Use borders of sprites when generating edge geometry. </summary>
  293. public bool useSpriteBorders
  294. {
  295. get { return m_UseSpriteBorders; }
  296. set { m_UseSpriteBorders = value; }
  297. }
  298. [SerializeField]
  299. List<AngleRange> m_Angles = new List<AngleRange>();
  300. [SerializeField]
  301. Texture2D m_FillTexture;
  302. [SerializeField]
  303. List<CornerSprite> m_CornerSprites = new List<CornerSprite>();
  304. [SerializeField]
  305. float m_FillOffset;
  306. [SerializeField]
  307. bool m_UseSpriteBorders = true;
  308. #if UNITY_EDITOR
  309. internal static event Action<SpriteShape> onReset = null;
  310. #endif
  311. private CornerSprite GetCornerSprite(CornerType cornerType)
  312. {
  313. var cornerSprite = new CornerSprite();
  314. cornerSprite.cornerType = cornerType;
  315. cornerSprite.sprites = new List<Sprite>();
  316. cornerSprite.sprites.Insert(0, null);
  317. return cornerSprite;
  318. }
  319. void ResetCornerList()
  320. {
  321. m_CornerSprites.Clear();
  322. m_CornerSprites.Insert(0, GetCornerSprite(CornerType.OuterTopLeft));
  323. m_CornerSprites.Insert(1, GetCornerSprite(CornerType.OuterTopRight));
  324. m_CornerSprites.Insert(2, GetCornerSprite(CornerType.OuterBottomLeft));
  325. m_CornerSprites.Insert(3, GetCornerSprite(CornerType.OuterBottomRight));
  326. m_CornerSprites.Insert(4, GetCornerSprite(CornerType.InnerTopLeft));
  327. m_CornerSprites.Insert(5, GetCornerSprite(CornerType.InnerTopRight));
  328. m_CornerSprites.Insert(6, GetCornerSprite(CornerType.InnerBottomLeft));
  329. m_CornerSprites.Insert(7, GetCornerSprite(CornerType.InnerBottomRight));
  330. }
  331. void OnValidate()
  332. {
  333. if (m_CornerSprites.Count != 8)
  334. ResetCornerList();
  335. }
  336. void Reset()
  337. {
  338. m_Angles.Clear();
  339. ResetCornerList();
  340. #if UNITY_EDITOR
  341. onReset?.Invoke(this);
  342. #endif
  343. }
  344. internal static int GetSpriteShapeHashCode(SpriteShape spriteShape)
  345. {
  346. // useSpriteBorders, fillOffset and fillTexture are hashChecked elsewhere.
  347. unchecked
  348. {
  349. int hashCode = (int)2166136261;
  350. hashCode = hashCode * 16777619 ^ spriteShape.angleRanges.Count;
  351. for (int i = 0; i < spriteShape.angleRanges.Count; ++i)
  352. {
  353. hashCode = hashCode * 16777619 ^ (spriteShape.angleRanges[i].GetHashCode() + i);
  354. }
  355. hashCode = hashCode * 16777619 ^ spriteShape.cornerSprites.Count;
  356. for (int i = 0; i < spriteShape.cornerSprites.Count; ++i)
  357. {
  358. hashCode = hashCode * 16777619 ^ (spriteShape.cornerSprites[i].GetHashCode() + i);
  359. }
  360. return hashCode;
  361. }
  362. }
  363. }
  364. }