Unity自动切割动画

时间:2023-03-09 18:42:53
Unity自动切割动画

最近在开发项目时,需要处理大量的动画,于是就网上查找资料,然后写了这么编辑器工具:

就是在模型导入时,根据配置文件自动切割动画。

首先我们需要封装两个类:一个模型类和一个动画类

 public class ModelFbx
{
#region -- 变量定义
public string modelName; //模型名称
public Clip[] clips; //模型所包含的动画
#endregion
} public class Clip
{
#region -- 变量定义
public string clipName; //动画名称
public int firstFrame; //动画第一帧
public int lastFrame; //动画最后一帧
public bool isLoop; //是否循环
#endregion #region -- 自定义函数
/// <summary>
/// 构造动画信息
/// </summary>
/// <param name="_clipName">动画名称</param>
/// <param name="_firstFrame">动画第一帧</param>
/// <param name="_lastFrame">动画最后一帧</param>
/// <param name="_isLoop">动画是否循环</param>
public Clip(string _clipName, int _firstFrame, int _lastFrame, bool _isLoop)
{
clipName = _clipName;
firstFrame = _firstFrame;
lastFrame = _lastFrame;
isLoop = _isLoop;
}
#endregion }

然后我们封装一个类,来读取配置文件并初始化切割信息的类

 using UnityEngine;
using System.Collections.Generic;
using System.Xml;
using System.IO; public static class AnimationClipConfig
{
#region -- 变量定义
public static string ConfigPath = "/_Scripts/Editor/CutAnimation/Config.xml";
private static bool mIsInit = false;//配置信息是否初始化
public static List<ModelFbx> modelList = new List<ModelFbx>();
#endregion #region -- 自定义函数
public static bool Enable
{
get
{
string _enable = Read(Application.dataPath + ConfigPath, new string[] { "Root", "Enable" });
return bool.Parse(_enable);
}
}
/// <summary>
/// 初始化配置信息
/// </summary>
/// <returns>返回初始化是否成功</returns>
public static bool Init()
{
if (mIsInit)
{
return true;
}
mIsInit = true; return InitModeList();
}
private static bool InitModeList()
{
string _path = Application.dataPath + ConfigPath;
if (File.Exists(_path))
{
XmlDocument _xmlDoc = new XmlDocument();
XmlReaderSettings _set = new XmlReaderSettings();
_set.IgnoreComments = true;
XmlReader _reader = XmlReader.Create(_path, _set);
_xmlDoc.Load(_reader);
_reader.Close();
XmlNodeList _nodeList = _xmlDoc.SelectSingleNode("Root").ChildNodes;
foreach (XmlElement _xe in _nodeList)
{
if (_xe.Name == "ModelFbx")
{
ModelFbx _modelFbx = new ModelFbx();
foreach (XmlElement _x1 in _xe.ChildNodes)
{
if (_x1.Name == "ModelName")
{
_modelFbx.modelName = _x1.InnerText;
}
if (_x1.Name == "Clips")
{
_modelFbx.clips = new Clip[_x1.ChildNodes.Count];
int _index = ;
foreach (XmlElement _x2 in _x1.ChildNodes)
{
string _clipName = "";
int _firstFrame = ;
int _lastFrame = ;
bool _isLoop = false;
foreach (XmlElement _x3 in _x2.ChildNodes)
{
if (_x3.Name == "ClipName")
{
_clipName = _x3.InnerText;
}
if (_x3.Name == "FirstFrame")
{
_firstFrame = int.Parse(_x3.InnerText);
}
if (_x3.Name == "LastFrame")
{
_lastFrame = int.Parse(_x3.InnerText);
}
if (_x3.Name == "IsLoop")
{
_isLoop = bool.Parse(_x3.InnerText);
}
}
_modelFbx.clips[_index] = new Clip(_clipName, _firstFrame, _lastFrame, _isLoop);
_index++;
}
}
}
modelList.Add(_modelFbx);
}
}
return true;
}
else
{
Debug.LogError("无法找打" + _path + "文件,请检查配置文件路径(ConfigPath)是否正确");
return false;
}
} /// <summary>
/// 读取 XML 文件指定子节点数据
/// </summary>
/// <param name="_path">文件读取路径</param>
/// <param name="_xmlNodes">节点数组</param>
/// <returns></returns>
private static string Read(string _path, string[] _xmlNodes)
{
string _innerstr = "";//返回值
XmlDocument _xmlDoc = new XmlDocument();
XmlReaderSettings _set = new XmlReaderSettings();
_set.IgnoreComments = true;
//判断文件是否存在
if (File.Exists(_path))
{
_xmlDoc.Load(XmlReader.Create(_path, _set));
}
else
{
Debug.LogError("目标文件不存在,请检查路径是否有误");
return null;
}
int _nodeNum = _xmlNodes.Length;
int _counter = ;
XmlNodeList _nodelist = _xmlDoc.SelectSingleNode(_xmlNodes[]).ChildNodes;
if (_nodelist == null)
{
return _innerstr;
}
while (_counter < _nodeNum)
{
bool _checkok = false;
foreach (XmlNode _element in _nodelist)
{
if (_element.Name == _xmlNodes[_counter])
{
_checkok = true;
_counter++;
if (_counter >= _nodeNum)
{
_innerstr = _element.InnerText;
_nodelist = null;
break;
}
_nodelist = _element.ChildNodes;
break;
}
}
if (!_checkok)
{
break;
}
}
return _innerstr;
}
#endregion }

接下来就是切割动画了

using UnityEngine;
using UnityEditor; public class CutAnimation : AssetPostprocessor
{
#region -- 系统函数
/// <summary>
/// 模型导入之前调用
/// </summary>
public void OnPreprocessModel()
{
//是否启用动画切割
if (!AnimationClipConfig.Enable)
{
return;
} //当前正在导入的模型
ModelImporter _modelImporter = (ModelImporter)assetImporter; if (AnimationClipConfig.Init())
{
foreach (ModelFbx item in AnimationClipConfig.modelList)
{
//当前导入模型的路径包含AnimationClipConfig.modelList数据表中的模型名字,那就要对这个模型的动画进行切割
if (assetPath.Contains(item.modelName))
{
_modelImporter.animationType = ModelImporterAnimationType.Generic;
_modelImporter.generateAnimations = ModelImporterGenerateAnimations.GenerateAnimations;
ModelImporterClipAnimation[] _animations = new ModelImporterClipAnimation[item.clips.Length];
for (int i = ; i < item.clips.Length; i++)
{
_animations[i] = SetClipAnimation(item.clips[i].clipName, item.clips[i].firstFrame, item.clips[i].lastFrame, item.clips[i].isLoop);
}
_modelImporter.clipAnimations = _animations;
}
}
}
else
{
Debug.LogError("无法找打" + Application.dataPath+AnimationClipConfig.ConfigPath + "文件,请检查配置文件路径(mCofigPath)是否正确");
}
}
#endregion #region -- 自定义函数
private ModelImporterClipAnimation SetClipAnimation(string _clipName, int _firstFrame, int _lastFrame, bool _isLoop)
{
ModelImporterClipAnimation _clip = new ModelImporterClipAnimation();
_clip.name = _clipName;
_clip.firstFrame =_firstFrame;
_clip.lastFrame = _lastFrame;
_clip.loop = _isLoop;
if (_isLoop)
{
_clip.wrapMode = WrapMode.Loop;
}
else
{
_clip.wrapMode = WrapMode.Default;
}
return _clip;
}
#endregion }

感觉也没啥好说的,就直接分享代码了。而且我觉得这个功能比较鸡肋,适用性不是很广,只能在一些特定情况下用到。

下面是我的配置文件和文件结构:

Unity自动切割动画

<?xml version="1.0" encoding="utf-8"?>

<Root>
<Enable>True</Enable><!--是否启用。启用:True;禁用:False--> <ModelFbx><!--模型-->
<ModelName></ModelName><!--模型名称(string)-->
<Clips><!--动画集-->
<Clip><!--动画-->
<ClipName>Start</ClipName><!--动画名称(string)-->
<FirstFrame></FirstFrame><!--动画第一帧(int)-->
<LastFrame></LastFrame><!--动画最后一帧(int)-->
<IsLoop>False</IsLoop><!--是否循环(bool)-->
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> </Root>