using UnityEngine; using System.Linq; using System.Collections.Generic; using Lean.Common; namespace Lean.Transition { /// This class allows you to reference Transforms whose GameObjects contain transition components. /// If these transition components define TargetAlias names, then this class will also manage them in the inspector. [System.Serializable] public class LeanPlayer { [System.Serializable] public class Alias { public string Key; public Object Obj; [System.NonSerialized] public System.Type Type; } [System.Serializable] public class Entry { public Transform Root { set { root = value; } get { return root; } } [SerializeField] private Transform root; public float Speed { set { speed = value; } get { return speed; } } [SerializeField] private float speed = -1.0f; public List Aliases { get { if (aliases == null) aliases = new List(); return aliases; } } [SerializeField] private List aliases; public void AddAlias(string key, Object obj) { foreach (var alias in Aliases) { if (alias.Key == key) { alias.Key = key; return; } } aliases.Add(new Alias() { Key = key, Obj = obj }); } } // Legacy [SerializeField] private float speed = -1.0f; // Legacy [SerializeField] private List roots = null; // Legacy [SerializeField] private List aliases = null; // Legacy [SerializeField] private List targets = null; [SerializeField] private List entries; public float Speed { set { speed = value; } get { return speed; } } private static Dictionary tempAliases = new Dictionary(); public bool IsUsed { get { if (entries != null && entries.Count > 0) { foreach (var entry in entries) { if (entry.Root != null) { return true; } } } return false; } } /// This stores a list of all Transforms containing transitions that will be played, and their settings. public List Entries { get { if (entries == null) { entries = new List(); } return entries; } } public void Validate(bool validateEntries) { if (roots != null && roots.Count > 0) { Entries.Clear(); foreach (var root in roots) { if (root != null) { entries.Add(new Entry() { Root = root, Speed = speed > 0.0f ? speed : -1.0f }); } } roots.Clear(); } if (Entries.Count == 0) { entries.Add(new Entry()); } if (aliases != null && aliases.Count > 0 && targets != null && targets.Count > 0) { var min = System.Math.Min(aliases.Count, targets.Count); for (var i = 0; i < min; i++) { foreach (var entry in Entries) { entry.AddAlias(aliases[i], targets[i]); } } aliases.Clear(); targets.Clear(); } if (validateEntries == true) { foreach (var entry in Entries) { if (entry != null) { var pairs = LeanTransition.FindAllAliasTypePairs(entry.Root); // Move entry.Aliases into dictionary foreach (var alias in entry.Aliases) { tempAliases.Add(alias.Key, alias); } entry.Aliases.Clear(); // Rebuild entry.Aliases from dictionaries foreach (var pair in pairs) { Alias alias; // Use existing by set type again (it's non-serialized, so it must be set again) if (tempAliases.TryGetValue(pair.Key, out alias) == true) { alias.Type = pair.Value; entry.Aliases.Add(alias); } // Use new else { entry.Aliases.Add(new Alias() { Key = pair.Key, Type = pair.Value }); } } // Discard remaining tempAliases.Clear(); } } } } /// This method will begin all transition entries. public void Begin() { Validate(false); if (entries != null) { LeanTransition.CurrentAliases.Clear(); foreach (var entry in entries) { foreach (var alias in entry.Aliases) { LeanTransition.AddAlias(alias.Key, alias.Obj); } LeanTransition.BeginAllTransitions(entry.Root, entry.Speed); } } } } } #if UNITY_EDITOR namespace Lean.Transition.Editor { using UnityEditor; [CustomPropertyDrawer(typeof(LeanPlayer))] public class LeanPlayerDrawer : PropertyDrawer { private static Color color; private static float height; private static float heightStep; private static string title; private static string tooltip; public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { height = base.GetPropertyHeight(property, label); heightStep = height + 2.0f; ValidateAndUpdate(property.serializedObject, property); var count = 0; var sEntries = property.FindPropertyRelative("entries"); for (var i = 0; i < sEntries.arraySize; i++) { var sEntry = sEntries.GetArrayElementAtIndex(i); var sSpeed = sEntry.FindPropertyRelative("speed"); var sAliases = sEntry.FindPropertyRelative("aliases"); if (sSpeed.floatValue >= 0.0f) { count++; } count += sAliases.arraySize; count++; } return height + heightStep * System.Math.Max(0, count - 1); } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var player = LeanHelper.GetObjectFromSerializedProperty(property.serializedObject.targetObject, property); var sObject = property.serializedObject; var sEntries = property.FindPropertyRelative("entries"); DrawPlay(position, sObject); color = GUI.color; position.height = height; title = label.text; tooltip = label.tooltip; for (var i = 0; i < sEntries.arraySize; i++) { var entry = player.Entries[i]; var sEntry = sEntries.GetArrayElementAtIndex(i); var sRoot = sEntry.FindPropertyRelative("root"); var sSpeed = sEntry.FindPropertyRelative("speed"); var sAliases = sEntry.FindPropertyRelative("aliases"); var rectL = position; rectL.width = EditorGUIUtility.labelWidth - 16.0f; var rectR = position; rectR.xMin += EditorGUIUtility.labelWidth; if (Event.current.isMouse == true && Event.current.button == 1 && rectL.Contains(Event.current.mousePosition) == true) { Event.current.Use(); ShowMenu(sObject, sEntries, i, sRoot, sSpeed, title); } EditorGUI.PropertyField(position, sRoot, new GUIContent(title, tooltip)); position.y += heightStep; EditorGUI.indentLevel++; if (sSpeed.floatValue >= 0.0f) { EditorGUI.PropertyField(position, sSpeed); position.y += heightStep; } for (var j = 0; j < sAliases.arraySize; j++) { var alias = entry.Aliases[j]; var sAlias = sAliases.GetArrayElementAtIndex(j); var sKey = sAlias.FindPropertyRelative("Key"); var sObj = sAlias.FindPropertyRelative("Obj"); EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = sObj.hasMultipleDifferentValues; var obj = EditorGUI.ObjectField(position, new GUIContent(sKey.stringValue, ""), alias.Obj, alias.Type, true); position.y += heightStep; EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck() == true) { sObj.objectReferenceValue = obj; } } EditorGUI.indentLevel--; } GUI.color = color; } private void DrawPlay(Rect position, SerializedObject sObject) { var rectL = position; rectL.xMin += EditorGUIUtility.labelWidth - 15.0f; rectL.width = 14.0f; rectL.yMin += 1.0f; rectL.yMax -= 1.0f; var rectR = rectL; rectR.y -= 1.0f; if (GUI.Button(rectL, new GUIContent("", "Clicking this will play the transitions now.")) == true) { foreach (var targetObject in sObject.targetObjects) { ((LeanPlayer)fieldInfo.GetValue(targetObject)).Begin(); } } GUI.Label(rectR, "▶", EditorStyles.centeredGreyMiniLabel); } private void ShowMenu(SerializedObject sObject, SerializedProperty sEntries, int index, SerializedProperty sRoot, SerializedProperty sSpeed, string title) { var menu = new GenericMenu(); var methodPrefabs = AssetDatabase.FindAssets("t:GameObject"). Select((guid) => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid))). Where((prefab) => prefab.GetComponent() != null); var targetComponent = sObject.targetObject as Component; if (targetComponent != null) { if (sRoot.objectReferenceValue == null) { menu.AddItem(new GUIContent("Create"), false, () => { var root = new GameObject("[" + title + "]").transform; root.SetParent(targetComponent.transform, false); sRoot.objectReferenceValue = root; sObject.ApplyModifiedProperties(); Selection.activeTransform = root; }); } else { menu.AddItem(new GUIContent("Add"), false, () => { sEntries.InsertArrayElementAtIndex(index + 1); var sEntry = sEntries.GetArrayElementAtIndex(index + 1); sEntry.FindPropertyRelative("root").objectReferenceValue = null; sEntry.FindPropertyRelative("speed").floatValue = -1.0f; sEntry.FindPropertyRelative("aliases").arraySize = 0; sObject.ApplyModifiedProperties(); }); } } if (sSpeed.floatValue <= -1.0f) { menu.AddItem(new GUIContent("Speed"), false, () => { sSpeed.floatValue = 1.0f; sObject.ApplyModifiedProperties(); }); } else { menu.AddItem(new GUIContent("Speed"), true, () => { sSpeed.floatValue = -1.0f; sObject.ApplyModifiedProperties(); }); } menu.AddSeparator(""); foreach (var methodPrefab in methodPrefabs) { var root = methodPrefab.transform; menu.AddItem(new GUIContent("Prefab/" + methodPrefab.name), false, () => { sRoot.objectReferenceValue = root; sObject.ApplyModifiedProperties(); }); } menu.AddSeparator(""); menu.AddItem(new GUIContent("Remove"), false, () => { sEntries.DeleteArrayElementAtIndex(index); sObject.ApplyModifiedProperties(); }); menu.ShowAsContext(); } private void ValidateAndUpdate(SerializedObject sObject, SerializedProperty sPlayer) { sObject.ApplyModifiedProperties(); foreach (var targetObject in sObject.targetObjects) { var player = LeanHelper.GetObjectFromSerializedProperty(targetObject, sPlayer); if (player != null) { player.Validate(true); } } sObject.Update(); } } } #endif