Geen omschrijving
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.

RuleTile.cs 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Tilemaps;
  4. namespace UnityEngine
  5. {
  6. [Serializable]
  7. [CreateAssetMenu]
  8. public class RuleTile : TileBase
  9. {
  10. public Sprite m_DefaultSprite;
  11. public Tile.ColliderType m_DefaultColliderType = Tile.ColliderType.Sprite;
  12. [Serializable]
  13. public class TilingRule
  14. {
  15. public Neighbor[] m_Neighbors;
  16. public Sprite[] m_Sprites;
  17. public float m_AnimationSpeed;
  18. public float m_PerlinScale;
  19. public Transform m_RuleTransform;
  20. public OutputSprite m_Output;
  21. public Tile.ColliderType m_ColliderType;
  22. public Transform m_RandomTransform;
  23. public TilingRule()
  24. {
  25. m_Output = OutputSprite.Single;
  26. m_Neighbors = new Neighbor[8];
  27. m_Sprites = new Sprite[1];
  28. m_AnimationSpeed = 1f;
  29. m_PerlinScale = 0.5f;
  30. m_ColliderType = Tile.ColliderType.Sprite;
  31. for(int i=0; i<m_Neighbors.Length; i++)
  32. m_Neighbors[i] = Neighbor.DontCare;
  33. }
  34. public enum Transform { Fixed, Rotated, MirrorX, MirrorY }
  35. public enum Neighbor { DontCare, This, NotThis }
  36. public enum OutputSprite { Single, Random, Animation }
  37. }
  38. [HideInInspector] public List<TilingRule> m_TilingRules;
  39. public override void GetTileData(Vector3Int position, ITilemap tileMap, ref TileData tileData)
  40. {
  41. tileData.sprite = m_DefaultSprite;
  42. tileData.colliderType = m_DefaultColliderType;
  43. tileData.flags = TileFlags.LockTransform;
  44. tileData.transform = Matrix4x4.identity;
  45. foreach (TilingRule rule in m_TilingRules)
  46. {
  47. Matrix4x4 transform = Matrix4x4.identity;
  48. if (RuleMatches(rule, position, tileMap, ref transform))
  49. {
  50. switch (rule.m_Output)
  51. {
  52. case TilingRule.OutputSprite.Single:
  53. case TilingRule.OutputSprite.Animation:
  54. tileData.sprite = rule.m_Sprites[0];
  55. break;
  56. case TilingRule.OutputSprite.Random:
  57. int index = Mathf.Clamp(Mathf.FloorToInt(GetPerlinValue(position, rule.m_PerlinScale, 100000f) * rule.m_Sprites.Length), 0, rule.m_Sprites.Length - 1);
  58. tileData.sprite = rule.m_Sprites[index];
  59. if (rule.m_RandomTransform != TilingRule.Transform.Fixed)
  60. transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
  61. break;
  62. }
  63. tileData.transform = transform;
  64. tileData.colliderType = rule.m_ColliderType;
  65. break;
  66. }
  67. }
  68. }
  69. private static float GetPerlinValue(Vector3Int position, float scale, float offset)
  70. {
  71. return Mathf.PerlinNoise((position.x + offset) * scale, (position.y + offset) * scale);
  72. }
  73. public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
  74. {
  75. foreach (TilingRule rule in m_TilingRules)
  76. {
  77. Matrix4x4 transform = Matrix4x4.identity;
  78. if (RuleMatches(rule, position, tilemap, ref transform) && rule.m_Output == TilingRule.OutputSprite.Animation)
  79. {
  80. tileAnimationData.animatedSprites = rule.m_Sprites;
  81. tileAnimationData.animationSpeed = rule.m_AnimationSpeed;
  82. return true;
  83. }
  84. }
  85. return false;
  86. }
  87. public override void RefreshTile(Vector3Int location, ITilemap tileMap)
  88. {
  89. if (m_TilingRules != null && m_TilingRules.Count > 0)
  90. {
  91. for (int y = -1; y <= 1; y++)
  92. {
  93. for (int x = -1; x <= 1; x++)
  94. {
  95. base.RefreshTile(location + new Vector3Int(x, y, 0), tileMap);
  96. }
  97. }
  98. }
  99. else
  100. {
  101. base.RefreshTile(location, tileMap);
  102. }
  103. }
  104. public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, ref Matrix4x4 transform)
  105. {
  106. // Check rule against rotations of 0, 90, 180, 270
  107. for (int angle = 0; angle <= (rule.m_RuleTransform == TilingRule.Transform.Rotated ? 270 : 0); angle += 90)
  108. {
  109. if (RuleMatches(rule, position, tilemap, angle))
  110. {
  111. transform = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
  112. return true;
  113. }
  114. }
  115. // Check rule against x-axis mirror
  116. if ((rule.m_RuleTransform == TilingRule.Transform.MirrorX) && RuleMatches(rule, position, tilemap, true, false))
  117. {
  118. transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f));
  119. return true;
  120. }
  121. // Check rule against y-axis mirror
  122. if ((rule.m_RuleTransform == TilingRule.Transform.MirrorY) && RuleMatches(rule, position, tilemap, false, true))
  123. {
  124. transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
  125. return true;
  126. }
  127. return false;
  128. }
  129. private static Matrix4x4 ApplyRandomTransform(TilingRule.Transform type, Matrix4x4 original, float perlinScale, Vector3Int position)
  130. {
  131. float perlin = GetPerlinValue(position, perlinScale, 200000f);
  132. switch (type)
  133. {
  134. case TilingRule.Transform.MirrorX:
  135. return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(perlin < 0.5 ? 1f : -1f, 1f, 1f));
  136. case TilingRule.Transform.MirrorY:
  137. return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, perlin < 0.5 ? 1f : -1f, 1f));
  138. case TilingRule.Transform.Rotated:
  139. int angle = Mathf.Clamp(Mathf.FloorToInt(perlin * 4), 0, 3) * 90;
  140. return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
  141. }
  142. return original;
  143. }
  144. public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, int angle)
  145. {
  146. for (int y = -1; y <= 1; y++)
  147. {
  148. for (int x = -1; x <= 1; x++)
  149. {
  150. if (x != 0 || y != 0)
  151. {
  152. Vector3Int offset = new Vector3Int(x, y, 0);
  153. Vector3Int rotated = GetRotatedPos(offset, angle);
  154. int index = GetIndexOfOffset(rotated);
  155. TileBase tile = tilemap.GetTile(position + offset);
  156. if (rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this || rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && tile == this)
  157. {
  158. return false;
  159. }
  160. }
  161. }
  162. }
  163. return true;
  164. }
  165. public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, bool mirrorX, bool mirrorY)
  166. {
  167. for (int y = -1; y <= 1; y++)
  168. {
  169. for (int x = -1; x <= 1; x++)
  170. {
  171. if (x != 0 || y != 0)
  172. {
  173. Vector3Int offset = new Vector3Int(x, y, 0);
  174. Vector3Int mirrored = GetMirroredPos(offset, mirrorX, mirrorY);
  175. int index = GetIndexOfOffset(mirrored);
  176. TileBase tile = tilemap.GetTile(position + offset);
  177. if (rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this || rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && tile == this)
  178. {
  179. return false;
  180. }
  181. }
  182. }
  183. }
  184. return true;
  185. }
  186. private int GetIndexOfOffset(Vector3Int offset)
  187. {
  188. int result = offset.x + 1 + (-offset.y + 1) * 3;
  189. if (result >= 4)
  190. result--;
  191. return result;
  192. }
  193. public Vector3Int GetRotatedPos(Vector3Int original, int rotation)
  194. {
  195. switch (rotation)
  196. {
  197. case 0:
  198. return original;
  199. case 90:
  200. return new Vector3Int(-original.y, original.x, original.z);
  201. case 180:
  202. return new Vector3Int(-original.x, -original.y, original.z);
  203. case 270:
  204. return new Vector3Int(original.y, -original.x, original.z);
  205. }
  206. return original;
  207. }
  208. public Vector3Int GetMirroredPos(Vector3Int original, bool mirrorX, bool mirrorY)
  209. {
  210. return new Vector3Int(original.x * (mirrorX ? -1 : 1), original.y * (mirrorY ? -1 : 1), original.z);
  211. }
  212. }
  213. }