using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine.Tilemaps;
using UnityEngine.Serialization;
namespace UnityEngine
{
///
/// Generic visual tile for creating different tilesets like terrain, pipeline, random or animated tiles.
/// This is templated to accept a Neighbor Rule Class for Custom Rules.
///
/// Neighbor Rule Class for Custom Rules
public class RuleTile : RuleTile
{
///
/// Returns the Neighbor Rule Class type for this Rule Tile.
///
public sealed override Type m_NeighborType => typeof(T);
}
///
/// Generic visual tile for creating different tilesets like terrain, pipeline, random or animated tiles.
///
[Serializable]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.tilemap.extras@latest/index.html?subfolder=/manual/RuleTile.html")]
public class RuleTile : TileBase
{
///
/// Returns the default Neighbor Rule Class type.
///
public virtual Type m_NeighborType => typeof(TilingRuleOutput.Neighbor);
///
/// The Default Sprite set when creating a new Rule.
///
public Sprite m_DefaultSprite;
///
/// The Default GameObject set when creating a new Rule.
///
public GameObject m_DefaultGameObject;
///
/// The Default Collider Type set when creating a new Rule.
///
public Tile.ColliderType m_DefaultColliderType = Tile.ColliderType.Sprite;
///
/// Angle in which the RuleTile is rotated by for matching in Degrees.
///
public virtual int m_RotationAngle => 90;
///
/// Number of rotations the RuleTile can be rotated by for matching.
///
public int m_RotationCount => 360 / m_RotationAngle;
///
/// The data structure holding the Rule information for matching Rule Tiles with
/// its neighbors.
///
[Serializable]
public class TilingRuleOutput
{
///
/// Id for this Rule.
///
public int m_Id;
///
/// The output Sprites for this Rule.
///
public Sprite[] m_Sprites = new Sprite[1];
///
/// The output GameObject for this Rule.
///
public GameObject m_GameObject;
///
/// The output minimum Animation Speed for this Rule.
///
[FormerlySerializedAs("m_AnimationSpeed")]
public float m_MinAnimationSpeed = 1f;
///
/// The output maximum Animation Speed for this Rule.
///
[FormerlySerializedAs("m_AnimationSpeed")]
public float m_MaxAnimationSpeed = 1f;
///
/// The perlin scale factor for this Rule.
///
public float m_PerlinScale = 0.5f;
///
/// The output type for this Rule.
///
public OutputSprite m_Output = OutputSprite.Single;
///
/// The output Collider Type for this Rule.
///
public Tile.ColliderType m_ColliderType = Tile.ColliderType.Sprite;
///
/// The randomized transform output for this Rule.
///
public Transform m_RandomTransform;
///
/// The enumeration for matching Neighbors when matching Rule Tiles
///
public class Neighbor
{
///
/// The Rule Tile will check if the contents of the cell in that direction is an instance of this Rule Tile.
/// If not, the rule will fail.
///
public const int This = 1;
///
/// The Rule Tile will check if the contents of the cell in that direction is not an instance of this Rule Tile.
/// If it is, the rule will fail.
///
public const int NotThis = 2;
}
///
/// The enumeration for the transform rule used when matching Rule Tiles.
///
public enum Transform
{
///
/// The Rule Tile will match Tiles exactly as laid out in its neighbors.
///
Fixed,
///
/// The Rule Tile will rotate and match its neighbors.
///
Rotated,
///
/// The Rule Tile will mirror in the X axis and match its neighbors.
///
MirrorX,
///
/// The Rule Tile will mirror in the Y axis and match its neighbors.
///
MirrorY,
///
/// The Rule Tile will mirror in the X or Y axis and match its neighbors.
///
MirrorXY
}
///
/// The Output for the Tile which fits this Rule.
///
public enum OutputSprite
{
///
/// A Single Sprite will be output.
///
Single,
///
/// A Random Sprite will be output.
///
Random,
///
/// A Sprite Animation will be output.
///
Animation
}
}
///
/// The data structure holding the Rule information for matching Rule Tiles with
/// its neighbors.
///
[Serializable]
public class TilingRule : TilingRuleOutput
{
///
/// The matching Rule conditions for each of its neighboring Tiles.
///
public List m_Neighbors = new List();
///
/// * Preset this list to RuleTile backward compatible, but not support for HexagonalRuleTile backward compatible.
///
public List m_NeighborPositions = new List()
{
new Vector3Int(-1, 1, 0),
new Vector3Int(0, 1, 0),
new Vector3Int(1, 1, 0),
new Vector3Int(-1, 0, 0),
new Vector3Int(1, 0, 0),
new Vector3Int(-1, -1, 0),
new Vector3Int(0, -1, 0),
new Vector3Int(1, -1, 0),
};
///
/// The transform matching Rule for this Rule.
///
public Transform m_RuleTransform;
///
/// This clones a copy of the TilingRule.
///
/// A copy of the TilingRule.
public TilingRule Clone()
{
TilingRule rule = new TilingRule
{
m_Neighbors = new List(m_Neighbors),
m_NeighborPositions = new List(m_NeighborPositions),
m_RuleTransform = m_RuleTransform,
m_Sprites = new Sprite[m_Sprites.Length],
m_GameObject = m_GameObject,
m_MinAnimationSpeed = m_MinAnimationSpeed,
m_MaxAnimationSpeed = m_MaxAnimationSpeed,
m_PerlinScale = m_PerlinScale,
m_Output = m_Output,
m_ColliderType = m_ColliderType,
m_RandomTransform = m_RandomTransform,
};
Array.Copy(m_Sprites, rule.m_Sprites, m_Sprites.Length);
return rule;
}
///
/// Returns all neighbors of this Tile as a dictionary
///
/// A dictionary of neighbors for this Tile
public Dictionary GetNeighbors()
{
Dictionary dict = new Dictionary();
for (int i = 0; i < m_Neighbors.Count && i < m_NeighborPositions.Count; i++)
dict.Add(m_NeighborPositions[i], m_Neighbors[i]);
return dict;
}
///
/// Applies the values from the given dictionary as this Tile's neighbors
///
/// Dictionary to apply values from
public void ApplyNeighbors(Dictionary dict)
{
m_NeighborPositions = dict.Keys.ToList();
m_Neighbors = dict.Values.ToList();
}
///
/// Gets the cell bounds of the TilingRule.
///
/// Returns the cell bounds of the TilingRule.
public BoundsInt GetBounds()
{
BoundsInt bounds = new BoundsInt(Vector3Int.zero, Vector3Int.one);
foreach (var neighbor in GetNeighbors())
{
bounds.xMin = Mathf.Min(bounds.xMin, neighbor.Key.x);
bounds.yMin = Mathf.Min(bounds.yMin, neighbor.Key.y);
bounds.xMax = Mathf.Max(bounds.xMax, neighbor.Key.x + 1);
bounds.yMax = Mathf.Max(bounds.yMax, neighbor.Key.y + 1);
}
return bounds;
}
}
///
/// Attribute which marks a property which cannot be overridden by a RuleOverrideTile
///
public class DontOverride : Attribute { }
///
/// A list of Tiling Rules for the Rule Tile.
///
[HideInInspector] public List m_TilingRules = new List();
///
/// Returns a set of neighboring positions for this RuleTile
///
public HashSet neighborPositions
{
get
{
if (m_NeighborPositions.Count == 0)
UpdateNeighborPositions();
return m_NeighborPositions;
}
}
private HashSet m_NeighborPositions = new HashSet();
///
/// Updates the neighboring positions of this RuleTile
///
public void UpdateNeighborPositions()
{
m_CacheTilemapsNeighborPositions.Clear();
HashSet positions = m_NeighborPositions;
positions.Clear();
foreach (TilingRule rule in m_TilingRules)
{
foreach (var neighbor in rule.GetNeighbors())
{
Vector3Int position = neighbor.Key;
positions.Add(position);
// Check rule against rotations of 0, 90, 180, 270
if (rule.m_RuleTransform == TilingRuleOutput.Transform.Rotated)
{
for (int angle = m_RotationAngle; angle < 360; angle += m_RotationAngle)
{
positions.Add(GetRotatedPosition(position, angle));
}
}
// Check rule against x-axis, y-axis mirror
else if (rule.m_RuleTransform == TilingRuleOutput.Transform.MirrorXY)
{
positions.Add(GetMirroredPosition(position, true, true));
positions.Add(GetMirroredPosition(position, true, false));
positions.Add(GetMirroredPosition(position, false, true));
}
// Check rule against x-axis mirror
else if (rule.m_RuleTransform == TilingRuleOutput.Transform.MirrorX)
{
positions.Add(GetMirroredPosition(position, true, false));
}
// Check rule against y-axis mirror
else if (rule.m_RuleTransform == TilingRuleOutput.Transform.MirrorY)
{
positions.Add(GetMirroredPosition(position, false, true));
}
}
}
}
///
/// StartUp is called on the first frame of the running Scene.
///
/// Position of the Tile on the Tilemap.
/// The Tilemap the tile is present on.
/// The GameObject instantiated for the Tile.
/// Whether StartUp was successful
public override bool StartUp(Vector3Int position, ITilemap tilemap, GameObject instantiatedGameObject)
{
if (instantiatedGameObject != null)
{
Tilemap tmpMap = tilemap.GetComponent();
Matrix4x4 orientMatrix = tmpMap.orientationMatrix;
var iden = Matrix4x4.identity;
Vector3 gameObjectTranslation = new Vector3();
Quaternion gameObjectRotation = new Quaternion();
Vector3 gameObjectScale = new Vector3();
bool ruleMatched = false;
Matrix4x4 transform = iden;
foreach (TilingRule rule in m_TilingRules)
{
if (RuleMatches(rule, position, tilemap, ref transform))
{
transform = orientMatrix * transform;
// Converts the tile's translation, rotation, & scale matrix to values to be used by the instantiated GameObject
gameObjectTranslation = new Vector3(transform.m03, transform.m13, transform.m23);
gameObjectRotation = Quaternion.LookRotation(new Vector3(transform.m02, transform.m12, transform.m22), new Vector3(transform.m01, transform.m11, transform.m21));
gameObjectScale = transform.lossyScale;
ruleMatched = true;
break;
}
}
if (!ruleMatched)
{
// Fallback to just using the orientMatrix for the translation, rotation, & scale values.
gameObjectTranslation = new Vector3(orientMatrix.m03, orientMatrix.m13, orientMatrix.m23);
gameObjectRotation = Quaternion.LookRotation(new Vector3(orientMatrix.m02, orientMatrix.m12, orientMatrix.m22), new Vector3(orientMatrix.m01, orientMatrix.m11, orientMatrix.m21));
gameObjectScale = orientMatrix.lossyScale;
}
instantiatedGameObject.transform.localPosition = gameObjectTranslation + tmpMap.CellToLocalInterpolated(position + tmpMap.tileAnchor);
instantiatedGameObject.transform.localRotation = gameObjectRotation;
instantiatedGameObject.transform.localScale = gameObjectScale;
}
return true;
}
///
/// 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 position, ITilemap tilemap, ref TileData tileData)
{
var iden = Matrix4x4.identity;
tileData.sprite = m_DefaultSprite;
tileData.gameObject = m_DefaultGameObject;
tileData.colliderType = m_DefaultColliderType;
tileData.flags = TileFlags.LockTransform;
tileData.transform = iden;
Matrix4x4 transform = iden;
foreach (TilingRule rule in m_TilingRules)
{
if (RuleMatches(rule, position, tilemap, ref transform))
{
switch (rule.m_Output)
{
case TilingRuleOutput.OutputSprite.Single:
case TilingRuleOutput.OutputSprite.Animation:
tileData.sprite = rule.m_Sprites[0];
break;
case TilingRuleOutput.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 != TilingRuleOutput.Transform.Fixed)
transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
break;
}
tileData.transform = transform;
tileData.gameObject = rule.m_GameObject;
tileData.colliderType = rule.m_ColliderType;
break;
}
}
}
///
/// Returns a Perlin Noise value based on the given inputs.
///
/// Position of the Tile on the Tilemap.
/// The Perlin Scale factor of the Tile.
/// Offset of the Tile on the Tilemap.
/// A Perlin Noise value based on the given inputs.
public static float GetPerlinValue(Vector3Int position, float scale, float offset)
{
return Mathf.PerlinNoise((position.x + offset) * scale, (position.y + offset) * scale);
}
static Dictionary, HashSet>> m_CacheTilemapsNeighborPositions = new Dictionary, HashSet>>();
static TileBase[] m_AllocatedUsedTileArr = Array.Empty();
static bool IsTilemapUsedTilesChange(Tilemap tilemap, out KeyValuePair, HashSet> hashSet)
{
if (!m_CacheTilemapsNeighborPositions.TryGetValue(tilemap, out hashSet))
return true;
var oldUsedTiles = hashSet.Key;
int newUsedTilesCount = tilemap.GetUsedTilesCount();
if (newUsedTilesCount != oldUsedTiles.Count)
return true;
if (m_AllocatedUsedTileArr.Length < newUsedTilesCount)
Array.Resize(ref m_AllocatedUsedTileArr, newUsedTilesCount);
tilemap.GetUsedTilesNonAlloc(m_AllocatedUsedTileArr);
for (int i = 0; i < newUsedTilesCount; i++)
{
TileBase newUsedTile = m_AllocatedUsedTileArr[i];
if (!oldUsedTiles.Contains(newUsedTile))
return true;
}
return false;
}
static KeyValuePair, HashSet> CachingTilemapNeighborPositions(Tilemap tilemap)
{
int usedTileCount = tilemap.GetUsedTilesCount();
HashSet usedTiles = new HashSet();
HashSet neighborPositions = new HashSet();
if (m_AllocatedUsedTileArr.Length < usedTileCount)
Array.Resize(ref m_AllocatedUsedTileArr, usedTileCount);
tilemap.GetUsedTilesNonAlloc(m_AllocatedUsedTileArr);
for (int i = 0; i < usedTileCount; i++)
{
TileBase tile = m_AllocatedUsedTileArr[i];
usedTiles.Add(tile);
RuleTile ruleTile = null;
if (tile is RuleTile rt)
ruleTile = rt;
else if (tile is RuleOverrideTile ot)
ruleTile = ot.m_Tile;
if (ruleTile)
foreach (Vector3Int neighborPosition in ruleTile.neighborPositions)
neighborPositions.Add(neighborPosition);
}
var value = new KeyValuePair, HashSet>(usedTiles, neighborPositions);
m_CacheTilemapsNeighborPositions[tilemap] = value;
return value;
}
static bool NeedRelease()
{
foreach (var keypair in m_CacheTilemapsNeighborPositions)
{
if (keypair.Key == null)
{
return true;
}
}
return false;
}
static void ReleaseDestroyedTilemapCacheData()
{
if (!NeedRelease())
return;
var hasCleared = false;
var keys = m_CacheTilemapsNeighborPositions.Keys.ToArray();
foreach (var key in keys)
{
if (key == null && m_CacheTilemapsNeighborPositions.Remove(key))
hasCleared = true;
}
if (hasCleared)
{
// TrimExcess
m_CacheTilemapsNeighborPositions = new Dictionary, HashSet>>(m_CacheTilemapsNeighborPositions);
}
}
///
/// Retrieves any tile animation data from the scripted tile.
///
/// Position of the Tile on the Tilemap.
/// The Tilemap the tile is present on.
/// Data to run an animation on the tile.
/// Whether the call was successful.
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
{
Matrix4x4 transform = Matrix4x4.identity;
foreach (TilingRule rule in m_TilingRules)
{
if (rule.m_Output == TilingRuleOutput.OutputSprite.Animation)
{
if (RuleMatches(rule, position, tilemap, ref transform))
{
tileAnimationData.animatedSprites = rule.m_Sprites;
tileAnimationData.animationSpeed = Random.Range( rule.m_MinAnimationSpeed, rule.m_MaxAnimationSpeed);
return true;
}
}
}
return false;
}
///
/// 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 position, ITilemap tilemap)
{
base.RefreshTile(position, tilemap);
Tilemap baseTilemap = tilemap.GetComponent();
ReleaseDestroyedTilemapCacheData(); // Prevent memory leak
if (IsTilemapUsedTilesChange(baseTilemap, out var neighborPositionsSet))
neighborPositionsSet = CachingTilemapNeighborPositions(baseTilemap);
var neighborPositionsRuleTile = neighborPositionsSet.Value;
foreach (Vector3Int offset in neighborPositionsRuleTile)
{
Vector3Int offsetPosition = GetOffsetPositionReverse(position, offset);
TileBase tile = tilemap.GetTile(offsetPosition);
RuleTile ruleTile = null;
if (tile is RuleTile rt)
ruleTile = rt;
else if (tile is RuleOverrideTile ot)
ruleTile = ot.m_Tile;
if (ruleTile != null)
if (ruleTile == this || ruleTile.neighborPositions.Contains(offset))
base.RefreshTile(offsetPosition, tilemap);
}
}
///
/// Does a Rule Match given a Tiling Rule and neighboring Tiles.
///
/// The Tiling Rule to match with.
/// Position of the Tile on the Tilemap.
/// The tilemap to match with.
/// A transform matrix which will match the Rule.
/// True if there is a match, False if not.
public virtual bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, ref Matrix4x4 transform)
{
if (RuleMatches(rule, position, tilemap, 0))
{
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, 0f), Vector3.one);
return true;
}
// Check rule against rotations of 0, 90, 180, 270
if (rule.m_RuleTransform == TilingRuleOutput.Transform.Rotated)
{
for (int angle = m_RotationAngle; angle < 360; angle += m_RotationAngle)
{
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, y-axis mirror
else if (rule.m_RuleTransform == TilingRuleOutput.Transform.MirrorXY)
{
if (RuleMatches(rule, position, tilemap, true, true))
{
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, -1f, 1f));
return true;
}
if (RuleMatches(rule, position, tilemap, true, false))
{
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f));
return true;
}
if (RuleMatches(rule, position, tilemap, false, true))
{
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
return true;
}
}
// Check rule against x-axis mirror
else if (rule.m_RuleTransform == TilingRuleOutput.Transform.MirrorX)
{
if (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
else if (rule.m_RuleTransform == TilingRuleOutput.Transform.MirrorY)
{
if (RuleMatches(rule, position, tilemap, false, true))
{
transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
return true;
}
}
return false;
}
///
/// Returns a random transform matrix given the random transform rule.
///
/// Random transform rule.
/// The original transform matrix.
/// The Perlin Scale factor of the Tile.
/// Position of the Tile on the Tilemap.
/// A random transform matrix.
public virtual Matrix4x4 ApplyRandomTransform(TilingRuleOutput.Transform type, Matrix4x4 original, float perlinScale, Vector3Int position)
{
float perlin = GetPerlinValue(position, perlinScale, 200000f);
switch (type)
{
case TilingRuleOutput.Transform.MirrorXY:
return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(Math.Abs(perlin - 0.5) > 0.25 ? 1f : -1f, perlin < 0.5 ? 1f : -1f, 1f));
case TilingRuleOutput.Transform.MirrorX:
return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(perlin < 0.5 ? 1f : -1f, 1f, 1f));
case TilingRuleOutput.Transform.MirrorY:
return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, perlin < 0.5 ? 1f : -1f, 1f));
case TilingRuleOutput.Transform.Rotated:
int angle = Mathf.Clamp(Mathf.FloorToInt(perlin * m_RotationCount), 0, m_RotationCount - 1) * m_RotationAngle;
return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
}
return original;
}
///
/// Returns custom fields for this RuleTile
///
/// Whether override fields are returned
/// Custom fields for this RuleTile
public FieldInfo[] GetCustomFields(bool isOverrideInstance)
{
return this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
.Where(field => typeof(RuleTile).GetField(field.Name) == null)
.Where(field => field.IsPublic || field.IsDefined(typeof(SerializeField)))
.Where(field => !field.IsDefined(typeof(HideInInspector)))
.Where(field => !isOverrideInstance || !field.IsDefined(typeof(DontOverride)))
.ToArray();
}
///
/// Checks if there is a match given the neighbor matching rule and a Tile.
///
/// Neighbor matching rule.
/// Tile to match.
/// True if there is a match, False if not.
public virtual bool RuleMatch(int neighbor, TileBase other)
{
if (other is RuleOverrideTile ot)
other = ot.m_InstanceTile;
switch (neighbor)
{
case TilingRuleOutput.Neighbor.This: return other == this;
case TilingRuleOutput.Neighbor.NotThis: return other != this;
}
return true;
}
///
/// Checks if there is a match given the neighbor matching rule and a Tile with a rotation angle.
///
/// Neighbor matching rule.
/// Position of the Tile on the Tilemap.
/// Tilemap to match.
/// Rotation angle for matching.
/// True if there is a match, False if not.
public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, int angle)
{
var minCount = Math.Min(rule.m_Neighbors.Count, rule.m_NeighborPositions.Count);
for (int i = 0; i < minCount ; i++)
{
int neighbor = rule.m_Neighbors[i];
Vector3Int positionOffset = GetRotatedPosition(rule.m_NeighborPositions[i], angle);
TileBase other = tilemap.GetTile(GetOffsetPosition(position, positionOffset));
if (!RuleMatch(neighbor, other))
{
return false;
}
}
return true;
}
///
/// Checks if there is a match given the neighbor matching rule and a Tile with mirrored axii.
///
/// Neighbor matching rule.
/// Position of the Tile on the Tilemap.
/// Tilemap to match.
/// Mirror X Axis for matching.
/// Mirror Y Axis for matching.
/// True if there is a match, False if not.
public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, bool mirrorX, bool mirrorY)
{
var minCount = Math.Min(rule.m_Neighbors.Count, rule.m_NeighborPositions.Count);
for (int i = 0; i < minCount; i++)
{
int neighbor = rule.m_Neighbors[i];
Vector3Int positionOffset = GetMirroredPosition(rule.m_NeighborPositions[i], mirrorX, mirrorY);
TileBase other = tilemap.GetTile(GetOffsetPosition(position, positionOffset));
if (!RuleMatch(neighbor, other))
{
return false;
}
}
return true;
}
///
/// Gets a rotated position given its original position and the rotation in degrees.
///
/// Original position of Tile.
/// Rotation in degrees.
/// Rotated position of Tile.
public virtual Vector3Int GetRotatedPosition(Vector3Int position, int rotation)
{
switch (rotation)
{
case 0:
return position;
case 90:
return new Vector3Int(position.y, -position.x, 0);
case 180:
return new Vector3Int(-position.x, -position.y, 0);
case 270:
return new Vector3Int(-position.y, position.x, 0);
}
return position;
}
///
/// Gets a mirrored position given its original position and the mirroring axii.
///
/// Original position of Tile.
/// Mirror in the X Axis.
/// Mirror in the Y Axis.
/// Mirrored position of Tile.
public virtual Vector3Int GetMirroredPosition(Vector3Int position, bool mirrorX, bool mirrorY)
{
if (mirrorX)
position.x *= -1;
if (mirrorY)
position.y *= -1;
return position;
}
///
/// Get the offset for the given position with the given offset.
///
/// Position to offset.
/// Offset for the position.
/// The offset position.
public virtual Vector3Int GetOffsetPosition(Vector3Int position, Vector3Int offset)
{
return position + offset;
}
///
/// Get the reversed offset for the given position with the given offset.
///
/// Position to offset.
/// Offset for the position.
/// The reversed offset position.
public virtual Vector3Int GetOffsetPositionReverse(Vector3Int position, Vector3Int offset)
{
return position - offset;
}
}
}