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 }
感觉也没啥好说的,就直接分享代码了。而且我觉得这个功能比较鸡肋,适用性不是很广,只能在一些特定情况下用到。
下面是我的配置文件和文件结构:

<?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自动切割动画的更多相关文章
- Unity自动生成AnimatorController
上一篇写了如何自动切割动画,这一篇写如何自动生成AnimatorController. 之前网上查了很多资料,看的一直很蒙,看不懂是怎么回事的,这里我先给大家明确几个概念: 画的不好,大家将就着看,写 ...
- 关于Unity中Mecanim动画的动画状态代码控制与代码生成动画控制器
对于多量的.复杂的.有规律的控制器使用代码生成 动画状态代码控制 1:每个动画状态,比如进入状态,离开状态, 等都有可能需要代码来参与和处理,比如,进入这个动画单元后做哪些事情,来开这个动画单元后做哪 ...
- Unity 2D骨骼动画2:创建真实动画
http://bbs.9ria.com/thread-401781-1-1.html 在这个系列,我们将关注Unity引擎提供的基于骨骼动画工具.它的主要思想是为了把它应用到你自己的游戏来介绍和教基本 ...
- Unity2D研究院之自动生成动画、AnimationController、Prefab(一)
http://www.xuanyusong.com/archives/3243 国庆了,回家了.时刻还是要吃一颗学习的心,在家了也要抽出时间好好学习一下.之前MOMO一直没研究过Unity2D,今天研 ...
- unity 对Animator动画系统的研究
unity的新动画系统叫Mecanim,使用Animator来取代旧系统Animation,按Unity文档的惯例:知识点主要分2部分:unity manual和unity script,读者可以边看 ...
- Unity MegaFiers 顶点动画
使用 MegaFiers 插件,能够使得Unity支持顶点动画的播放. 官方视频教程例如以下: 在这里简单測试使用下,环境例如以下: Blender 2.72 Unity 4.5.4 Mega ...
- Linux下nginx生成日志自动切割
1.编辑切割日志的 shell 程序,目录自定 #vi /data/nginx/cut_nginx_log.sh 输入代码: #!/bin/bash # This script run at 00:0 ...
- 【shell脚本】nginx每天自动切割日志脚本
nginx每天日志量比较大的时候,最好每天自动切割,存储,这样可以方面以后的查询和分析 #!/bin/sh ################### #filename: nginx_log_rotat ...
- linux系统日志自动切割工具----logrotate
参考资料 :https://www.cnblogs.com/kevingrace/p/6307298.html 对于Linux系统安全来说,日志文件是极其重要的工具.不知为何,我发现很多运维同学的服务 ...
随机推荐
- docker镜像无法下载或者下载缓慢
解决docker镜像无法下载的问题 2015年10月02日 16:01:05 阅读数:20776 克服跨洋网络延迟,使用Docker Hub Mirror加速Docker官方镜像下载 http://c ...
- CSS 背景图像 background属性简写
background属性简写 background属性可以像margin padding属性一样,有简写方法,它的简写顺序是: background-color background-image ba ...
- 爬虫 2 XPath 和 pyquery
XPath 1.常用规则 表达式 描述 nodename 选取此节点的所有子节点 / 从当前节点选取直接子节点 // 从当前节点选取子孙节点 . 选取当前节点 .. 选取当前节点的父节点 @ 选 ...
- Linux中Nginx安装教程
Nginx 是一个很强大的高性能Web和反向代理服务器,它具有很多非常优越的特性: 在连接高并发的情况下,Nginx是Apache服务器不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的 ...
- jmeter-用户定义的变量
添加-配置元件-用户定义的变量 请求中出现变量值的位置,用${_tbip}替换 脚本执行完成,在查看结果树中debug sampler中可以看见变量名和变量值
- [ArcGIS]ArcGIS Server环境搭建,发布服务,以及使用ArcGIS API for JavaScript
环境搭建 安装Web服务器 IIS 控制面板-程序-程序和功能-启用或关闭Windows功能,勾选以下 安装VisualStudio,选择包括ASP.NET模块 安装ArcGIS服务器 ArcGIS ...
- 关于项目里server清楚缓存的代码
Venk proc存在很多问题,不能应对高并发的情况,所以提供了这个 方法来清理cache, 但是前提是需要有prod的权限: 要想验证是否通过URL清楚了缓存,就要 removeCache url执 ...
- node.js中对 redis 的安装和基本操作
一.win下安装redis https://github.com/MicrosoftArchive/redis/releases 下载Redis-x64-3.2.100.zip,然后解压,放到自定义目 ...
- 非WifI环境处理
//1.创建网络状态监测管理者 AFNetworkReachabilityManager *mangerStatus = [AFNetworkReachabilityManager sharedMan ...
- zookeeper资料
ZooKeeper 入门