IKManager2DEditor.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using UnityEditorInternal;
  2. using UnityEngine;
  3. using UnityEngine.U2D.IK;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Reflection;
  7. using System.Linq;
  8. using UnityEditor.U2D.Animation;
  9. namespace UnityEditor.U2D.IK
  10. {
  11. /// <summary>
  12. /// Custom Inspector for IKManager2D.
  13. /// </summary>
  14. [CustomEditor(typeof(IKManager2D))]
  15. [CanEditMultipleObjects]
  16. class IKManager2DEditor : Editor
  17. {
  18. private class Contents
  19. {
  20. public static readonly GUIContent findAllSolversLabel = new GUIContent("Find Solvers", "Find all applicable solvers handled by this manager");
  21. public static readonly GUIContent weightLabel = new GUIContent("Weight", "Blend between Forward and Inverse Kinematics");
  22. public static readonly string listHeaderLabel = "IK Solvers";
  23. public static readonly string createSolverString = "Create Solver";
  24. public static readonly string restoreDefaultPoseString = "Restore Default Pose";
  25. public static readonly GUIContent gizmoColorTooltip = new GUIContent("","Customizes the IK Chain's Gizmo color");
  26. public static int showGizmoPropertyWidth = 20;
  27. public static int solverPropertyWidth = 100;
  28. public static int solverColorPropertyWidth = 40;
  29. public static readonly GUIContent gizmoVisibilityToolTip = new GUIContent("",L10n.Tr("Show/Hide Gizmo"));
  30. public readonly GUIStyle visibilityToggleStyle;
  31. public Contents()
  32. {
  33. visibilityToggleStyle = new GUIStyle();
  34. visibilityToggleStyle.fixedWidth = EditorGUIUtility.singleLineHeight;
  35. visibilityToggleStyle.onNormal.background = IconUtility.LoadIconResource("Visibility_Tool", IconUtility.k_LightIconResourcePath, IconUtility.k_DarkIconResourcePath);
  36. visibilityToggleStyle.normal.background = IconUtility.LoadIconResource("Visibility_Hidded", IconUtility.k_LightIconResourcePath, IconUtility.k_DarkIconResourcePath);
  37. }
  38. }
  39. static Contents k_Contents;
  40. private ReorderableList m_ReorderableList;
  41. private Solver2D m_SelectedSolver;
  42. private Editor m_SelectedSolverEditor;
  43. SerializedProperty m_SolversProperty;
  44. SerializedProperty m_SolverEditorDataProperty;
  45. SerializedProperty m_WeightProperty;
  46. List<Type> m_SolverTypes;
  47. IKManager2D m_Manager;
  48. private void OnEnable()
  49. {
  50. m_Manager = target as IKManager2D;
  51. m_SolverTypes = GetDerivedTypes<Solver2D>();
  52. m_SolversProperty = serializedObject.FindProperty("m_Solvers");
  53. m_SolverEditorDataProperty = serializedObject.FindProperty("m_SolverEditorData");
  54. m_WeightProperty = serializedObject.FindProperty("m_Weight");
  55. SetupReordeableList();
  56. }
  57. void SetupReordeableList()
  58. {
  59. m_ReorderableList = new ReorderableList(serializedObject, m_SolversProperty, true, true, true, true);
  60. m_ReorderableList.drawHeaderCallback = (Rect rect) =>
  61. {
  62. GUI.Label(rect, Contents.listHeaderLabel);
  63. };
  64. m_ReorderableList.elementHeightCallback = (int index) =>
  65. {
  66. return EditorGUIUtility.singleLineHeight + 6;
  67. };
  68. m_ReorderableList.drawElementCallback = (Rect rect, int index, bool isactive, bool isfocused) =>
  69. {
  70. rect.y += 2f;
  71. rect.height = EditorGUIUtility.singleLineHeight;
  72. SerializedProperty element = m_SolversProperty.GetArrayElementAtIndex(index);
  73. SerializedProperty elementData = m_SolverEditorDataProperty.GetArrayElementAtIndex(index);
  74. var width = rect.width;
  75. rect.width = width > Contents.showGizmoPropertyWidth ? Contents.showGizmoPropertyWidth : width;
  76. var showGizmoProperty = elementData.FindPropertyRelative("showGizmo");
  77. showGizmoProperty.boolValue = GUI.Toggle(rect, showGizmoProperty.boolValue, Contents.gizmoVisibilityToolTip, k_Contents.visibilityToggleStyle);
  78. rect.x += rect.width;
  79. width -= rect.width;
  80. rect.width = width > Contents.solverPropertyWidth ? width - Contents.solverColorPropertyWidth : Contents.solverPropertyWidth;
  81. EditorGUI.PropertyField(rect, element, GUIContent.none);
  82. rect.x += rect.width;
  83. width -= 100;
  84. rect.width = width > Contents.solverColorPropertyWidth ? Contents.solverColorPropertyWidth : width;
  85. EditorGUI.PropertyField(rect, elementData.FindPropertyRelative("color"), Contents.gizmoColorTooltip);
  86. };
  87. m_ReorderableList.onAddCallback = (ReorderableList list) =>
  88. {
  89. var menu = new GenericMenu();
  90. foreach (Type type in m_SolverTypes)
  91. {
  92. Solver2DMenuAttribute attribute = Attribute.GetCustomAttribute(type, typeof(Solver2DMenuAttribute)) as Solver2DMenuAttribute;
  93. if (attribute != null)
  94. menu.AddItem(new GUIContent(attribute.menuPath), false, OnSelectMenu, type);
  95. else
  96. menu.AddItem(new GUIContent(type.Name), false, OnSelectMenu, type);
  97. }
  98. menu.ShowAsContext();
  99. };
  100. m_ReorderableList.onRemoveCallback = (ReorderableList list) =>
  101. {
  102. Solver2D solver = m_Manager.solvers[list.index];
  103. if (solver)
  104. {
  105. Undo.RegisterCompleteObjectUndo(m_Manager, Undo.GetCurrentGroupName());
  106. m_Manager.RemoveSolver(solver);
  107. GameObject solverGO = solver.gameObject;
  108. if (solverGO.transform.childCount == 0)
  109. Undo.DestroyObjectImmediate(solverGO);
  110. else
  111. Undo.DestroyObjectImmediate(solver);
  112. EditorUtility.SetDirty(m_Manager);
  113. }
  114. else
  115. {
  116. ReorderableList.defaultBehaviours.DoRemoveButton(list);
  117. }
  118. };
  119. }
  120. private void OnSelectMenu(object param)
  121. {
  122. Type solverType = param as Type;
  123. GameObject solverGO = new GameObject(GameObjectUtility.GetUniqueNameForSibling(m_Manager.transform, "New " + solverType.Name));
  124. solverGO.transform.SetParent(m_Manager.transform);
  125. solverGO.transform.localPosition = Vector3.zero;
  126. solverGO.transform.rotation = Quaternion.identity;
  127. solverGO.transform.localScale = Vector3.one;
  128. Solver2D solver = solverGO.AddComponent(solverType) as Solver2D;
  129. Undo.RegisterCreatedObjectUndo(solverGO, Contents.createSolverString);
  130. Undo.RegisterCompleteObjectUndo(m_Manager, Contents.createSolverString);
  131. m_Manager.AddSolver(solver);
  132. EditorUtility.SetDirty(m_Manager);
  133. Selection.activeGameObject = solverGO;
  134. }
  135. /// <summary>
  136. /// Custom Inspector OnInspectorGUI override.
  137. /// </summary>
  138. public override void OnInspectorGUI()
  139. {
  140. if(k_Contents == null)
  141. k_Contents = new Contents();
  142. serializedObject.Update();
  143. EditorGUILayout.Space();
  144. m_ReorderableList.DoLayoutList();
  145. EditorGUILayout.Space();
  146. EditorGUILayout.PropertyField(m_WeightProperty, Contents.weightLabel);
  147. EditorGUILayout.BeginHorizontal();
  148. GUILayout.FlexibleSpace();
  149. DoRestoreDefaultPoseButton();
  150. GUILayout.FlexibleSpace();
  151. EditorGUILayout.EndHorizontal();
  152. serializedObject.ApplyModifiedProperties();
  153. }
  154. private void DoRestoreDefaultPoseButton()
  155. {
  156. if (GUILayout.Button(Contents.restoreDefaultPoseString, GUILayout.MaxWidth(150f)))
  157. {
  158. foreach (var l_target in targets)
  159. {
  160. var manager = l_target as IKManager2D;
  161. IKEditorManager.instance.Record(manager, Contents.restoreDefaultPoseString);
  162. foreach(var solver in manager.solvers)
  163. {
  164. for(int i = 0; i < solver.chainCount; ++i)
  165. {
  166. var chain = solver.GetChain(i);
  167. chain.RestoreDefaultPose(solver.constrainRotation);
  168. if(chain.target)
  169. {
  170. chain.target.position = chain.effector.position;
  171. chain.target.rotation = chain.effector.rotation;
  172. }
  173. }
  174. }
  175. IKEditorManager.instance.UpdateManagerImmediate(manager, true);
  176. }
  177. }
  178. }
  179. static List<Type> GetDerivedTypes<T>() where T : class
  180. {
  181. var assemblies = AppDomain.CurrentDomain.GetAssemblies();
  182. var derivedTypes = new List<Type>();
  183. for (var i = 0; i < assemblies.Length; ++i)
  184. {
  185. var assemblyTypes = assemblies[i].GetTypes();
  186. var types = assemblyTypes.Where(myType =>
  187. myType.IsClass &&
  188. !myType.IsAbstract &&
  189. myType.IsSubclassOf(typeof(T)));
  190. derivedTypes.AddRange(types);
  191. }
  192. return derivedTypes;
  193. }
  194. }
  195. }