很惭愧从事游戏开发三年半才开始记录,之前也有一些零散信息记录在有道云笔记里,但都不成体系。那就从现在开始吧!
最近项目刚出完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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。