diff --git a/Documentation~/RandomTerrainTile.md b/Documentation~/RandomTerrainTile.md
new file mode 100644
index 0000000..1ead717
--- /dev/null
+++ b/Documentation~/RandomTerrainTile.md
@@ -0,0 +1,33 @@
+# Random Terrain Tile
+
+Very similar to the Terrain Tile, but this supports an array of sprites for each property, and applies them randomly, at the time of the placement.
+
+## Properties
+
+The following properties describe the appearance of Sprites representing terrain or walls. Assign Sprites that matches the description to each of these properties.
+
+| Property | Function |
+| ------------------------------------- | ------------------------------------------------------------ |
+| 1. __Filled__ | Sprites with all sides filled. |
+| 2. __Three Sides__ | Sprites with three sides. |
+| 3. __Two Sides and One Corner__ | Sprites with two sides and one corner without adjacent sides. |
+| 4. __Two Adjacent Sides__ | Sprites with two adjacent sides. |
+| 5. __Two Opposite Sides__ | Sprites with two opposite sides across each other. |
+| 6. __One Side and Two Corners__ | Sprites with a single side and two corners without adjacent sides. |
+| 7. __One Side and One Lower Corner__ | Sprites with one side and a corner in the lower half of the Sprite. |
+| 8. __One Side and One Upper Corner__ | Sprites with one side and a corner in the upper half of the Sprite. |
+| 9. __One Side__ | Sprites with a single side. |
+| 10. __Four Corners__ | Sprites with four unconnected corners without adjacent sides. |
+| 11. __Three Corners__ | Sprites with three corners without adjacent sides. |
+| 12. __Two Adjacent Corners__ | Sprites with two adjacent corners. |
+| 13. __Two Opposite Corners__ | Sprites with two opposite corners across each other. |
+| 14. __One Corner__ | Sprites with a single corner with no adjacent sides. |
+| 15. __Empty__ | Sprites without any terrain. |
+
+## Usage
+
+The Random Terrain Tile is a copy of Terrain Tile with the only difference that it supports multiple sprites for each level.
+
+The image below may be of help to know how to position tiles in a way to facilitate their positioning. Such layout works for Terrain Tiles too, by the way.
+
+
diff --git a/Documentation~/Tiles.md b/Documentation~/Tiles.md
index 605fffe..d8be8ff 100644
--- a/Documentation~/Tiles.md
+++ b/Documentation~/Tiles.md
@@ -12,5 +12,6 @@ The following are some implementations and examples of __Scriptables Tiles__ whi
- [Rule Override Tile](RuleOverrideTile.md)
- [Terrain Tile](TerrainTile.md)
- [Weighted Random Tile](WeightedRandomTile.md)
+- [Random Terrain Tile](RandomTerrainTile.md)
Refer to the [Scriptable Tiles](https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles.html) documentation page for more information on creating your own Scriptable Tiles.
\ No newline at end of file
diff --git a/Documentation~/images/RandomTerrainTilePositioning.png b/Documentation~/images/RandomTerrainTilePositioning.png
new file mode 100644
index 0000000..6fa86f5
Binary files /dev/null and b/Documentation~/images/RandomTerrainTilePositioning.png differ
diff --git a/Runtime/Tiles/RandomTerrainTile/RandomTerrainTile.cs b/Runtime/Tiles/RandomTerrainTile/RandomTerrainTile.cs
new file mode 100644
index 0000000..47cf073
--- /dev/null
+++ b/Runtime/Tiles/RandomTerrainTile/RandomTerrainTile.cs
@@ -0,0 +1,349 @@
+using System;
+
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace UnityEngine.Tilemaps
+{
+
+ ///
+ /// Terrain Tiles, similar to Pipeline Tiles, are tiles which take into consideration its orthogonal and diagonal neighboring tiles and displays a sprite depending on whether the neighboring tile is the same tile.
+ ///
+ [Serializable]
+ [CreateAssetMenu(fileName = "New Random Terrain Tile", menuName = "2D Extras/Tiles/Random Terrain Tile", order = 360)]
+ public class RandomTerrainTile : TileBase
+ {
+ [SerializeField] public Sprite[] Filled;
+ [SerializeField] public Sprite[] ThreeSides;
+ [SerializeField] public Sprite[] TwoSidesAndOneCorner;
+ [SerializeField] public Sprite[] TwoAdjacentSides;
+ [SerializeField] public Sprite[] TwoOppositeSides;
+ [SerializeField] public Sprite[] OneSideAndTwoCorners;
+ [SerializeField] public Sprite[] OneSideAndOneLowerCorner;
+ [SerializeField] public Sprite[] OneSideAndOneUpperCorner;
+ [SerializeField] public Sprite[] OneSide;
+ [SerializeField] public Sprite[] FourCorners;
+ [SerializeField] public Sprite[] ThreeCorners;
+ [SerializeField] public Sprite[] TwoAdjacentCorners;
+ [SerializeField] public Sprite[] TwoOppositeCorners;
+ [SerializeField] public Sprite[] OneCorner;
+ [SerializeField] public Sprite[] Empty;
+
+ ///
+ /// The Sprites used for defining the Terrain.
+ ///
+ // [SerializeField]
+ // public Sprite[] m_Sprites;
+
+ ///
+ /// This method is called when the tile is refreshed.
+ ///
+ /// Position of the Tile on the Tilemap.
+ /// The Tilemap the tile is present on.
+ public override void RefreshTile(Vector3Int location, ITilemap tileMap)
+ {
+ for (int yd = -1; yd <= 1; yd++)
+ for (int xd = -1; xd <= 1; xd++)
+ {
+ Vector3Int position = new Vector3Int(location.x + xd, location.y + yd, location.z);
+ if (TileValue(tileMap, position))
+ tileMap.RefreshTile(position);
+ }
+ }
+
+ ///
+ /// Retrieves any tile rendering data from the scripted tile.
+ ///
+ /// Position of the Tile on the Tilemap.
+ /// The Tilemap the tile is present on.
+ /// Data to render the tile.
+ public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
+ {
+ UpdateTile(location, tileMap, ref tileData);
+ }
+
+ private void UpdateTile(Vector3Int location, ITilemap tileMap, ref TileData tileData)
+ {
+ tileData.transform = Matrix4x4.identity;
+ tileData.color = Color.white;
+
+ int mask = TileValue(tileMap, location + new Vector3Int(0, 1, 0)) ? 1 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(1, 1, 0)) ? 2 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(1, 0, 0)) ? 4 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(1, -1, 0)) ? 8 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(0, -1, 0)) ? 16 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(-1, -1, 0)) ? 32 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(-1, 0, 0)) ? 64 : 0;
+ mask += TileValue(tileMap, location + new Vector3Int(-1, 1, 0)) ? 128 : 0;
+
+ byte original = (byte)mask;
+ if ((original | 254) < 255) { mask = mask & 125; }
+ if ((original | 251) < 255) { mask = mask & 245; }
+ if ((original | 239) < 255) { mask = mask & 215; }
+ if ((original | 191) < 255) { mask = mask & 95; }
+
+ Sprite[][] m_Sprites = GetSpritesAsOne();
+
+ int index = GetIndex((byte)mask);
+ if (index >= 0 && index < m_Sprites.Length && TileValue(tileMap, location))
+ {
+ tileData.sprite = GetRandomSprite(m_Sprites[index]);
+ tileData.transform = GetTransform((byte)mask);
+ tileData.color = Color.white;
+ tileData.flags = TileFlags.LockTransform | TileFlags.LockColor;
+ tileData.colliderType = Tile.ColliderType.Sprite;
+ }
+ }
+
+ private Sprite GetRandomSprite(Sprite[] spriteList) {
+ if (spriteList.Length == 0) {
+ return null;
+ }
+
+ int spriteIndex = Random.Range(0, spriteList.Length - 1);
+ return spriteList[spriteIndex];
+ }
+
+ private Sprite[][] GetSpritesAsOne() {
+ Sprite[][] m_Sprites = new Sprite[15][];
+ m_Sprites[0] = Filled;
+ m_Sprites[1] = ThreeSides;
+ m_Sprites[2] = TwoSidesAndOneCorner;
+ m_Sprites[3] = TwoAdjacentSides;
+ m_Sprites[4] = TwoOppositeSides;
+ m_Sprites[5] = OneSideAndTwoCorners;
+ m_Sprites[6] = OneSideAndOneLowerCorner;
+ m_Sprites[7] = OneSideAndOneUpperCorner;
+ m_Sprites[8] = OneSide;
+ m_Sprites[9] = FourCorners;
+ m_Sprites[10] = ThreeCorners;
+ m_Sprites[11] = TwoAdjacentCorners;
+ m_Sprites[12] = TwoOppositeCorners;
+ m_Sprites[13] = OneCorner;
+ m_Sprites[14] = Empty;
+ return m_Sprites;
+ }
+
+ private bool TileValue(ITilemap tileMap, Vector3Int position)
+ {
+ TileBase tile = tileMap.GetTile(position);
+ return (tile != null && tile == this);
+ }
+
+ private int GetIndex(byte mask)
+ {
+ switch (mask)
+ {
+ case 0: return 0;
+ case 1:
+ case 4:
+ case 16:
+ case 64: return 1;
+ case 5:
+ case 20:
+ case 80:
+ case 65: return 2;
+ case 7:
+ case 28:
+ case 112:
+ case 193: return 3;
+ case 17:
+ case 68: return 4;
+ case 21:
+ case 84:
+ case 81:
+ case 69: return 5;
+ case 23:
+ case 92:
+ case 113:
+ case 197: return 6;
+ case 29:
+ case 116:
+ case 209:
+ case 71: return 7;
+ case 31:
+ case 124:
+ case 241:
+ case 199: return 8;
+ case 85: return 9;
+ case 87:
+ case 93:
+ case 117:
+ case 213: return 10;
+ case 95:
+ case 125:
+ case 245:
+ case 215: return 11;
+ case 119:
+ case 221: return 12;
+ case 127:
+ case 253:
+ case 247:
+ case 223: return 13;
+ case 255: return 14;
+ }
+ return -1;
+ }
+
+ private Matrix4x4 GetTransform(byte mask)
+ {
+ switch (mask)
+ {
+ case 4:
+ case 20:
+ case 28:
+ case 68:
+ case 84:
+ case 92:
+ case 116:
+ case 124:
+ case 93:
+ case 125:
+ case 221:
+ case 253:
+ return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -90f), Vector3.one);
+ case 16:
+ case 80:
+ case 112:
+ case 81:
+ case 113:
+ case 209:
+ case 241:
+ case 117:
+ case 245:
+ case 247:
+ return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -180f), Vector3.one);
+ case 64:
+ case 65:
+ case 193:
+ case 69:
+ case 197:
+ case 71:
+ case 199:
+ case 213:
+ case 215:
+ case 223:
+ return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -270f), Vector3.one);
+ }
+ return Matrix4x4.identity;
+ }
+ }
+
+#if UNITY_EDITOR
+ [CustomEditor(typeof(RandomTerrainTile))]
+ public class RandomTerrainTileEditor : Editor
+ {
+ private RandomTerrainTile tile { get { return (target as RandomTerrainTile); } }
+
+ public void OnEnable()
+ {
+ bool setDirty = false;
+
+ if (tile.Filled == null || tile.Filled.Length == 0) {
+ tile.Filled = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.ThreeSides == null || tile.ThreeSides.Length == 0) {
+ tile.ThreeSides = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.TwoSidesAndOneCorner == null || tile.TwoSidesAndOneCorner.Length == 0) {
+ tile.TwoSidesAndOneCorner = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.TwoAdjacentSides == null || tile.TwoAdjacentSides.Length == 0) {
+ tile.TwoAdjacentSides = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.TwoOppositeSides == null || tile.TwoOppositeSides.Length == 0) {
+ tile.TwoOppositeSides = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.OneSideAndTwoCorners == null || tile.OneSideAndTwoCorners.Length == 0) {
+ tile.OneSideAndTwoCorners = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.OneSideAndOneLowerCorner == null || tile.OneSideAndOneLowerCorner.Length == 0) {
+ tile.OneSideAndOneLowerCorner = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.OneSideAndOneUpperCorner == null || tile.OneSideAndOneUpperCorner.Length == 0) {
+ tile.OneSideAndOneUpperCorner = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.OneSide == null || tile.OneSide.Length == 0) {
+ tile.OneSide = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.FourCorners == null || tile.FourCorners.Length == 0) {
+ tile.FourCorners = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.ThreeCorners == null || tile.ThreeCorners.Length == 0) {
+ tile.ThreeCorners = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.TwoAdjacentCorners == null || tile.TwoAdjacentCorners.Length == 0) {
+ tile.TwoAdjacentCorners = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.TwoOppositeCorners == null || tile.TwoOppositeCorners.Length == 0) {
+ tile.TwoOppositeCorners = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.OneCorner == null || tile.OneCorner.Length == 0) {
+ tile.OneCorner = new Sprite[1]; setDirty = true;
+ }
+
+ if (tile.Empty == null || tile.Empty.Length == 0) {
+ tile.Empty = new Sprite[1]; setDirty = true;
+ }
+
+ if (setDirty) {
+ EditorUtility.SetDirty(tile);
+ }
+ }
+
+ // public void OnEnable()
+ // {
+ // if (tile.m_Sprites == null || tile.m_Sprites.Length != 15)
+ // {
+ // tile.m_Sprites = new Sprite[15];
+ // EditorUtility.SetDirty(tile);
+ // }
+ // }
+
+
+ // public override void OnInspectorGUI()
+ // {
+ // EditorGUILayout.LabelField("Place sprites shown based on the contents of the sprite.");
+ // EditorGUILayout.Space();
+
+ // float oldLabelWidth = EditorGUIUtility.labelWidth;
+ // EditorGUIUtility.labelWidth = 210;
+
+ // EditorGUI.BeginChangeCheck();
+ // tile.m_Sprites[0] = (Sprite) EditorGUILayout.ObjectField("Filled", tile.m_Sprites[0], typeof(Sprite), false, null);
+ // tile.m_Sprites[1] = (Sprite) EditorGUILayout.ObjectField("Three Sides", tile.m_Sprites[1], typeof(Sprite), false, null);
+ // tile.m_Sprites[2] = (Sprite) EditorGUILayout.ObjectField("Two Sides and One Corner", tile.m_Sprites[2], typeof(Sprite), false, null);
+ // tile.m_Sprites[3] = (Sprite) EditorGUILayout.ObjectField("Two Adjacent Sides", tile.m_Sprites[3], typeof(Sprite), false, null);
+ // tile.m_Sprites[4] = (Sprite) EditorGUILayout.ObjectField("Two Opposite Sides", tile.m_Sprites[4], typeof(Sprite), false, null);
+ // tile.m_Sprites[5] = (Sprite) EditorGUILayout.ObjectField("One Side and Two Corners", tile.m_Sprites[5], typeof(Sprite), false, null);
+ // tile.m_Sprites[6] = (Sprite) EditorGUILayout.ObjectField("One Side and One Lower Corner", tile.m_Sprites[6], typeof(Sprite), false, null);
+ // tile.m_Sprites[7] = (Sprite) EditorGUILayout.ObjectField("One Side and One Upper Corner", tile.m_Sprites[7], typeof(Sprite), false, null);
+ // tile.m_Sprites[8] = (Sprite) EditorGUILayout.ObjectField("One Side", tile.m_Sprites[8], typeof(Sprite), false, null);
+ // tile.m_Sprites[9] = (Sprite) EditorGUILayout.ObjectField("Four Corners", tile.m_Sprites[9], typeof(Sprite), false, null);
+ // tile.m_Sprites[10] = (Sprite) EditorGUILayout.ObjectField("Three Corners", tile.m_Sprites[10], typeof(Sprite), false, null);
+ // tile.m_Sprites[11] = (Sprite) EditorGUILayout.ObjectField("Two Adjacent Corners", tile.m_Sprites[11], typeof(Sprite), false, null);
+ // tile.m_Sprites[12] = (Sprite) EditorGUILayout.ObjectField("Two Opposite Corners", tile.m_Sprites[12], typeof(Sprite), false, null);
+ // tile.m_Sprites[13] = (Sprite) EditorGUILayout.ObjectField("One Corner", tile.m_Sprites[13], typeof(Sprite), false, null);
+ // tile.m_Sprites[14] = (Sprite) EditorGUILayout.ObjectField("Empty", tile.m_Sprites[14], typeof(Sprite), false, null);
+ // if (EditorGUI.EndChangeCheck())
+ // EditorUtility.SetDirty(tile);
+
+ // EditorGUIUtility.labelWidth = oldLabelWidth;
+ // }
+ }
+#endif
+}
diff --git a/Runtime/Tiles/RandomTerrainTile/RandomTerrainTile.cs.meta b/Runtime/Tiles/RandomTerrainTile/RandomTerrainTile.cs.meta
new file mode 100644
index 0000000..b5b25e2
--- /dev/null
+++ b/Runtime/Tiles/RandomTerrainTile/RandomTerrainTile.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: af8ebeabaad034943bca08de2636b4b4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: