Singularity/Library/PackageCache/com.unity.2d.tilemap.extras.../Runtime/Tiles/AnimatedTile/AnimatedTile.cs

388 lines
16 KiB
C#
Raw Permalink Normal View History

2024-05-06 14:45:45 -04:00
using System;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using System.Linq;
#endif
namespace UnityEngine.Tilemaps
{
/// <summary>
/// Animated Tiles are tiles which run through and display a list of sprites in sequence.
/// </summary>
[Serializable]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.tilemap.extras@latest/index.html?subfolder=/manual/AnimatedTile.html")]
public class AnimatedTile : TileBase
{
/// <summary>
/// The List of Sprites set for the Animated Tile.
/// This will be played in sequence.
/// </summary>
public Sprite[] m_AnimatedSprites;
/// <summary>
/// The minimum possible speed at which the Animation of the Tile will be played.
/// A speed value will be randomly chosen between the minimum and maximum speed.
/// </summary>
public float m_MinSpeed = 1f;
/// <summary>
/// The maximum possible speed at which the Animation of the Tile will be played.
/// A speed value will be randomly chosen between the minimum and maximum speed.
/// </summary>
public float m_MaxSpeed = 1f;
/// <summary>
/// The starting time of this Animated Tile.
/// This allows you to start the Animation from time in the list of Animated Sprites depending on the
/// Tilemap's Animation Frame Rate.
/// </summary>
public float m_AnimationStartTime;
/// <summary>
/// The starting frame of this Animated Tile.
/// This allows you to start the Animation from a particular Sprite in the list of Animated Sprites.
/// If this is set, this overrides m_AnimationStartTime.
/// </summary>
public int m_AnimationStartFrame = 0;
/// <summary>
/// The Collider Shape generated by the Tile.
/// </summary>
public Tile.ColliderType m_TileColliderType;
/// <summary>
/// Retrieves any tile rendering data from the scripted tile.
/// </summary>
/// <param name="position">Position of the Tile on the Tilemap.</param>
/// <param name="tilemap">The Tilemap the tile is present on.</param>
/// <param name="tileData">Data to render the tile.</param>
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
tileData.transform = Matrix4x4.identity;
tileData.color = Color.white;
if (m_AnimatedSprites != null && m_AnimatedSprites.Length > 0)
{
tileData.sprite = m_AnimatedSprites[m_AnimatedSprites.Length - 1];
tileData.colliderType = m_TileColliderType;
}
}
/// <summary>
/// Retrieves any tile animation data from the scripted tile.
/// </summary>
/// <param name="position">Position of the Tile on the Tilemap.</param>
/// <param name="tilemap">The Tilemap the tile is present on.</param>
/// <param name="tileAnimationData">Data to run an animation on the tile.</param>
/// <returns>Whether the call was successful.</returns>
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
{
if (m_AnimatedSprites.Length > 0)
{
tileAnimationData.animatedSprites = m_AnimatedSprites;
tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
tileAnimationData.animationStartTime = m_AnimationStartTime;
if (0 < m_AnimationStartFrame && m_AnimationStartFrame <= m_AnimatedSprites.Length)
{
var tilemapComponent = tilemap.GetComponent<Tilemap>();
if (tilemapComponent != null && tilemapComponent.animationFrameRate > 0)
tileAnimationData.animationStartTime = (m_AnimationStartFrame - 1) / tilemapComponent.animationFrameRate;
}
return true;
}
return false;
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(AnimatedTile))]
public class AnimatedTileEditor : Editor
{
private static class Styles
{
public static readonly GUIContent orderAnimatedTileSpritesInfo =
EditorGUIUtility.TrTextContent("Place sprites shown based on the order of animation.");
public static readonly GUIContent emptyAnimatedTileInfo =
EditorGUIUtility.TrTextContent(
"Drag Sprite or Sprite Texture assets \n" +
" to start creating an Animated Tile.");
public static readonly GUIContent minimumSpeedLabel = EditorGUIUtility.TrTextContent("Minimum Speed",
"The minimum possible speed at which the Animation of the Tile will be played. A speed value will be randomly chosen between the minimum and maximum speed.");
public static readonly GUIContent maximumSpeedLabel = EditorGUIUtility.TrTextContent("Maximum Speed",
"The maximum possible speed at which the Animation of the Tile will be played. A speed value will be randomly chosen between the minimum and maximum speed.");
public static readonly GUIContent startTimeLabel = EditorGUIUtility.TrTextContent("Start Time", "The starting time of this Animated Tile. This allows you to start the Animation from a particular time.");
public static readonly GUIContent startFrameLabel = EditorGUIUtility.TrTextContent("Start Frame", "The starting frame of this Animated Tile. This allows you to start the Animation from a particular Sprite in the list of Animated Sprites.");
public static readonly GUIContent colliderTypeLabel = EditorGUIUtility.TrTextContent("Collider Type", "The Collider Shape generated by the Tile.");
}
private static readonly string k_UndoName = L10n.Tr("Change AnimatedTile");
private SerializedProperty m_AnimatedSprites;
private AnimatedTile tile { get { return (target as AnimatedTile); } }
private List<Sprite> dragAndDropSprites;
private ReorderableList reorderableList;
private void OnEnable()
{
reorderableList = new ReorderableList(tile.m_AnimatedSprites, typeof(Sprite), true, true, true, true);
reorderableList.drawHeaderCallback = OnDrawHeader;
reorderableList.drawElementCallback = OnDrawElement;
reorderableList.elementHeightCallback = GetElementHeight;
reorderableList.onAddCallback = OnAddElement;
reorderableList.onRemoveCallback = OnRemoveElement;
reorderableList.onReorderCallback = OnReorderElement;
m_AnimatedSprites = serializedObject.FindProperty("m_AnimatedSprites");
}
private void OnDrawHeader(Rect rect)
{
GUI.Label(rect, Styles.orderAnimatedTileSpritesInfo);
}
private void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
if (tile.m_AnimatedSprites != null && index < tile.m_AnimatedSprites.Length)
{
var spriteName = tile.m_AnimatedSprites[index] != null ? tile.m_AnimatedSprites[index].name : "Null";
tile.m_AnimatedSprites[index] = (Sprite) EditorGUI.ObjectField(rect
, $"Sprite {index + 1}: {spriteName}"
, tile.m_AnimatedSprites[index]
, typeof(Sprite)
, false);
}
}
private float GetElementHeight(int index)
{
return 3 * EditorGUI.GetPropertyHeight(SerializedPropertyType.ObjectReference,
null);
}
private void OnAddElement(ReorderableList list)
{
var count = tile.m_AnimatedSprites != null ? tile.m_AnimatedSprites.Length + 1 : 1;
ResizeAnimatedSpriteList(count);
if (list.index == 0 || list.index < list.count)
{
Array.Copy(tile.m_AnimatedSprites, list.index + 1, tile.m_AnimatedSprites, list.index + 2, list.count - list.index - 1);
tile.m_AnimatedSprites[list.index + 1] = null;
if (list.IsSelected(list.index))
list.index += 1;
}
else
{
tile.m_AnimatedSprites[count - 1] = null;
}
}
private void OnRemoveElement(ReorderableList list)
{
if (tile.m_AnimatedSprites != null && tile.m_AnimatedSprites.Length > 0 && list.index < tile.m_AnimatedSprites.Length)
{
var sprites = tile.m_AnimatedSprites.ToList();
sprites.RemoveAt(list.index);
tile.m_AnimatedSprites = sprites.ToArray();
}
}
private void OnReorderElement(ReorderableList list)
{
// Fix for 2020.1, which does not track changes when reordering in the list
EditorUtility.SetDirty(tile);
}
private void DisplayClipboardText(GUIContent clipboardText, Rect position)
{
Color old = GUI.color;
GUI.color = Color.gray;
var infoSize = GUI.skin.label.CalcSize(clipboardText);
Rect rect = new Rect(position.center.x - infoSize.x * .5f
, position.center.y - infoSize.y * .5f
, infoSize.x
, infoSize.y);
GUI.Label(rect, clipboardText);
GUI.color = old;
}
private bool dragAndDropActive
{
get
{
return dragAndDropSprites != null
&& dragAndDropSprites.Count > 0;
}
}
private void DragAndDropClear()
{
dragAndDropSprites = null;
DragAndDrop.visualMode = DragAndDropVisualMode.None;
Event.current.Use();
}
private static List<Sprite> GetSpritesFromTexture(Texture2D texture)
{
string path = AssetDatabase.GetAssetPath(texture);
Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path);
List<Sprite> sprites = new List<Sprite>();
foreach (Object asset in assets)
{
if (asset is Sprite)
{
sprites.Add(asset as Sprite);
}
}
return sprites;
}
private static List<Sprite> GetValidSingleSprites(Object[] objects)
{
List<Sprite> result = new List<Sprite>();
foreach (Object obj in objects)
{
if (obj is Sprite)
{
result.Add(obj as Sprite);
}
else if (obj is Texture2D)
{
Texture2D texture = obj as Texture2D;
List<Sprite> sprites = GetSpritesFromTexture(texture);
if (sprites.Count > 0)
{
result.AddRange(sprites);
}
}
}
return result;
}
private void HandleDragAndDrop(Rect guiRect)
{
if (DragAndDrop.objectReferences.Length == 0 || !guiRect.Contains(Event.current.mousePosition))
return;
switch (Event.current.type)
{
case EventType.DragUpdated:
{
dragAndDropSprites = GetValidSingleSprites(DragAndDrop.objectReferences);
if (dragAndDropActive)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
Event.current.Use();
GUI.changed = true;
}
}
break;
case EventType.DragPerform:
{
if (!dragAndDropActive)
return;
Undo.RegisterCompleteObjectUndo(tile, "Drag and Drop to Animated Tile");
ResizeAnimatedSpriteList(dragAndDropSprites.Count);
Array.Copy(dragAndDropSprites.ToArray(), tile.m_AnimatedSprites, dragAndDropSprites.Count);
DragAndDropClear();
GUI.changed = true;
EditorUtility.SetDirty(tile);
GUIUtility.ExitGUI();
}
break;
case EventType.Repaint:
// Handled in Render()
break;
}
if (Event.current.type == EventType.DragExited ||
Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
{
DragAndDropClear();
}
}
/// <summary>
/// Draws an Inspector for the AnimatedTile.
/// </summary>
public override void OnInspectorGUI()
{
serializedObject.Update();
Undo.RecordObject(tile, k_UndoName);
EditorGUI.BeginChangeCheck();
int count = EditorGUILayout.DelayedIntField("Number of Animated Sprites", tile.m_AnimatedSprites != null ? tile.m_AnimatedSprites.Length : 0);
if (count < 0)
count = 0;
if (tile.m_AnimatedSprites == null || tile.m_AnimatedSprites.Length != count)
ResizeAnimatedSpriteList(count);
if (count == 0)
{
Rect rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight * 5);
HandleDragAndDrop(rect);
EditorGUI.DrawRect(rect, dragAndDropActive && rect.Contains(Event.current.mousePosition) ? Color.white : Color.black);
var innerRect = new Rect(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2);
EditorGUI.DrawRect(innerRect, EditorGUIUtility.isProSkin
? (Color) new Color32 (56, 56, 56, 255)
: (Color) new Color32 (194, 194, 194, 255));
DisplayClipboardText(Styles.emptyAnimatedTileInfo, rect);
GUILayout.Space(rect.height);
EditorGUILayout.Space();
}
if (reorderableList != null)
{
var tileCount = tile.m_AnimatedSprites != null ? tile.m_AnimatedSprites.Length : 0;
if (reorderableList.list == null || reorderableList.count != tileCount)
reorderableList.list = tile.m_AnimatedSprites;
reorderableList.DoLayoutList();
}
using (new EditorGUI.DisabledScope(tile.m_AnimatedSprites == null || tile.m_AnimatedSprites.Length == 0))
{
float minSpeed = EditorGUILayout.FloatField(Styles.minimumSpeedLabel, tile.m_MinSpeed);
float maxSpeed = EditorGUILayout.FloatField(Styles.maximumSpeedLabel, 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;
using (new EditorGUI.DisabledScope(tile.m_AnimatedSprites == null
|| (0 < tile.m_AnimationStartFrame
&& tile.m_AnimationStartFrame <= tile.m_AnimatedSprites.Length)))
{
tile.m_AnimationStartTime = EditorGUILayout.FloatField(Styles.startTimeLabel, tile.m_AnimationStartTime);
}
tile.m_AnimationStartFrame = EditorGUILayout.IntField(Styles.startFrameLabel, tile.m_AnimationStartFrame);
tile.m_TileColliderType = (Tile.ColliderType) EditorGUILayout.EnumPopup(Styles.colliderTypeLabel, tile.m_TileColliderType);
}
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(tile);
}
}
private void ResizeAnimatedSpriteList(int count)
{
m_AnimatedSprites.arraySize = count;
serializedObject.ApplyModifiedProperties();
}
}
#endif
}