Created
June 22, 2018 19:34
-
-
Save Alexander-van-der-Zalm/aa2d2f12f60c71eaf462d8126505e54a to your computer and use it in GitHub Desktop.
Extends the ruletile so that it distinguishes between this, not this, empty and dont care.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using UnityEngine.Tilemaps; | |
| namespace UnityEngine | |
| { | |
| [Serializable] | |
| [CreateAssetMenu] | |
| public class RuleTile : TileBase | |
| { | |
| public Sprite m_DefaultSprite; | |
| public Tile.ColliderType m_DefaultColliderType = Tile.ColliderType.Sprite; | |
| [Serializable] | |
| public class TilingRule | |
| { | |
| public Neighbor[] m_Neighbors; | |
| public Sprite[] m_Sprites; | |
| public float m_AnimationSpeed; | |
| public float m_PerlinScale; | |
| public Transform m_RuleTransform; | |
| public OutputSprite m_Output; | |
| public Tile.ColliderType m_ColliderType; | |
| public Transform m_RandomTransform; | |
| public TilingRule() | |
| { | |
| m_Output = OutputSprite.Single; | |
| m_Neighbors = new Neighbor[8]; | |
| m_Sprites = new Sprite[1]; | |
| m_AnimationSpeed = 1f; | |
| m_PerlinScale = 0.5f; | |
| m_ColliderType = Tile.ColliderType.Sprite; | |
| for(int i=0; i<m_Neighbors.Length; i++) | |
| m_Neighbors[i] = Neighbor.DontCare; | |
| } | |
| public enum Transform { Fixed, Rotated, MirrorX, MirrorY } | |
| public enum Neighbor { DontCare, This, NotThis, Empty } | |
| public enum OutputSprite { Single, Random, Animation } | |
| } | |
| [HideInInspector] public List<TilingRule> m_TilingRules; | |
| public override void GetTileData(Vector3Int position, ITilemap tileMap, ref TileData tileData) | |
| { | |
| tileData.sprite = m_DefaultSprite; | |
| tileData.colliderType = m_DefaultColliderType; | |
| tileData.flags = TileFlags.LockTransform; | |
| tileData.transform = Matrix4x4.identity; | |
| foreach (TilingRule rule in m_TilingRules) | |
| { | |
| Matrix4x4 transform = Matrix4x4.identity; | |
| if (RuleMatches(rule, position, tileMap, ref transform)) | |
| { | |
| switch (rule.m_Output) | |
| { | |
| case TilingRule.OutputSprite.Single: | |
| case TilingRule.OutputSprite.Animation: | |
| tileData.sprite = rule.m_Sprites[0]; | |
| break; | |
| case TilingRule.OutputSprite.Random: | |
| int index = Mathf.Clamp(Mathf.FloorToInt(GetPerlinValue(position, rule.m_PerlinScale, 100000f) * rule.m_Sprites.Length), 0, rule.m_Sprites.Length - 1); | |
| tileData.sprite = rule.m_Sprites[index]; | |
| if (rule.m_RandomTransform != TilingRule.Transform.Fixed) | |
| transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position); | |
| break; | |
| } | |
| tileData.transform = transform; | |
| tileData.colliderType = rule.m_ColliderType; | |
| break; | |
| } | |
| } | |
| } | |
| private static float GetPerlinValue(Vector3Int position, float scale, float offset) | |
| { | |
| return Mathf.PerlinNoise((position.x + offset) * scale, (position.y + offset) * scale); | |
| } | |
| public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData) | |
| { | |
| foreach (TilingRule rule in m_TilingRules) | |
| { | |
| Matrix4x4 transform = Matrix4x4.identity; | |
| if (RuleMatches(rule, position, tilemap, ref transform) && rule.m_Output == TilingRule.OutputSprite.Animation) | |
| { | |
| tileAnimationData.animatedSprites = rule.m_Sprites; | |
| tileAnimationData.animationSpeed = rule.m_AnimationSpeed; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| public override void RefreshTile(Vector3Int location, ITilemap tileMap) | |
| { | |
| if (m_TilingRules != null && m_TilingRules.Count > 0) | |
| { | |
| for (int y = -1; y <= 1; y++) | |
| { | |
| for (int x = -1; x <= 1; x++) | |
| { | |
| base.RefreshTile(location + new Vector3Int(x, y, 0), tileMap); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| base.RefreshTile(location, tileMap); | |
| } | |
| } | |
| public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, ref Matrix4x4 transform) | |
| { | |
| // Check rule against rotations of 0, 90, 180, 270 | |
| for (int angle = 0; angle <= (rule.m_RuleTransform == TilingRule.Transform.Rotated ? 270 : 0); angle += 90) | |
| { | |
| if (RuleMatches(rule, position, tilemap, angle)) | |
| { | |
| transform = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one); | |
| return true; | |
| } | |
| } | |
| // Check rule against x-axis mirror | |
| if ((rule.m_RuleTransform == TilingRule.Transform.MirrorX) && RuleMatches(rule, position, tilemap, true, false)) | |
| { | |
| transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f)); | |
| return true; | |
| } | |
| // Check rule against y-axis mirror | |
| if ((rule.m_RuleTransform == TilingRule.Transform.MirrorY) && RuleMatches(rule, position, tilemap, false, true)) | |
| { | |
| transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f)); | |
| return true; | |
| } | |
| return false; | |
| } | |
| private static Matrix4x4 ApplyRandomTransform(TilingRule.Transform type, Matrix4x4 original, float perlinScale, Vector3Int position) | |
| { | |
| float perlin = GetPerlinValue(position, perlinScale, 200000f); | |
| switch (type) | |
| { | |
| case TilingRule.Transform.MirrorX: | |
| return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(perlin < 0.5 ? 1f : -1f, 1f, 1f)); | |
| case TilingRule.Transform.MirrorY: | |
| return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, perlin < 0.5 ? 1f : -1f, 1f)); | |
| case TilingRule.Transform.Rotated: | |
| int angle = Mathf.Clamp(Mathf.FloorToInt(perlin * 4), 0, 3) * 90; | |
| return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one); | |
| } | |
| return original; | |
| } | |
| public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, int angle) | |
| { | |
| for (int y = -1; y <= 1; y++) | |
| { | |
| for (int x = -1; x <= 1; x++) | |
| { | |
| if (x != 0 || y != 0) | |
| { | |
| Vector3Int offset = new Vector3Int(x, y, 0); | |
| Vector3Int rotated = GetRotatedPos(offset, angle); | |
| int index = GetIndexOfOffset(rotated); | |
| TileBase tile = tilemap.GetTile(position + offset); | |
| if (RuleBroken(rule,index,tile)) | |
| { | |
| return false; | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, bool mirrorX, bool mirrorY) | |
| { | |
| for (int y = -1; y <= 1; y++) | |
| { | |
| for (int x = -1; x <= 1; x++) | |
| { | |
| if (x != 0 || y != 0) | |
| { | |
| Vector3Int offset = new Vector3Int(x, y, 0); | |
| Vector3Int mirrored = GetMirroredPos(offset, mirrorX, mirrorY); | |
| int index = GetIndexOfOffset(mirrored); | |
| TileBase tile = tilemap.GetTile(position + offset); | |
| if (RuleBroken(rule,index,tile)) | |
| { | |
| return false; | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| private bool OldRuleCheck(TilingRule rule, int index, TileBase tile) | |
| { | |
| return rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this || rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && tile == this; | |
| } | |
| // When this returns true, that means that the rule does not match | |
| // IE this is testing if any of the rules are broken | |
| // If the rule matches that means that the sprite associated to the rule will be the new main sprite | |
| // These are the rules which are being checked if they are broken | |
| // This - should only be triggered for the same tile type, | |
| // which is not the case when the tile is not this | |
| // NotThis - should only be triggered for another tile, which is not empty | |
| // IE broken when it is this or null(empty) | |
| // Empty - should only be triggered when there is no tile | |
| // IE broken when it is this or not null(empty) | |
| private bool RuleBroken(TilingRule rule, int index, TileBase tile) | |
| { | |
| return (rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this) | |
| || (rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && (tile == this || tile == null)) | |
| || (rule.m_Neighbors[index] == TilingRule.Neighbor.Empty && (tile == this || tile != null)) | |
| ; | |
| } | |
| private int GetIndexOfOffset(Vector3Int offset) | |
| { | |
| int result = offset.x + 1 + (-offset.y + 1) * 3; | |
| if (result >= 4) | |
| result--; | |
| return result; | |
| } | |
| public Vector3Int GetRotatedPos(Vector3Int original, int rotation) | |
| { | |
| switch (rotation) | |
| { | |
| case 0: | |
| return original; | |
| case 90: | |
| return new Vector3Int(-original.y, original.x, original.z); | |
| case 180: | |
| return new Vector3Int(-original.x, -original.y, original.z); | |
| case 270: | |
| return new Vector3Int(original.y, -original.x, original.z); | |
| } | |
| return original; | |
| } | |
| public Vector3Int GetMirroredPos(Vector3Int original, bool mirrorX, bool mirrorY) | |
| { | |
| return new Vector3Int(original.x * (mirrorX ? -1 : 1), original.y * (mirrorY ? -1 : 1), original.z); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Reflection; | |
| using UnityEditor.Sprites; | |
| using UnityEditorInternal; | |
| using UnityEngine; | |
| using UnityEngine.Networking; | |
| using UnityEngine.Tilemaps; | |
| using Object = UnityEngine.Object; | |
| namespace UnityEditor | |
| { | |
| [CustomEditor(typeof(RuleTile))] | |
| [CanEditMultipleObjects] | |
| internal class RuleTileEditor : Editor | |
| { | |
| private const string s_XIconString = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABoSURBVDhPnY3BDcAgDAOZhS14dP1O0x2C/LBEgiNSHvfwyZabmV0jZRUpq2zi6f0DJwdcQOEdwwDLypF0zHLMa9+NQRxkQ+ACOT2STVw/q8eY1346ZlE54sYAhVhSDrjwFymrSFnD2gTZpls2OvFUHAAAAABJRU5ErkJggg=="; | |
| private const string s_Arrow0 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACYSURBVDhPzZExDoQwDATzE4oU4QXXcgUFj+YxtETwgpMwXuFcwMFSRMVKKwzZcWzhiMg91jtg34XIntkre5EaT7yjjhI9pOD5Mw5k2X/DdUwFr3cQ7Pu23E/BiwXyWSOxrNqx+ewnsayam5OLBtbOGPUM/r93YZL4/dhpR/amwByGFBz170gNChA6w5bQQMqramBTgJ+Z3A58WuWejPCaHQAAAABJRU5ErkJggg=="; | |
| private const string s_Arrow1 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABqSURBVDhPxYzBDYAgEATpxYcd+PVr0fZ2siZrjmMhFz6STIiDs8XMlpEyi5RkO/d66TcgJUB43JfNBqRkSEYDnYjhbKD5GIUkDqRDwoH3+NgTAw+bL/aoOP4DOgH+iwECEt+IlFmkzGHlAYKAWF9R8zUnAAAAAElFTkSuQmCC"; | |
| private const string s_Arrow2 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAAC0SURBVDhPjVE5EsIwDMxPKFKYF9CagoJH8xhaMskLmEGsjOSRkBzYmU2s9a58TUQUmCH1BWEHweuKP+D8tphrWcAHuIGrjPnPNY8X2+DzEWE+FzrdrkNyg2YGNNfRGlyOaZDJOxBrDhgOowaYW8UW0Vau5ZkFmXbbDr+CzOHKmLinAXMEePyZ9dZkZR+s5QX2O8DY3zZ/sgYcdDqeEVp8516o0QQV1qeMwg6C91toYoLoo+kNt/tpKQEVvFQAAAAASUVORK5CYII="; | |
| private const string s_Arrow3 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAAB2SURBVDhPzY1LCoAwEEPnLi48gW5d6p31bH5SMhp0Cq0g+CCLxrzRPqMZ2pRqKG4IqzJc7JepTlbRZXYpWTg4RZE1XAso8VHFKNhQuTjKtZvHUNCEMogO4K3BhvMn9wP4EzoPZ3n0AGTW5fiBVzLAAYTP32C2Ay3agtu9V/9PAAAAAElFTkSuQmCC"; | |
| private const string s_Arrow5 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABqSURBVDhPnY3BCYBADASvFx924NevRdvbyoLBmNuDJQMDGjNxAFhK1DyUQ9fvobCdO+j7+sOKj/uSB+xYHZAxl7IR1wNTXJeVcaAVU+614uWfCT9mVUhknMlxDokd15BYsQrJFHeUQ0+MB5ErsPi/6hO1AAAAAElFTkSuQmCC"; | |
| private const string s_Arrow6 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACaSURBVDhPxZExEkAwEEVzE4UiTqClUDi0w2hlOIEZsV82xCZmQuPPfFn8t1mirLWf7S5flQOXjd64vCuEKWTKVt+6AayH3tIa7yLg6Qh2FcKFB72jBgJeziA1CMHzeaNHjkfwnAK86f3KUafU2ClHIJSzs/8HHLv09M3SaMCxS7ljw/IYJWzQABOQZ66x4h614ahTCL/WT7BSO51b5Z5hSx88AAAAAElFTkSuQmCC"; | |
| private const string s_Arrow7 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABQSURBVDhPYxh8QNle/T8U/4MKEQdAmsz2eICx6W530gygr2aQBmSMphkZYxqErAEXxusKfAYQ7XyyNMIAsgEkaYQBkAFkaYQBsjXSGDAwAAD193z4luKPrAAAAABJRU5ErkJggg=="; | |
| private const string s_Arrow8 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACYSURBVDhPxZE9DoAwCIW9iUOHegJXHRw8tIdx1egJTMSHAeMPaHSR5KVQ+KCkCRF91mdz4VDEWVzXTBgg5U1N5wahjHzXS3iFFVRxAygNVaZxJ6VHGIl2D6oUXP0ijlJuTp724FnID1Lq7uw2QM5+thoKth0N+GGyA7IA3+yM77Ag1e2zkey5gCdAg/h8csy+/89v7E+YkgUntOWeVt2SfAAAAABJRU5ErkJggg=="; | |
| private const string s_MirrorX = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAG1JREFUOE+lj9ENwCAIRB2IFdyRfRiuDSaXAF4MrR9P5eRhHGb2Gxp2oaEjIovTXSrAnPNx6hlgyCZ7o6omOdYOldGIZhAziEmOTSfigLV0RYAB9y9f/7kO8L3WUaQyhCgz0dmCL9CwCw172HgBeyG6oloC8fAAAAAASUVORK5CYII="; | |
| private const string s_MirrorY = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAG9JREFUOE+djckNACEMAykoLdAjHbPyw1IOJ0L7mAejjFlm9hspyd77Kk+kBAjPOXcakJIh6QaKyOE0EB5dSPJAiUmOiL8PMVGxugsP/0OOib8vsY8yYwy6gRyC8CB5QIWgCMKBLgRSkikEUr5h6wOPWfMoCYILdgAAAABJRU5ErkJggg=="; | |
| private const string s_Rotated = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAHdJREFUOE+djssNwCAMQxmIFdgx+2S4Vj4YxWlQgcOT8nuG5u5C732Sd3lfLlmPMR4QhXgrTQaimUlA3EtD+CJlBuQ7aUAUMjEAv9gWCQNEPhHJUkYfZ1kEpcxDzioRzGIlr0Qwi0r+Q5rTgM+AAVcygHgt7+HtBZs/2QVWP8ahAAAAAElFTkSuQmCC"; | |
| private const string s_OtherTile = "R0lGODlhDwAPAJEAAE1NTUxMTP///wAAACH5BAAAAAAALAAAAAAPAA8AAAIjjI8Zwu1tnmTxLXtdhpvKqn2XclCdcIKQ+LGWO2nnRB5AUgAAOw=="; | |
| private const string s_Empty = "R0lGODlhDwAPAPcAAHd5dnd5eHh4dnh4eP3+/v7+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAADwAPAAAITwAHCBQAQCAAAQMFKBxAoIDDhxAdIoxIUaKAihQJPmyIcSJGiBMbcnQ4soBChwIDBFDI0mKBkiRBDoi5MeLJjw9v4jR5cSdPnzxZCh2qMCAAOw=="; | |
| private static Texture2D[] s_Arrows; | |
| public static Texture2D[] arrows | |
| { | |
| get | |
| { | |
| if (s_Arrows == null) | |
| { | |
| s_Arrows = new Texture2D[12]; | |
| s_Arrows[0] = Base64ToTexture(s_Arrow0); | |
| s_Arrows[1] = Base64ToTexture(s_Arrow1); | |
| s_Arrows[2] = Base64ToTexture(s_Arrow2); | |
| s_Arrows[3] = Base64ToTexture(s_Arrow3); | |
| s_Arrows[5] = Base64ToTexture(s_Arrow5); | |
| s_Arrows[6] = Base64ToTexture(s_Arrow6); | |
| s_Arrows[7] = Base64ToTexture(s_Arrow7); | |
| s_Arrows[8] = Base64ToTexture(s_Arrow8); | |
| s_Arrows[9] = Base64ToTexture(s_XIconString); | |
| s_Arrows[10] = Base64ToTexture(s_OtherTile); | |
| s_Arrows[11] = Base64ToTexture(s_Empty); | |
| } | |
| return s_Arrows; | |
| } | |
| } | |
| private static Texture2D[] s_AutoTransforms; | |
| public static Texture2D[] autoTransforms | |
| { | |
| get | |
| { | |
| if (s_AutoTransforms == null) | |
| { | |
| s_AutoTransforms = new Texture2D[3]; | |
| s_AutoTransforms[0] = Base64ToTexture(s_Rotated); | |
| s_AutoTransforms[1] = Base64ToTexture(s_MirrorX); | |
| s_AutoTransforms[2] = Base64ToTexture(s_MirrorY); | |
| } | |
| return s_AutoTransforms; | |
| } | |
| } | |
| private ReorderableList m_ReorderableList; | |
| public RuleTile tile { get { return (target as RuleTile); } } | |
| private Rect m_ListRect; | |
| const float k_DefaultElementHeight = 48f; | |
| const float k_PaddingBetweenRules = 13f; | |
| const float k_SingleLineHeight = 16f; | |
| const float k_LabelWidth = 53f; | |
| private int m_previewsPerRow = 0; | |
| public void OnEnable() | |
| { | |
| if (tile.m_TilingRules == null) | |
| tile.m_TilingRules = new List<RuleTile.TilingRule>(); | |
| m_ReorderableList = new ReorderableList(tile.m_TilingRules, typeof(RuleTile.TilingRule), true, true, true, true); | |
| m_ReorderableList.drawHeaderCallback = OnDrawHeader; | |
| m_ReorderableList.drawElementCallback = OnDrawElement; | |
| m_ReorderableList.elementHeightCallback = GetElementHeight; | |
| m_ReorderableList.onReorderCallback = ListUpdated; | |
| } | |
| private void ListUpdated(ReorderableList list) | |
| { | |
| SaveTile(); | |
| } | |
| private float GetElementHeight(int index) | |
| { | |
| if (tile.m_TilingRules != null && tile.m_TilingRules.Count > 0) | |
| { | |
| float spritePreviewHeight = Mathf.Ceil((float) tile.m_TilingRules[index].m_Sprites.Length / (m_previewsPerRow > 0 ? m_previewsPerRow : 1)) * (k_DefaultElementHeight + 2); | |
| switch (tile.m_TilingRules[index].m_Output) | |
| { | |
| case RuleTile.TilingRule.OutputSprite.Random: | |
| return k_DefaultElementHeight + k_PaddingBetweenRules + spritePreviewHeight + k_SingleLineHeight * 3;// k_SingleLineHeight*(tile.m_TilingRules[index].m_Sprites.Length*2 + 3) + k_PaddingBetweenRules; | |
| case RuleTile.TilingRule.OutputSprite.Animation: | |
| return k_DefaultElementHeight + k_PaddingBetweenRules + spritePreviewHeight + k_SingleLineHeight * 2;// k_SingleLineHeight*(tile.m_TilingRules[index].m_Sprites.Length*2 + 2) + k_PaddingBetweenRules; | |
| } | |
| } | |
| return k_DefaultElementHeight + k_PaddingBetweenRules; | |
| } | |
| private void OnDrawElement(Rect rect, int index, bool isactive, bool isfocused) | |
| { | |
| RuleTile.TilingRule rule = tile.m_TilingRules[index]; | |
| float yPos = rect.yMin + 2f; | |
| float height = rect.height - k_PaddingBetweenRules; | |
| float matrixWidth = k_DefaultElementHeight; | |
| Rect inspectorRect = new Rect(rect.xMin, yPos, rect.width - matrixWidth * 2f - 20f, height); | |
| Rect matrixRect = new Rect(rect.xMax - matrixWidth * 2f - 10f, yPos, matrixWidth, k_DefaultElementHeight); | |
| Rect spriteRect = new Rect(rect.xMax - matrixWidth - 5f, yPos, matrixWidth, k_DefaultElementHeight); | |
| EditorGUI.BeginChangeCheck(); | |
| RuleInspectorOnGUI(inspectorRect, rule, index, this); | |
| RuleMatrixOnGUI(matrixRect, rule); | |
| SpriteOnGUI(spriteRect, rule); | |
| if (EditorGUI.EndChangeCheck()) | |
| SaveTile(); | |
| } | |
| private void SaveTile() | |
| { | |
| EditorUtility.SetDirty(target); | |
| SceneView.RepaintAll(); | |
| } | |
| private void OnDrawHeader(Rect rect) | |
| { | |
| GUI.Label(rect, "Tiling Rules"); | |
| } | |
| public override void OnInspectorGUI() | |
| { | |
| EditorGUILayout.HelpBox("Iconography: arrow = same tile, x = empty, ? = another tile",MessageType.None,true); | |
| tile.m_DefaultSprite = EditorGUILayout.ObjectField("Default Sprite", tile.m_DefaultSprite, typeof(Sprite), false) as Sprite; | |
| tile.m_DefaultColliderType = (Tile.ColliderType)EditorGUILayout.EnumPopup("Default Collider", tile.m_DefaultColliderType); | |
| EditorGUILayout.Space(); | |
| if (m_ReorderableList != null && tile.m_TilingRules != null) | |
| m_ReorderableList.DoLayoutList(); | |
| } | |
| private static void RuleMatrixOnGUI(Rect rect, RuleTile.TilingRule tilingRule) | |
| { | |
| Handles.color = EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.2f) : new Color(0f, 0f, 0f, 0.2f); | |
| int index = 0; | |
| float w = rect.width / 3f; | |
| float h = rect.height / 3f; | |
| for (int y = 0; y <= 3; y++) | |
| { | |
| float top = rect.yMin + y * h; | |
| Handles.DrawLine(new Vector3(rect.xMin, top), new Vector3(rect.xMax, top)); | |
| } | |
| for (int x = 0; x <= 3; x++) | |
| { | |
| float left = rect.xMin + x * w; | |
| Handles.DrawLine(new Vector3(left, rect.yMin), new Vector3(left, rect.yMax)); | |
| } | |
| Handles.color = Color.white; | |
| for (int y = 0; y <= 2; y++) | |
| { | |
| for (int x = 0; x <= 2; x++) | |
| { | |
| Rect r = new Rect(rect.xMin + x * w, rect.yMin + y * h, w - 1, h - 1); | |
| if (x != 1 || y != 1) | |
| { | |
| switch (tilingRule.m_Neighbors[index]) | |
| { | |
| case RuleTile.TilingRule.Neighbor.This: | |
| GUI.DrawTexture(r, arrows[y*3 + x]); | |
| break; | |
| case RuleTile.TilingRule.Neighbor.NotThis: | |
| GUI.DrawTexture(r, arrows[10]); | |
| break; | |
| case RuleTile.TilingRule.Neighbor.Empty: | |
| GUI.DrawTexture(r, arrows[9]); | |
| break; | |
| } | |
| if (Event.current.type == EventType.MouseDown && r.Contains(Event.current.mousePosition)) | |
| { | |
| tilingRule.m_Neighbors[index] = (RuleTile.TilingRule.Neighbor) (((int)tilingRule.m_Neighbors[index] + 1) % 4); | |
| GUI.changed = true; | |
| Event.current.Use(); | |
| } | |
| index++; | |
| } | |
| else | |
| { | |
| switch (tilingRule.m_RuleTransform) | |
| { | |
| case RuleTile.TilingRule.Transform.Rotated: | |
| GUI.DrawTexture(r, autoTransforms[0]); | |
| break; | |
| case RuleTile.TilingRule.Transform.MirrorX: | |
| GUI.DrawTexture(r, autoTransforms[1]); | |
| break; | |
| case RuleTile.TilingRule.Transform.MirrorY: | |
| GUI.DrawTexture(r, autoTransforms[2]); | |
| break; | |
| } | |
| if (Event.current.type == EventType.MouseDown && r.Contains(Event.current.mousePosition)) | |
| { | |
| tilingRule.m_RuleTransform = (RuleTile.TilingRule.Transform)(((int)tilingRule.m_RuleTransform + 1) % 4); | |
| GUI.changed = true; | |
| Event.current.Use(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| private static void OnSelect(object userdata) | |
| { | |
| MenuItemData data = (MenuItemData) userdata; | |
| data.m_Rule.m_RuleTransform = data.m_NewValue; | |
| } | |
| private class MenuItemData | |
| { | |
| public RuleTile.TilingRule m_Rule; | |
| public RuleTile.TilingRule.Transform m_NewValue; | |
| public MenuItemData(RuleTile.TilingRule mRule, RuleTile.TilingRule.Transform mNewValue) | |
| { | |
| this.m_Rule = mRule; | |
| this.m_NewValue = mNewValue; | |
| } | |
| } | |
| private void SpriteOnGUI(Rect rect, RuleTile.TilingRule tilingRule) | |
| { | |
| tilingRule.m_Sprites[0] = EditorGUI.ObjectField(new Rect(rect.xMax - rect.height, rect.yMin, rect.height, rect.height), tilingRule.m_Sprites[0], typeof (Sprite), false) as Sprite; | |
| } | |
| private static void RuleInspectorOnGUI(Rect rect, RuleTile.TilingRule tilingRule, int index, RuleTileEditor editor) | |
| { | |
| float y = rect.yMin; | |
| EditorGUI.BeginChangeCheck(); | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Rule-" + index); | |
| tilingRule.m_RuleTransform = (RuleTile.TilingRule.Transform)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_RuleTransform); | |
| y += k_SingleLineHeight; | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Collider"); | |
| tilingRule.m_ColliderType = (Tile.ColliderType)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_ColliderType); | |
| y += k_SingleLineHeight; | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Output"); | |
| tilingRule.m_Output = (RuleTile.TilingRule.OutputSprite)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_Output); | |
| y += k_SingleLineHeight; | |
| if (tilingRule.m_Output == RuleTile.TilingRule.OutputSprite.Animation) | |
| { | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Speed"); | |
| tilingRule.m_AnimationSpeed = EditorGUI.FloatField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_AnimationSpeed); | |
| y += k_SingleLineHeight; | |
| } | |
| if (tilingRule.m_Output == RuleTile.TilingRule.OutputSprite.Random) | |
| { | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Noise"); | |
| tilingRule.m_PerlinScale = EditorGUI.Slider(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_PerlinScale, 0.001f, 0.999f); | |
| y += k_SingleLineHeight; | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Shuffle"); | |
| tilingRule.m_RandomTransform = (RuleTile.TilingRule.Transform)EditorGUI.EnumPopup(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_RandomTransform); | |
| y += k_SingleLineHeight; | |
| } | |
| if (tilingRule.m_Output != RuleTile.TilingRule.OutputSprite.Single) | |
| { | |
| GUI.Label(new Rect(rect.xMin, y, k_LabelWidth, k_SingleLineHeight), "Size"); | |
| EditorGUI.BeginChangeCheck(); | |
| int newLength = EditorGUI.DelayedIntField(new Rect(rect.xMin + k_LabelWidth, y, rect.width - k_LabelWidth, k_SingleLineHeight), tilingRule.m_Sprites.Length); | |
| if (EditorGUI.EndChangeCheck()) | |
| Array.Resize(ref tilingRule.m_Sprites, Math.Max(newLength, 1)); | |
| y += k_SingleLineHeight; | |
| // Rows is equal to | |
| float singleWidth = k_DefaultElementHeight + 5.0f; | |
| float maxWidth = EditorGUIUtility.currentViewWidth - k_LabelWidth - 34 - 22; | |
| editor.m_previewsPerRow = (int)(maxWidth/ singleWidth); | |
| for (int i = 0; i < tilingRule.m_Sprites.Length; i++) | |
| { | |
| int col = i % editor.m_previewsPerRow; | |
| if (i != 0 && col == 0) | |
| y += k_DefaultElementHeight + 2.0f; | |
| tilingRule.m_Sprites[i] = EditorGUI.ObjectField(new Rect(rect.xMin + k_LabelWidth + col * singleWidth, y, k_DefaultElementHeight, k_DefaultElementHeight), tilingRule.m_Sprites[i], typeof(Sprite), false) as Sprite; | |
| } | |
| } | |
| } | |
| public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height) | |
| { | |
| if (tile.m_DefaultSprite != null) | |
| { | |
| Type t = GetType("UnityEditor.SpriteUtility"); | |
| if (t != null) | |
| { | |
| MethodInfo method = t.GetMethod("RenderStaticPreview", new Type[] {typeof (Sprite), typeof (Color), typeof (int), typeof (int)}); | |
| if (method != null) | |
| { | |
| object ret = method.Invoke("RenderStaticPreview", new object[] {tile.m_DefaultSprite, Color.white, width, height}); | |
| if (ret is Texture2D) | |
| return ret as Texture2D; | |
| } | |
| } | |
| } | |
| return base.RenderStaticPreview(assetPath, subAssets, width, height); | |
| } | |
| private static Type GetType(string TypeName) | |
| { | |
| var type = Type.GetType(TypeName); | |
| if (type != null) | |
| return type; | |
| if (TypeName.Contains(".")) | |
| { | |
| var assemblyName = TypeName.Substring(0, TypeName.IndexOf('.')); | |
| var assembly = Assembly.Load(assemblyName); | |
| if (assembly == null) | |
| return null; | |
| type = assembly.GetType(TypeName); | |
| if (type != null) | |
| return type; | |
| } | |
| var currentAssembly = Assembly.GetExecutingAssembly(); | |
| var referencedAssemblies = currentAssembly.GetReferencedAssemblies(); | |
| foreach (var assemblyName in referencedAssemblies) | |
| { | |
| var assembly = Assembly.Load(assemblyName); | |
| if (assembly != null) | |
| { | |
| type = assembly.GetType(TypeName); | |
| if (type != null) | |
| return type; | |
| } | |
| } | |
| return null; | |
| } | |
| private static Texture2D Base64ToTexture(string base64) | |
| { | |
| Texture2D t = new Texture2D(1, 1); | |
| t.hideFlags = HideFlags.HideAndDontSave; | |
| t.LoadImage(System.Convert.FromBase64String(base64)); | |
| return t; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment