独立游戏的诞生

记录游戏制作的点点滴滴。

模型动画查看器

美术制作的3D模型动画文件,没有很好的预览手段,往往需要手动创建Animator,然后再拖对应的动画文件到State中,在模型动画数量增多的时候,手动处理这些问题往往是耗时低效的。所以就有了制作模型动画查看器的需求。

基本的思路为读取模型文件,创建Animation Controller, 将动画文件添加到Animation Controller的Layer,并建立不同状态间的Transition. 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using UnityEngine;
using System.Collections;
using UnityEditor;
using UnityEditorInternal;
using System.IO;
using System.Collections.Generic;

public class AnimationViewer : Editor
{
  private static string ModelPath = Application.dataPath + "/Model";
  private static string animationControllerPath = "Assets/AnimationController";
  private static string PrefabPath = "Assets/Resources/Prefabs";
  private static string FileName = "ModelNames";
  private static StreamWriter writer;
  
  static void DoCreateAnimationAssets ()
  {
      //获得模型动画所在文件夹
      DirectoryInfo raw = new DirectoryInfo (ModelPath);      
      string appendString = "";

      //遍历模型动画文件夹
      foreach (DirectoryInfo dictory in raw.GetDirectories())
      {
          appendString += ":" + dictory.Name;
          State lastState = null;

          //生成AnimationController
          AnimatorController animatorController = AnimatorController.CreateAnimatorControllerAtPath (animationControllerPath + "/" + dictory.Name + ".controller");
          //得到AnimationController的Layer, 默认layer为base
          AnimatorControllerLayer layer = animatorController.GetLayer (0);
          List<State> stateList = new List<State>();
          foreach (FileInfo file in dictory.GetFiles()) {
              //动画名称遵循"模型名@动画名"的规则,并除去.meta文件
              if (file.Name.Contains ("@") && !file.Name.Contains (".meta")) {
                  //把动画文件保存在我们创建的AnimationController中,并与上一个动画状态做Transition.
                  string fbxPath = "Assets/Model/" + dictory.Name + "/" + file.Name;
                  lastState = AddStateTransition (fbxPath, layer, lastState);
                  stateList.Add(lastState);
              }
          }

          UnityEditorInternal.StateMachine sm = layer.stateMachine;
          //首位详解,形成一个循环播放的效果
          sm.AddTransition(stateList[stateList.Count -1], stateList[0]);

          //保存为Prefab
          BuildPrefab (dictory, animatorController);
      }

      AppendString (appendString);
  }

  static void AppendString (string appendString)
  {
      //记录所有的模型名称
      File.WriteAllText (Application.dataPath + "/Resources/" + FileName + ".txt", appendString);
  }

  private static State AddStateTransition (string path, AnimatorControllerLayer layer, State lastState)
  {
      UnityEditorInternal.StateMachine sm = layer.stateMachine;
      //根据动画文件读取它的AnimationClip对象
      AnimationClip newClip = AssetDatabase.LoadAssetAtPath (path, typeof(AnimationClip)) as AnimationClip;
      AnimationUtility.SetAnimationType (newClip, ModelImporterAnimationType.Generic);
      //取出动画名子 添加到state里面
      State state = sm.AddState (newClip.name);
      state.SetAnimationClip (newClip, layer);
      //把state添加在layer里面
      if (lastState = null)
      {
          sm.AddTransition (lastState, state);
      }

      return state;
  }

  private static void BuildPrefab (DirectoryInfo dictory, AnimatorController animatorCountorller)
  {
      string modelPath = "Assets/Model/" + dictory.Name + "/" + dictory.Name + ".FBX";

      GameObject go = AssetDatabase.LoadAssetAtPath (modelPath, typeof(GameObject)) as GameObject;
      go.name = dictory.Name;

      Animator animator = go.GetComponent<Animator> ();
      animator.runtimeAnimatorController = animatorCountorller;

      PrefabUtility.CreatePrefab (PrefabPath + "/" + go.name + ".prefab", go);
  }
}

unity

« BasketBallCourt_Fight 一撸到底 »