No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IKEditorManager.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEditor.SceneManagement;
  4. using UnityEngine;
  5. using UnityEngine.U2D.Common;
  6. using UnityEngine.U2D.IK;
  7. namespace UnityEditor.U2D.IK
  8. {
  9. [DefaultExecutionOrder(-3)]
  10. internal class IKEditorManager : ScriptableObject
  11. {
  12. static IKEditorManager s_Instance;
  13. readonly HashSet<IKManager2D> m_DirtyManagers = new HashSet<IKManager2D>();
  14. readonly HashSet<IKManager2D> m_IKManagers = new HashSet<IKManager2D>();
  15. readonly Dictionary<IKChain2D, Vector3> m_ChainPositionOverrides = new Dictionary<IKChain2D, Vector3>();
  16. readonly List<Vector3> m_TargetPositions = new List<Vector3>();
  17. GameObject m_Helper;
  18. GameObject[] m_SelectedGameobjects;
  19. internal bool isDraggingATool { get; private set; }
  20. bool m_Initialized;
  21. [InitializeOnLoadMethod]
  22. static void CreateInstance()
  23. {
  24. if (s_Instance != null)
  25. return;
  26. var ikManagers = Resources.FindObjectsOfTypeAll<IKEditorManager>();
  27. if (ikManagers.Length > 0)
  28. s_Instance = ikManagers[0];
  29. else
  30. s_Instance = ScriptableObject.CreateInstance<IKEditorManager>();
  31. s_Instance.hideFlags = HideFlags.HideAndDontSave;
  32. }
  33. public static IKEditorManager instance
  34. {
  35. get
  36. {
  37. if (s_Instance == null)
  38. CreateInstance();
  39. return s_Instance;
  40. }
  41. }
  42. void OnEnable()
  43. {
  44. if (s_Instance == null)
  45. s_Instance = this;
  46. IKManager2D.onEnabledEditor += AddIKManager2D;
  47. IKManager2D.onDisabledEditor += RemoveIKManager2D;
  48. }
  49. void OnDisable()
  50. {
  51. IKManager2D.onEnabledEditor -= AddIKManager2D;
  52. IKManager2D.onDisabledEditor -= RemoveIKManager2D;
  53. Dispose();
  54. }
  55. public void Initialize()
  56. {
  57. var currentStage = StageUtility.GetCurrentStageHandle();
  58. var managers = currentStage.FindComponentsOfType<IKManager2D>().Where(x => x.gameObject.scene.isLoaded).ToArray();
  59. foreach (var ikManager2D in managers)
  60. m_IKManagers.Add(ikManager2D);
  61. RegisterCallbacks();
  62. m_Initialized = true;
  63. }
  64. void Dispose()
  65. {
  66. UnregisterCallbacks();
  67. Clear();
  68. m_Initialized = false;
  69. }
  70. void AddIKManager2D(IKManager2D manager)
  71. {
  72. if (manager == null)
  73. return;
  74. if (!m_Initialized)
  75. Initialize();
  76. m_IKManagers.Add(manager);
  77. }
  78. void RemoveIKManager2D(IKManager2D manager)
  79. {
  80. m_IKManagers.Remove(manager);
  81. if (m_IKManagers.Count == 0)
  82. Dispose();
  83. }
  84. private void RegisterCallbacks()
  85. {
  86. #if UNITY_2019_1_OR_NEWER
  87. SceneView.duringSceneGui += OnSceneGUI;
  88. #else
  89. SceneView.onSceneGUIDelegate += OnSceneGUI;
  90. #endif
  91. Selection.selectionChanged += OnSelectionChanged;
  92. }
  93. private void UnregisterCallbacks()
  94. {
  95. #if UNITY_2019_1_OR_NEWER
  96. SceneView.duringSceneGui -= OnSceneGUI;
  97. #else
  98. SceneView.onSceneGUIDelegate -= OnSceneGUI;
  99. #endif
  100. Selection.selectionChanged -= OnSelectionChanged;
  101. }
  102. private bool m_EnableGizmos;
  103. private bool m_CurrentEnableGizmoState;
  104. void OnDrawGizmos()
  105. {
  106. m_EnableGizmos = true;
  107. IKManager2D.onDrawGizmos.RemoveListener(OnDrawGizmos);
  108. }
  109. public void CheckGizmoToggle()
  110. {
  111. //Ignore events other than Repaint
  112. if (Event.current.type != EventType.Repaint)
  113. return;
  114. if (m_CurrentEnableGizmoState != m_EnableGizmos)
  115. SceneView.RepaintAll();
  116. m_CurrentEnableGizmoState = m_EnableGizmos;
  117. //Assume the Gizmo toggle is disabled and listen to the event again
  118. m_EnableGizmos = false;
  119. IKManager2D.onDrawGizmos.RemoveListener(OnDrawGizmos);
  120. IKManager2D.onDrawGizmos.AddListener(OnDrawGizmos);
  121. }
  122. private void OnSelectionChanged()
  123. {
  124. m_SelectedGameobjects = null;
  125. }
  126. void Clear()
  127. {
  128. m_IKManagers.Clear();
  129. m_DirtyManagers.Clear();
  130. m_ChainPositionOverrides.Clear();
  131. }
  132. public IKManager2D FindManager(Solver2D solver)
  133. {
  134. foreach (IKManager2D manager in m_IKManagers)
  135. {
  136. if (manager == null)
  137. continue;
  138. foreach (Solver2D s in manager.solvers)
  139. {
  140. if (s == null)
  141. continue;
  142. if (s == solver)
  143. return manager;
  144. }
  145. }
  146. return null;
  147. }
  148. public void Record(Solver2D solver, string undoName)
  149. {
  150. var manager = FindManager(solver);
  151. DoUndo(manager, undoName, true);
  152. }
  153. public void RegisterUndo(Solver2D solver, string undoName)
  154. {
  155. var manager = FindManager(solver);
  156. DoUndo(manager, undoName, false);
  157. }
  158. public void Record(IKManager2D manager, string undoName)
  159. {
  160. DoUndo(manager, undoName, true);
  161. }
  162. public void RegisterUndo(IKManager2D manager, string undoName)
  163. {
  164. DoUndo(manager, undoName, false);
  165. }
  166. private void DoUndo(IKManager2D manager, string undoName, bool record)
  167. {
  168. if (manager == null)
  169. return;
  170. foreach (var solver in manager.solvers)
  171. {
  172. if (solver == null || !solver.isActiveAndEnabled)
  173. continue;
  174. if (!solver.isValid)
  175. solver.Initialize();
  176. if (!solver.isValid)
  177. continue;
  178. for (int i = 0; i < solver.chainCount; ++i)
  179. {
  180. var chain = solver.GetChain(i);
  181. if (record)
  182. {
  183. foreach(var t in chain.transforms)
  184. Undo.RecordObject(t, undoName);
  185. if(chain.target)
  186. Undo.RecordObject(chain.target, undoName);
  187. }
  188. else
  189. {
  190. foreach(var t in chain.transforms)
  191. Undo.RegisterCompleteObjectUndo(t, undoName);
  192. if(chain.target)
  193. Undo.RegisterCompleteObjectUndo(chain.target, undoName);
  194. }
  195. }
  196. }
  197. }
  198. public void UpdateManagerImmediate(IKManager2D manager, bool recordRootLoops)
  199. {
  200. SetManagerDirty(manager);
  201. UpdateDirtyManagers(recordRootLoops);
  202. }
  203. public void UpdateSolverImmediate(Solver2D solver, bool recordRootLoops)
  204. {
  205. SetSolverDirty(solver);
  206. UpdateDirtyManagers(recordRootLoops);
  207. }
  208. public void SetChainPositionOverride(IKChain2D chain, Vector3 position)
  209. {
  210. m_ChainPositionOverrides[chain] = position;
  211. }
  212. private bool IsViewToolActive()
  213. {
  214. int button = Event.current.button;
  215. return Tools.current == Tool.View || Event.current.alt || (button == 1) || (button == 2);
  216. }
  217. private bool IsDraggingATool()
  218. {
  219. //If a tool has used EventType.MouseDrag, we won't be able to detect it. Instead we check for delta magnitude
  220. return GUIUtility.hotControl != 0 && Event.current.button == 0 && Event.current.delta.sqrMagnitude > 0f && !IsViewToolActive();
  221. }
  222. private void OnSceneGUI(SceneView sceneView)
  223. {
  224. CheckGizmoToggle();
  225. if (!m_CurrentEnableGizmoState)
  226. return;
  227. if (m_SelectedGameobjects == null)
  228. m_SelectedGameobjects = Selection.gameObjects;
  229. foreach (var ikManager2D in m_IKManagers)
  230. {
  231. if (ikManager2D != null && ikManager2D.isActiveAndEnabled)
  232. IKGizmos.instance.DoSolversGUI(ikManager2D);
  233. }
  234. if (!IKGizmos.instance.isDragging && IsDraggingATool())
  235. {
  236. //We expect the object to be selected while dragged
  237. foreach (var gameObject in m_SelectedGameobjects)
  238. {
  239. if (gameObject != null && gameObject.transform != null)
  240. SetDirtySolversAffectedByTransform(gameObject.transform);
  241. }
  242. if(m_DirtyManagers.Count > 0 && !isDraggingATool)
  243. {
  244. isDraggingATool = true;
  245. Undo.SetCurrentGroupName("IK Update");
  246. RegisterUndoForDirtyManagers();
  247. }
  248. }
  249. if(GUIUtility.hotControl == 0)
  250. isDraggingATool = false;
  251. }
  252. private void SetSolverDirty(Solver2D solver)
  253. {
  254. if (solver && solver.isValid && solver.isActiveAndEnabled)
  255. SetManagerDirty(FindManager(solver));
  256. }
  257. private void SetManagerDirty(IKManager2D manager)
  258. {
  259. if (manager && manager.isActiveAndEnabled)
  260. m_DirtyManagers.Add(manager);
  261. }
  262. private void SetDirtySolversAffectedByTransform(Transform transform)
  263. {
  264. foreach (var manager in m_IKManagers)
  265. {
  266. if (manager != null && manager.isActiveAndEnabled)
  267. {
  268. var dirty = false;
  269. var solvers = manager.solvers;
  270. for (var s = 0; s < solvers.Count; s++)
  271. {
  272. if (dirty)
  273. break;
  274. var solver = solvers[s];
  275. if (solver != null && solver.isValid)
  276. {
  277. for (var c = 0; c < solver.chainCount; ++c)
  278. {
  279. var chain = solver.GetChain(c);
  280. if (chain.target == null)
  281. continue;
  282. if (!(IKUtility.IsDescendentOf(chain.target, transform) && IKUtility.IsDescendentOf(chain.rootTransform, transform)) &&
  283. (chain.target == transform || IKUtility.IsDescendentOf(chain.target, transform) || IKUtility.IsDescendentOf(chain.effector, transform)))
  284. {
  285. SetManagerDirty(manager);
  286. dirty = true;
  287. break;
  288. }
  289. }
  290. }
  291. }
  292. }
  293. }
  294. }
  295. private void RegisterUndoForDirtyManagers()
  296. {
  297. foreach (var manager in m_DirtyManagers)
  298. RegisterUndo(manager, Undo.GetCurrentGroupName());
  299. }
  300. private void UpdateDirtyManagers(bool recordRootLoops)
  301. {
  302. foreach (var manager in m_DirtyManagers)
  303. {
  304. if (manager == null || !manager.isActiveAndEnabled)
  305. continue;
  306. foreach (var solver in manager.solvers)
  307. {
  308. if (solver == null || !solver.isActiveAndEnabled)
  309. continue;
  310. if (!solver.isValid)
  311. solver.Initialize();
  312. if (!solver.isValid)
  313. continue;
  314. if(solver.allChainsHaveTargets)
  315. solver.UpdateIK(manager.weight);
  316. else if(PrepareTargetOverrides(solver))
  317. solver.UpdateIK(m_TargetPositions, manager.weight);
  318. for (int i = 0; i < solver.chainCount; ++i)
  319. {
  320. var chain = solver.GetChain(i);
  321. if (recordRootLoops)
  322. InternalEngineBridge.SetLocalEulerHint(chain.rootTransform);
  323. if(solver.constrainRotation && chain.target != null)
  324. InternalEngineBridge.SetLocalEulerHint(chain.effector);
  325. }
  326. }
  327. }
  328. m_DirtyManagers.Clear();
  329. m_ChainPositionOverrides.Clear();
  330. }
  331. private bool PrepareTargetOverrides(Solver2D solver)
  332. {
  333. m_TargetPositions.Clear();
  334. for (int i = 0; i < solver.chainCount; ++i)
  335. {
  336. var chain = solver.GetChain(i);
  337. Vector3 positionOverride;
  338. if (!m_ChainPositionOverrides.TryGetValue(chain, out positionOverride))
  339. {
  340. m_TargetPositions.Clear();
  341. return false;
  342. }
  343. m_TargetPositions.Add(positionOverride);
  344. }
  345. return true;
  346. }
  347. }
  348. }