公司有需求,把暂时有的四十多个模型,都添加一个animator组件并且给添加动画状态控制,并且打出ab包。这就很烦了,于是花了一个下午把工具写完,最近也在捣鼓editor工具,公司加密软件没带不出demo来,思路还在,回家复盘,并且加上窗口!

private static string PrefabEndsWith = ".prefab";
/// <summary>
/// 创建预制体
/// </summary>
/// <param name="选择的物体"></param>
/// <param name="预制体存放路径"></param>
/// <param name="预制体父物体路径"></param>
public static void MyCreationPrefab(GameObject[] objs, string rootPath, string parent)
{
try
{
string path = rootPath + parent + "/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
for (int i = 0; i < objs.Length; i++)
{
EditorUtility.DisplayProgressBar("制作预制体", "名字:" + objs[i].name, i * 1.0f / objs.Length);
#if UNITY_2018
GameObject TempPrefab = PrefabUtility.CreatePrefab(path + name + ".prefab", objs[i]);
#elif UNITY_2019
GameObject TempPrefab = PrefabUtility.SaveAsPrefabAsset((GameObject)PrefabUtility.InstantiatePrefab(objs[i]), path + GetPrefabName(objs[i].name) + PrefabEndsWith);
#endif
}
EditorUtility.ClearProgressBar();
}
catch (System.Exception e)
{
Debug.LogError($"创建预制体失败!{e}");
EditorUtility.ClearProgressBar();
}
}
/// <summary>
/// 创建预制体重载
/// </summary>
/// <param name="modelPath"></param>
/// <param name="paefabRoot"></param>
/// <param name="是否给模型添加动画状态机"></param>
/// <param name="动画状态机存放地址"></param>
public static void MyCreationPrefab(List<string> modelPath, string paefabRoot, bool setAnim, string animPath)
{
try
{
for (int i = 0; i < modelPath.Count; i++)
{
if (modelPath[i] == "") continue;
string path = paefabRoot + PathToPrefabParent(modelPath[i]) + "/";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
List<string> mPath = GetModels(modelPath[i]);
for (int j = 0; j < mPath.Count; j++)
{
EditorUtility.DisplayProgressBar("制作预制体", "模型路径:" + mPath[j], j * 1.0f / mPath.Count);
#if UNITY_2018
PrefabUtility.CreatePrefab(path + name + ".prefab", objs[i]);
#elif UNITY_2019
GameObject TempPrefab = PrefabUtility.SaveAsPrefabAsset((GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<GameObject>(mPath[j])), path + PathToPrefabName(mPath[j]) + PrefabEndsWith);
#endif
if (setAnim)
{
SetAnimatorController(TempPrefab, mPath[j], animPath, PathToPrefabName(mPath[j]));
}
}
EditorUtility.ClearProgressBar();
}
}
catch (System.Exception e)
{
Debug.LogError($"创建预制体失败!{e}");
EditorUtility.ClearProgressBar();
}
}
/// <summary>
/// 获取模型的名字
/// </summary>
/// <param name="pathList"></param>
/// <returns></returns>
public static List<string> GetModels(string pathList)
{
try
{
List<string> modelPath = new List<string>();
string[] allStr = AssetDatabase.FindAssets("t:model", new string[] { pathList });
for (int i = 0; i < allStr.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(allStr[i]);
if (allStr.Length > 100)
{
EditorUtility.DisplayProgressBar("查找模型", "ModelPath:" + path, i * 1.0f / allStr.Length);
}
modelPath.Add(path);
}
EditorUtility.ClearProgressBar();
return modelPath;
}
catch (System.Exception e)
{
EditorUtility.ClearProgressBar();
Debug.LogError($"查找模型失败{e}!");
return null;
}
}
/// <summary>
/// 给预制体添加动画
/// </summary>
/// <param name="obj"></param>
/// <param name="modelPath"></param>
/// <param name="animatorControllerPath"></param>
/// <param name="name"></param>
public static void SetAnimatorController(GameObject obj, string modelPath, string animatorControllerPath, string name)
{
Animator anim = obj.GetComponent<Animator>();
if (anim)
{
AnimatorController controller = AnimatorController.CreateAnimatorControllerAtPath(animatorControllerPath + name + ".controller");
AnimatorController.SetAnimatorController(anim, controller);
AnimatorControllerLayer layer = controller.layers[0];
AnimatorStateMachine machine = layer.stateMachine;
controller.AddParameter("e", AnimatorControllerParameterType.Bool);
AnimatorState IdleState = machine.AddState("Idle", new Vector3(300, 0, 0));
machine.defaultState = IdleState;
AnimatorState behaviorState = machine.AddState("behavior", new Vector3(550, 0, 0));
behaviorState.motion = GetAnimationClip(modelPath);
AnimatorStateTransition behaviorTrue = IdleState.AddTransition(behaviorState);
behaviorTrue.AddCondition(AnimatorConditionMode.If, 1f, "e");
AnimatorStateTransition behaviorFlas = behaviorState.AddTransition(IdleState);
behaviorFlas.AddCondition(AnimatorConditionMode.IfNot, 1F, "e");
}
else
{
Debug.Log(obj.name + "没有挂载动画状态机组件");
}
}
/// <summary>
/// 获取动画片段
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static AnimationClip GetAnimationClip(string path)
{
Object[] objects = AssetDatabase.LoadAllAssetsAtPath(path);
for (int m = 0; m < objects.Length; m++)
{
if (objects[m].GetType() == typeof(AnimationClip))
{
AnimationClip clip = (AnimationClip)objects[m];
return clip;
}
}
return null;
}
/// <summary>
/// 获取动画片段
/// </summary>
/// <param name="go"></param>
/// <returns></returns>
public static AnimationClip GetAnimationClip(GameObject go)
{
return go.GetComponent<Animation>().clip;
}
/// <summary>
/// 给模型名字返回预制的名字
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
static string GetPrefabName(string name)
{
return name.Replace("_", "");
}
/// <summary>
/// 得到模型的名字
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
static string PathToPrefabName(string path)
{
string[] str = path.Split('/');
string result = str[str.Length - 1];
result = result.Replace("_", "");
result = result.Replace(".fbx", "");
return result;
}
/// <summary>
/// 得到模型父物体名字 "Assets/Model"
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
static string PathToPrefabParent(string path)
{
string[] str = path.Split('/');
string result = str[str.Length - 1];
return result;
}

可以选择把鼠标选择的模型制作为预制体,和根据传入一个地址,查找该目录下的模型进行处理。这里可以,拓展为配表,为多个模型添加动画,添加什么动画,这个时候成功的给产品增加了工作,但是可以增加一些效率,需要处理的模型越多,越省时间。

AnimBool m_SelectionGameobjectWinWin;
private string m_PrefabsRootPath = null;
private string m_PrafabsParent = null;
private string m_AnimatorControllerPath = null;
private bool m_SetAnimatorController = false;
AnimBool m_Win;
private List<string> list = new List<string>();
void OnEnable()
{
m_Win = new AnimBool(true);
m_Win.valueChanged.AddListener(Repaint);
m_SelectionGameobjectWinWin = new AnimBool(true);
m_SelectionGameobjectWinWin.valueChanged.AddListener(Repaint);
}
void OnGUI()
{
m_SelectionGameobjectWinWin.target = EditorGUILayout.ToggleLeft("选择模型制作为预制体", m_SelectionGameobjectWinWin.target);
if (EditorGUILayout.BeginFadeGroup(m_SelectionGameobjectWinWin.faded))
{
EditorGUI.indentLevel++;
EditorGUILayout.PrefixLabel("预制体存放根路径");
m_PrefabsRootPath = EditorGUILayout.TextField(m_PrefabsRootPath ?? "Assets/Prefabs/");
EditorGUILayout.PrefixLabel("预制体存放文件夹名称");
m_PrafabsParent = EditorGUILayout.TextField(m_PrafabsParent ?? "Other");
m_SetAnimatorController = EditorGUILayout.Toggle("为该模型添加动画控制", m_SetAnimatorController);
if (EditorGUILayout.BeginFadeGroup(m_SetAnimatorController == true ? 1.0f : 0))
{
EditorGUILayout.PrefixLabel("动画状态机存放文件夹名称");
m_AnimatorControllerPath = EditorGUILayout.TextField(m_AnimatorControllerPath ?? "Assets/AnimatorControllers");
}
EditorGUILayout.EndFadeGroup();
if (GUILayout.Button("把选择的模型制作为预制体", GUILayout.Width(200)))
{
if (Selection.gameObjects.Length > 0)
{
Debug.LogError("根据CreationPrefabTool.GetAnimationClip()适配");
Close();
}
else
{
Debug.LogError("请选择至少大于一个模型进行预制体制作!");
Close();
}
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndFadeGroup();
m_Win.target = EditorGUILayout.ToggleLeft("批量模型制作为预制体", m_Win.target);
if (EditorGUILayout.BeginFadeGroup(m_Win.faded))
{
EditorGUI.indentLevel++;
EditorGUILayout.PrefixLabel("预制体存放根路径");
m_PrefabsRootPath = EditorGUILayout.TextField(m_PrefabsRootPath ?? "Assets/Prefabs/");
EditorGUILayout.PrefixLabel("模型存放根路径");
for (int i = 0; i < list.Count; i++)
{
EditorGUILayout.BeginHorizontal("box");
m_SetAnimatorController = EditorGUILayout.Toggle("为该模型添加动画控制", m_SetAnimatorController);
if (EditorGUILayout.BeginFadeGroup(m_SetAnimatorController == true ? 1.0f : 0))
{
EditorGUILayout.PrefixLabel("动画状态机存放文件夹名称");
m_AnimatorControllerPath = EditorGUILayout.TextField(m_AnimatorControllerPath ?? "Assets/AnimatorControllers");
}
EditorGUILayout.EndFadeGroup();
list[i] = EditorGUILayout.TextField(list[i]);
if (GUILayout.Button("Remove", GUILayout.Width(70)))
{
list.RemoveAt(i);
}
EditorGUILayout.EndHorizontal();
}
if (GUILayout.Button("Add", GUILayout.Width(200)))
{
list.Add("");
}
if (GUILayout.Button("批量制作预制体", GUILayout.Width(200)))
{
CreationPrefabTool.MyCreationPrefab(list, m_PrefabsRootPath, m_SetAnimatorController, m_AnimatorControllerPath);
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndFadeGroup();
}

这个窗口不是很完善,暂时没有需求就懒得完善了,啥是需要的在回来完善,暂时使用,没有出现bug。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY