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

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

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

 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 }

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

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

<?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>

Unity自动切割动画的更多相关文章

  1. Unity自动生成AnimatorController

    上一篇写了如何自动切割动画,这一篇写如何自动生成AnimatorController. 之前网上查了很多资料,看的一直很蒙,看不懂是怎么回事的,这里我先给大家明确几个概念: 画的不好,大家将就着看,写 ...

  2. 关于Unity中Mecanim动画的动画状态代码控制与代码生成动画控制器

    对于多量的.复杂的.有规律的控制器使用代码生成 动画状态代码控制 1:每个动画状态,比如进入状态,离开状态, 等都有可能需要代码来参与和处理,比如,进入这个动画单元后做哪些事情,来开这个动画单元后做哪 ...

  3. Unity 2D骨骼动画2:创建真实动画

    http://bbs.9ria.com/thread-401781-1-1.html 在这个系列,我们将关注Unity引擎提供的基于骨骼动画工具.它的主要思想是为了把它应用到你自己的游戏来介绍和教基本 ...

  4. Unity2D研究院之自动生成动画、AnimationController、Prefab(一)

    http://www.xuanyusong.com/archives/3243 国庆了,回家了.时刻还是要吃一颗学习的心,在家了也要抽出时间好好学习一下.之前MOMO一直没研究过Unity2D,今天研 ...

  5. unity 对Animator动画系统的研究

    unity的新动画系统叫Mecanim,使用Animator来取代旧系统Animation,按Unity文档的惯例:知识点主要分2部分:unity manual和unity script,读者可以边看 ...

  6. Unity MegaFiers 顶点动画

        使用 MegaFiers 插件,能够使得Unity支持顶点动画的播放. 官方视频教程例如以下: 在这里简单測试使用下,环境例如以下: Blender 2.72 Unity 4.5.4 Mega ...

  7. Linux下nginx生成日志自动切割

    1.编辑切割日志的 shell 程序,目录自定 #vi /data/nginx/cut_nginx_log.sh 输入代码: #!/bin/bash # This script run at 00:0 ...

  8. 【shell脚本】nginx每天自动切割日志脚本

    nginx每天日志量比较大的时候,最好每天自动切割,存储,这样可以方面以后的查询和分析 #!/bin/sh ################### #filename: nginx_log_rotat ...

  9. linux系统日志自动切割工具----logrotate

    参考资料 :https://www.cnblogs.com/kevingrace/p/6307298.html 对于Linux系统安全来说,日志文件是极其重要的工具.不知为何,我发现很多运维同学的服务 ...

随机推荐

  1. Spring引入外部项目Junit 报ClassNotfound问题

    https://blog.csdn.net/sheng_Mu555/article/details/80465679 用它这个方法可以了 所以大家可以过去看一下哈哈

  2. Ubuntu 18.04 安装部署Net Core、Nginx全过程

    Ubuntu 18.04 安装部署Net Core.Nginx全过程 环境配置 Ubuntu 18.04 ,Nginx,.Net Core 2.1, Let's Encrypt 更新系统 sudo a ...

  3. 并发系列2:Java并发的基石,volatile关键字、synchronized关键字、乐观锁CAS操作

    由并发大师Doug Lea操刀的并发包Concurrent是并发编程的重要包,而并发包的基石又是volatile关键字.synchronized关键字.乐观锁CAS操作这些基础.因此了解他们的原理对我 ...

  4. vue实例

    <!--需求: 背景图片,进度条,减和重置按钮 进度条填满红色,值为100%,点击减时,进度条依次减十,减到0时换一张背景图片,减按钮消失,点击重置按钮时,进度条重新填满红色-->效果图: ...

  5. 用eclipse创建动态web项目手动生成web.xml方法

    建一个web项目,后来在用到web.xml文件时,才发现项目创建时没有自动创建web.xml文件. 在创建的项目上单击右键,然后单击java EE Tools下的用红线圈住的地方,然后查看你的WEB- ...

  6. python_Tkinter

    Tkinter相关 python支持多种图形界面的第三方库,包括:TKwxWidgetsQTGTK等等但是python自带的库是支持TK的TKinter,使用使用Tkinter,无需安装任何包,就可以 ...

  7. css文本垂直居中的实现

    本案例已经有新的比较简便的解决方案,可以直接采用 vertical-align:middle 样式对行内元素进行垂直居中布局,详见: 微信小程序开发——如何让商品标题类文本根据内容长度垂直居中. 以下 ...

  8. mybatis中foreach使用

    mybatis中的<foreach collection="list" item="item" index="index" open= ...

  9. 求数组中两数之和等于target的两个数的下标

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  10. js 中格式化显示时间

    function getMyDateTime(str){ var oDate = new Date(str), oYear = oDate.getFullYear(), oMonth = oDate. ...