很惭愧从事游戏开发三年半才开始记录,之前也有一些零散信息记录在有道云笔记里,但都不成体系。那就从现在开始吧!
最近项目刚出完demo,有些衔接的时间,花了一天时间写了一个方便美术同学操作的小工具。第一次写拓展编辑器,做好之后超级兴奋的说,哈哈~这个工具主要是根据某类人物的AnimatorController的模板,拷贝并将当前人物的动作自动赋值的过程,避免了手动拖拽动作操作的繁杂和失误。比如,monster一般可以共用AnimatorController的layer信息,只是各个state中的motion要对应各个人物的动作。
当然,写的还不够灵活,有一些目录和命名的要求。
1、AnimatorController模板文件的目录地址:放在该类型人物的文件夹下,如monster文件夹下
2、每个人物模型的skin文件的目录地址:放在该人物的文件夹下,如怪物1文件夹下
3、各个动作文件命名规范:怪物名@动作名,如monster_blk@skin、monster_blk@idlel01
monster文件夹
—AnimatorController(monster共用的AnimatorController模板文件)
—monster_blk(怪物1的资源文件夹)
—Anim(怪物1的动作文件夹)
—Materials(怪物1的材质文件夹)
—Tex(怪物1的贴图文件夹)
—monster_blk@skin(怪物1的skin文件)
—monster_blkw(怪物2的资源文件夹)
—Anim(怪物2的动作文件夹)
—Materials(怪物2的材质文件夹)
—Tex(怪物2的贴图文件夹)
—monster_blkw@skin(怪物2的skin文件)
和美术同学规范好细节后,就可以开始编码啦~话不多说,直接上代码~
新建一个EditorAnimatorController脚本,放在工程目录Editor下。
using UnityEditor;
using UnityEngine;
using System.Collections;
using System.IO;
public class EditorAnimatorController{
//controller模板名和拷贝后的名称
private static string fileName = "AnimatorController.controller";
[MenuItem("AnimatorController/CreateAnimatorController")]
static void CreateAnimatorController()
{
//获得当前选中为GameObject格式的文件
object[] objs = Selection.GetFiltered (typeof(GameObject), SelectionMode.Assets);
GameObject selectObj = null;
if (objs.Length < 1)
{
Debug.LogError("Please select a model file");
return;
}
//判断是否选中了skin文件,名字含有"@skin"
foreach (GameObject obj in objs)
{
if(obj.name.Contains("@skin"))
{
selectObj = obj;
}
}
//如果没有选中,则提示错误并返回
if (selectObj == null)
{
Debug.LogError("Please select a skin file");
return;
}
//获得模板文件的路径(没有找到获得上一级上上级目录的API,只好使用字符切割了)
string selectObjPath = AssetDatabase.GetAssetPath((Object) selectObj);
string[] array = selectObjPath.Split('/');
string templetControlPath = null;
string animatorControllerPath = null;
for (int i = 0; i < array.Length; ++i)
{
if(i == (array.Length - 1) )
continue;
animatorControllerPath += array[i] + "/";
if(i == (array.Length - 2) )
continue;
templetControlPath += array[i] + "/";
}
//判断模板文件是否在该类型人物文件夹下
if (!File.Exists (templetControlPath + fileName))
{
Debug.LogError("The templet control file is missing");
return;
}
//如果还没有生成AnimatorController文件,则将模板文件拷贝
if (!File.Exists (animatorControllerPath + fileName))
{
FileUtil.CopyFileOrDirectory (templetControlPath + fileName, animatorControllerPath + fileName);
Debug.Log("copy animator control success");
}
//注意下方高能坑!之前没有刷新,导致下面的animatorController一直为null
AssetDatabase.Refresh ();
//通过AssetDatabase类load新拷贝的文件,获得animatorController对象
UnityEditor.Animations.AnimatorController animatorController = AssetDatabase.LoadAssetAtPath (animatorControllerPath + fileName, typeof(UnityEditor.Animations.AnimatorController)) as UnityEditor.Animations.AnimatorController;
//获得layer信息
UnityEditor.Animations.AnimatorControllerLayer layer = animatorController.layers[0];
//获得stateMachine信息
UnityEditor.Animations.AnimatorStateMachine sm = layer.stateMachine;
//获得该人物文件夹下Anim文件夹中的动作资源
string animPath = animatorControllerPath + "Anim";
string[] assets = AssetDatabase.FindAssets( "t:GameObject" , animPath.Split() );
AnimationClip[] animClip = new AnimationClip[assets.Length];
//获得目录下所有的AnimationClip对象
for (int i = 0; i < assets.Length; ++i)
{
string path = AssetDatabase.GUIDToAssetPath(assets[i]);
animClip[i] = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
}
//通过名称匹配,将AnimationClip一一对应上state的motion
for (int i = 0; i < sm.states.Length; ++i)
{
for(int j = 0 ; j < animClip.Length ; ++j)
{
if(animClip[j].name.Contains(sm.states[i].state.name))
{
sm.states[i].state.motion = animClip[j];
}
}
}
}
}
好啦,先记录到这~周一继续写将当前AnimatorController附加到人物身上并生成Prefab到指定目录~
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。