您的位置:首页 > 移动开发 > Unity3D

Unity3D拓展编辑器之自动生成AnimatorController

2015-05-23 22:28 836 查看
很惭愧从事游戏开发三年半才开始记录,之前也有一些零散信息记录在有道云笔记里,但都不成体系。那就从现在开始吧!

最近项目刚出完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到指定目录~

本文出自 “口困哟” 博客,请务必保留此出处http://kokunyo.blog.51cto.com/3265918/1654541
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: