Skip to content

Instantly share code, notes, and snippets.

@ruccho
Created February 17, 2018 10:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ruccho/944e21922e24b35b4245570a230b1b15 to your computer and use it in GitHub Desktop.
Save ruccho/944e21922e24b35b4245570a230b1b15 to your computer and use it in GitHub Desktop.
An extension for Unity Tilemap.(Compatible with animation)
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Tilemaps
{
[Serializable]
public class WolfAutoTile : TileBase
{
[SerializeField]
public Sprite[] m_RawTilesSprites;
public Sprite[][] m_PatternedSprites;
[NonSerialized]
public Sprite[] m_AnimatedSprites;
public float m_MinSpeed = 1f;
public float m_MaxSpeed = 1f;
public float m_AnimationStartTime;
private void OnEnable()
{
if (m_PatternedSprites == null)
{
m_PatternedSprites = new Sprite[m_RawTilesSprites.Length / 5][];
if (m_RawTilesSprites != null)
{
for (int i = 0; i < m_RawTilesSprites.Length / 5; i++)
{
GeneratePatterns(i);
}
}
}
}
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);
}
}
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
{
if(m_AnimatedSprites == null)
{
return false;
}else
{
tileAnimationData.animatedSprites = m_AnimatedSprites;
tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
tileAnimationData.animationStartTime = m_AnimationStartTime;
return true;
}
}
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
UpdateTile(location, tileMap, ref tileData);
return;
}
private void BuildAnimatedSpritesArray(int index)
{
int frameCount = m_PatternedSprites.Length;
m_AnimatedSprites = new Sprite[frameCount];
for(int i = 0; i < frameCount; i++)
{
m_AnimatedSprites[i] = m_PatternedSprites[i][index];
}
}
private void UpdateTile(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
if (m_PatternedSprites == null)
{
if (m_RawTilesSprites != null)
{
for (int i = 0; i < m_RawTilesSprites.Length / 5; i++)
{
GeneratePatterns(i);
}
}
return;
}
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;
int index = GetIndex((byte)mask);
int frame = 0;
if (index >= 0 && index < m_PatternedSprites[frame].Length && TileValue(tileMap, location))
{
tileData.sprite = m_PatternedSprites[frame][index];
tileData.color = Color.white;
tileData.flags = (TileFlags.LockTransform | TileFlags.LockColor);
tileData.colliderType = Tile.ColliderType.Sprite;
}
int frameCount = m_PatternedSprites.Length;
if(frameCount > 1)
{
BuildAnimatedSpritesArray(index);
}else
{
m_AnimatedSprites = null;
}
}
private bool TileValue(ITilemap tileMap, Vector3Int position)
{
TileBase tile = tileMap.GetTile(position);
return (tile != null && tile == this);
}
private int GetIndex(byte mask)
{
string[] patternTexts = {
"x0x111x0",
"x11111x0",
"x111x0x0",
"x10111x0",
"x11101x0",
"01111111",
"11111101",
"x0x1x0x0",
"x0x11111",
"11111111",
"1111x0x1",
"x0x10111",
"1101x0x1",
"11011111",
"11110111",
"x0x1x0x1",
"x0x0x111",
"11x0x111",
"11x0x0x1",
"x0x11101",
"0111x0x1",
"01110111",
"11011101",
"x0x0x0x1",
"x0x101x0",
"x10101x0",
"x101x0x0",
"01x0x111",
"11x0x101",
"11010101",
"01010111",
"11010111",
"x0x10101",
"01010101",
"0101x0x1",
"11110101",
"01011111",
"01110101",
"01011101",
"01111101",
"x0x0x101",
"01x0x101",
"01x0x0x1",
"x0x0x1x0",
"x1x0x1x0",
"x1x0x0x0",
"x0x0x0x0"
};
int index = -1;
for (int j = 0; j < patternTexts.Length; j++)
{
bool flag = true;
for (int i = 0; i < 8; i++)
{
if (patternTexts[j][i] != 'x')
{
char currentBitChar = ((mask & (byte)Mathf.Pow(2, 7 - i)) != 0) ? '1' : '0';
if (patternTexts[j][i] != currentBitChar)
{
flag = false;
break;
}
}
}
if (flag)
{
index = j;
break;
}
}
return index;
}
Sprite[,] Segments = new Sprite[5, 4];
int[][] Patterns = new int[][]
{
new int[] {0,2,1,4},
new int[] {2,2,4,4},
new int[] {2,0,4,1},
new int[] {2,2,3,4},
new int[] {2,2,4,3},
new int[] {3,4,4,4},
new int[] {4,3,4,4},
new int[] {0,0,1,1},
new int[] {1,4,1,4},
new int[] {4,4,4,4},
new int[] {4,1,4,1},
new int[] {1,4,1,3},
new int[] {4,1,3,1},
new int[] {4,4,3,4},
new int[] {4,4,4,3},
new int[] {1,1,1,1},
new int[] {1,4,0,2},
new int[] {4,4,2,2},
new int[] {4,1,2,0},
new int[] {1,3,1,4},
new int[] {3,1,4,1},
new int[] {3,4,4,3},
new int[] {4,3,3,4},
new int[] {1,1,0,0},
new int[] {0,2,1,3},
new int[] {2,2,3,3},
new int[] {2,0,3,1},
new int[] {3,4,2,2},
new int[] {4,3,2,2},
new int[] {4,3,3,3},
new int[] {3,4,3,3},
new int[] {4,4,3,3},
new int[] {1,3,1,3},
new int[] {3,3,3,3},
new int[] {3,1,3,1},
new int[] {4,3,4,3},
new int[] {3,4,3,4},
new int[] {3,3,4,3},
new int[] {3,3,3,4},
new int[] {3,3,4,4},
new int[] {1,3,0,2},
new int[] {3,3,2,2},
new int[] {3,1,2,0},
new int[] {0,2,0,2},
new int[] {2,2,2,2},
new int[] {2,0,2,0},
new int[] {0,0,0,0}
};
public void GeneratePatterns(int frame)
{
Segments = new Sprite[5, 4];
for (int i = 0; i < 5; i++)
{
Texture2D tex = m_RawTilesSprites[frame*5 + i].texture;
int y = (int)m_RawTilesSprites[frame * 5 + i].rect.y;
int x = (int)m_RawTilesSprites[frame * 5 + i].rect.x;
int height = (int)m_RawTilesSprites[frame * 5 + i].rect.height;
int width = (int)m_RawTilesSprites[frame * 5 + i].rect.width;
int height_half = height / 2;
int width_half = width / 2;
Segments[i, 0] = Sprite.Create(tex, new Rect(x, y, width_half, height_half), Vector2.zero);
Segments[i, 1] = Sprite.Create(tex, new Rect(x + width_half, y, width_half, height_half), Vector2.zero);
Segments[i, 2] = Sprite.Create(tex, new Rect(x, y + height_half, width_half, height_half), Vector2.zero);
Segments[i, 3] = Sprite.Create(tex, new Rect(x + width_half, y + height_half, width_half, height_half), Vector2.zero);
}
m_PatternedSprites[frame] = new Sprite[47];
for (int i = 0; i < 47; i++)
{
m_PatternedSprites[frame][i] = CombineTextures(Patterns[i]);
}
}
private Sprite CombineTextures(int[] TypeIndex)
{
int[] fixedArray = new int[4];
fixedArray[0] = TypeIndex[2];
fixedArray[1] = TypeIndex[3];
fixedArray[2] = TypeIndex[0];
fixedArray[3] = TypeIndex[1];
Color[][] texs = new Color[4][];
for (int i = 0; i < 4; i++)
{
int x = (int)Segments[fixedArray[i], i].rect.x;
int y = (int)Segments[fixedArray[i], i].rect.y;
int w = (int)Segments[fixedArray[i], i].rect.width;
int h = (int)Segments[fixedArray[i], i].rect.height;
texs[i] = Segments[fixedArray[i], i].texture.GetPixels(x, y, w, h);
}
int width_half = (int)Segments[0, 0].rect.width;
int height_half = (int)Segments[0, 0].rect.height;
int width = width_half * 2;
int height = height_half * 2;
Color[] texArray = new Color[width * height];
for (int i = 0; i < height_half; i++)
{
Array.Copy(texs[0], i * width_half, texArray, i * width, width_half);
}
for (int i = 0; i < height_half; i++)
{
Array.Copy(texs[1], i * width_half, texArray, i * width + width_half, width_half);
}
for (int i = 0; i < height_half; i++)
{
Array.Copy(texs[2], i * width_half, texArray, (i + height_half) * width, width_half);
}
for (int i = 0; i < height_half; i++)
{
Array.Copy(texs[3], i * width_half, texArray, (i + height_half) * width + width_half, width_half);
}
Texture2D ret = new Texture2D(width, height, TextureFormat.ARGB32, false);
ret.filterMode = FilterMode.Point;
ret.wrapMode = TextureWrapMode.Clamp;
ret.SetPixels(texArray);
return Sprite.Create(ret, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f), width);
}
#if UNITY_EDITOR
[MenuItem("Assets/Create/WolfAuto Tile")]
public static void CreateTerrainTile()
{
string path = EditorUtility.SaveFilePanelInProject("Save WolfAuto Tile", "New WolfAuto Tile", "asset", "Save WolfAuto Tile", "Assets");
if (path == "")
return;
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<WolfAutoTile>(), path);
}
#endif
}
#if UNITY_EDITOR
[CustomEditor(typeof(WolfAutoTile))]
public class WolfAutoTileEditor : Editor
{
private WolfAutoTile tile { get { return (target as WolfAutoTile); } }
public void OnEnable()
{
if (tile.m_RawTilesSprites == null)
{
tile.m_RawTilesSprites = new Sprite[5];
}
if(tile.m_PatternedSprites == null)
{
tile.m_PatternedSprites = new Sprite[1][];
if(tile.m_RawTilesSprites != null)
{
for (int i = 0; i < tile.m_RawTilesSprites.Length / 5; i++)
{
tile.GeneratePatterns(i);
}
}
}
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
float minSpeed = EditorGUILayout.FloatField("Minimum Speed", tile.m_MinSpeed);
float maxSpeed = EditorGUILayout.FloatField("Maximum Speed", tile.m_MaxSpeed);
if (minSpeed < 0.0f)
minSpeed = 0.0f;
if (maxSpeed < 0.0f)
maxSpeed = 0.0f;
if (maxSpeed < minSpeed)
maxSpeed = minSpeed;
tile.m_MinSpeed = minSpeed;
tile.m_MaxSpeed = maxSpeed;
tile.m_AnimationStartTime = EditorGUILayout.FloatField("Start Time", tile.m_AnimationStartTime);
EditorGUILayout.LabelField("Set auto tile chips of WOLF RPG Editor standard in order from the top");
EditorGUILayout.Space();
float oldLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 210;
int count = EditorGUILayout.DelayedIntField("Number of Animated Sprites", tile.m_RawTilesSprites != null ? tile.m_RawTilesSprites.Length / 5 : 0);
if (count < 0)
count = 0;
if (tile.m_RawTilesSprites == null || tile.m_RawTilesSprites.Length != count * 5)
{
Array.Resize<Sprite>(ref tile.m_RawTilesSprites, count * 5);
}
if (count == 0)
return;
if (GUILayout.Button("GENERATE!"))
{
for (int i = 0; i < count; i++)
{
Array.Resize<Sprite[]>(ref tile.m_PatternedSprites, count);
tile.GeneratePatterns(i);
}
}
for (int i = 0; i < count; i++)
{
EditorGUILayout.LabelField("上下左右どこにもこのオートタイルがない(直角に配置したときの外側の角に現れる)");
EditorGUILayout.LabelField("×××");
EditorGUILayout.LabelField("×■×");
EditorGUILayout.LabelField("×××");
tile.m_RawTilesSprites[i * 5] = (Sprite)EditorGUILayout.ObjectField("", tile.m_RawTilesSprites[i*5], typeof(Sprite), false, null);
EditorGUILayout.LabelField("上下にこのオートタイルがある");
EditorGUILayout.LabelField("×□×");
EditorGUILayout.LabelField("×■×");
EditorGUILayout.LabelField("×□×");
tile.m_RawTilesSprites[i * 5 + 1] = (Sprite)EditorGUILayout.ObjectField("", tile.m_RawTilesSprites[i * 5 + 1], typeof(Sprite), false, null);
EditorGUILayout.LabelField("左右にこのオートタイルがある");
EditorGUILayout.LabelField("×××");
EditorGUILayout.LabelField("□■□");
EditorGUILayout.LabelField("×××");
tile.m_RawTilesSprites[i * 5 + 2] = (Sprite)EditorGUILayout.ObjectField("", tile.m_RawTilesSprites[i * 5 + 2], typeof(Sprite), false, null);
EditorGUILayout.LabelField("直角にこのオートタイルを配置したとき、内側の角に現れる");
EditorGUILayout.LabelField("×□×");
EditorGUILayout.LabelField("□■□");
EditorGUILayout.LabelField("×□×");
tile.m_RawTilesSprites[i * 5 + 3] = (Sprite)EditorGUILayout.ObjectField("", tile.m_RawTilesSprites[i * 5 + 3], typeof(Sprite), false, null);
EditorGUILayout.LabelField("このオートタイルに周囲を全て囲まれている");
EditorGUILayout.LabelField("□□□");
EditorGUILayout.LabelField("□■□");
EditorGUILayout.LabelField("□□□");
tile.m_RawTilesSprites[i * 5 + 4] = (Sprite)EditorGUILayout.ObjectField("", tile.m_RawTilesSprites[i * 5 + 4], typeof(Sprite), false, null);
}
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(tile);
}
EditorGUIUtility.labelWidth = oldLabelWidth;
}
}
#endif
}
@SimonDarksideJ
Copy link

Can you detail or link to a post as to what this script achieves please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment