Unity非運行模式下實現動畫播放/回退工具

Unity引擎 科技 科技動能 2017-05-21

實現效果

核心功能

  1. 支持選定模型(帶Animator)在非運行模式下,播放/暫停/停止動作。
  2. 支持動作單幀前進,單幀回退(幀時間默認0.05f,可以代碼設置)。
  3. 支持滾動條拖拽,將動作調整到指定時間。
  4. 支持調整播放速度。

其他功能

  1. 支持循環播放。
  2. 支持選中Animator下的任一動作。
  3. 編輯器關閉時,會刪除中間產生的臨時GameObject
  4. 選中Project中的Prefab,如果符合條件,將會自己創建一份Clone到Hierarchy中。

效果圖

Unity非運行模式下實現動畫播放/回退工具

實現原理

整體思路

  1. 獲取指定GameObject上的Animator,並記錄其所有的AniamtionClip。
  2. 模擬播放時間,通過AnimationMode.SampleAnimationClip方法設置播放位置。
  3. 添加進度條,單幀執行等方式修改播放時間。

注意細節

  1. 如果模型勾選了OptimizeGameObject選項,優化骨骼,那麼動作可能會因為找不到骨骼而無法播放。需要使用AnimatorUtility.DeoptimizeTransformHierarchy方法,暫時屏蔽骨骼優化。
  2. 在使用AnimationMode.SampleAnimationClip方法時,參數的GameObject應該設置為Animator所對應的GameObject而不是根節點。
  3. 因為不是運行狀態,所以Update需要由EditorApplication.update提供。(工具關閉時,需要反註冊)
  4. OnGUI方法不是每幀都執行,當使用滾動條( Slider )和進度條(ProgressBar)時,顯示不會及時更新,所以當數據更新時,需要調用Repaint方法,強制刷新UI。
  5. EditorWindow下,OnSelectionChange方法可以用來監聽選擇變化。但是在這個方法內部,修改當前選中的對象(Selection的屬性)無效。
  6. ProgressBar不能使用Layout,需要自己設置Position。在Layout中獲取上一個Rect的位置,然後計算ProcessBar的位置,實現方式:

     if(Event.current.type == EventType.Repaint) { var lastRect = GUILayoutUtility.GetLastRect; EditorGUI.ProgressBar(new Rect(lastRect.x, lastRect.y + lastRect.height, lastRect.width, 20), animationCtrl.escapeTime / animationCtrl.length, ""); }

存在疑問

  1. AnimationMode文檔中說在使用 SampleAnimationClip時需要StartAnimationMode,但沒有調用,也是可以正常運行。BeginSampling,EndSampling作用什麼?不加也可以正常運行。
  2. 在使用AnimatorUtility.OptimizeTransformHierarchy去還原模型時,需要知道exposedTransforms即需要保留的骨骼。但是沒有找到獲取exposedTransforms的方法,所以GameObject在被DeoptimizeTransformHierarchy之後無法還原。一種的思路是在調用DeoptimizeTransformHierarchy之前記錄子Transform,並且去掉包含SkinnedMeshRender的Transform,使用這些Transform來當做exposedTransforms。但是這種方式不精確,對模型有限制。

ToDo

  1. 倒播。修改時間變化方式,添加符號判斷。
  2. ParticleSystem.Simulate可以在非運行模式下制定特效播放到制定時間,可以用這個方法實現一套特效的播放回退機制。(特效比較複雜可能包含多個ParticleSystem,也可能包含動畫)
  3. 結合動作和特效,實現特效與模型動作的匹配,指定特效延時時間,並且可以同時處理多個特效。(類似技能編輯器的表現)

相關推薦

推薦中...