版权说明:本文为博主原创文章,转载需注明出处
环境 Unity 2018.3.9f1
2D游戏中避免不了帧动画的存在,当游戏中有大量角色的时候,手动创建Sprite Animation再整合到AnimatorController中可以说是要死人的,所以写了个简单的自动创建Animation和AnimatorController的Demo进行分享。
先上文件层级
每张图片文件末位以数字结尾,用于标识在Animation动画中的前后位置。
创建AnimatorController代码
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
public class AutoCreateAnimationEditor : Editor
{
//生成出的AnimationController的路径
private static string _animationControllerPath = "Assets/Animation";
//生成出的Animation的路径
private static string _animationPath = "Assets/Animation";
//美术给的原始图片路径
private static string _spriteRootPath = "Assets/Texture";
[MenuItem("Tools/CreateAnimatorController")]
static void CreateAnimation()
{
DirectoryInfo root = new DirectoryInfo(_spriteRootPath);
foreach (DirectoryInfo roleFolder in root.GetDirectories())
{
List<AnimationClip> clipsList = new List<AnimationClip>();
foreach (DirectoryInfo actionFolder in roleFolder.GetDirectories())
{
foreach (DirectoryInfo unitActionFolder in actionFolder.GetDirectories())
{
clipsList.Add(CreateAnimationClip(unitActionFolder));
}
}
CreateAnimationController(clipsList, roleFolder.Name);
}
}
static AnimationClip CreateAnimationClip(DirectoryInfo unitActionFolder)
{
string animationName = unitActionFolder.Name.ToLower();
FileInfo[] sprites = unitActionFolder.GetFiles("*.png");
Array.Sort(sprites, new FileComparer());
AnimationClip clip = new AnimationClip();
EditorCurveBinding curveBinding = new EditorCurveBinding
{
type = typeof(SpriteRenderer),
path = "",
propertyName = "m_Sprite"
};
string roleFolderName = unitActionFolder.Parent.Parent.Name;
string actionFolderName = unitActionFolder.Parent.Name;
ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[sprites.Length];
// 动画帧率 表示一秒播放几张图片
int frame = 10;
float frameTime = 1f / frame;
for (int i = 0; i < sprites.Length; i++)
{
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(
$"{_spriteRootPath}/{roleFolderName}/{actionFolderName}/{unitActionFolder.Name}/{sprites[i].Name}");
keyFrames[i] = new ObjectReferenceKeyframe
{
time = frameTime * i,
value = sprite
};
}
clip.frameRate = frame;
// 设置循环播放
AnimationClipSettings clipSetting = AnimationUtility.GetAnimationClipSettings(clip);
clipSetting.loopTime = true;
AnimationUtility.SetAnimationClipSettings(clip, clipSetting);
AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames);
// 创建文件夹
string animationClipPath = $"{_animationPath}/{roleFolderName}/{actionFolderName}";
Directory.CreateDirectory($"{animationClipPath}");
// 创建AnimationClip文件
string file = $"{animationClipPath}/{roleFolderName}_{animationName}.anim";
AssetDatabase.CreateAsset(clip, file);
AssetDatabase.SaveAssets();
return clip;
}
static void CreateAnimationController(List<AnimationClip> clipsList, string role)
{
string animatorControllerPath = $"{_animationControllerPath}/{role}/{role}_animator_ctrl.controller";
AnimatorController animatorController =
AnimatorController.CreateAnimatorControllerAtPath(animatorControllerPath);
// 添加参数
animatorController.AddParameter(new AnimatorControllerParameter()
{
name = "Run", type = AnimatorControllerParameterType.Bool, defaultBool = false
});
AnimatorControllerLayer layer = animatorController.layers[0];
AnimatorStateMachine sm = layer.stateMachine;
foreach (AnimationClip clip in clipsList)
{
AnimatorState state = sm.AddState(clip.name);
state.motion = clip;
state.writeDefaultValues = false;
if (clip.name.Contains("idle"))
{
sm.defaultState = state;
}
// 设置参数 这里只设置了 不能过渡到自身 以及 过渡时间
AnimatorStateTransition trans = sm.AddAnyStateTransition(state);
trans.canTransitionToSelf = false;
trans.duration = 0;
// 添加Animation条件
trans.AddCondition(
clip.name.IndexOf("run", StringComparison.Ordinal) > 0
? AnimatorConditionMode.If
: AnimatorConditionMode.IfNot, 0,
"Run");
}
AssetDatabase.SaveAssets();
}
}
文件排序接口实现
public class FileComparer : IComparer<FileInfo>
{
public int Compare(FileInfo a, FileInfo b)
{
int index_a_dot = a.Name.LastIndexOf('.');
int index_a__ = a.Name.LastIndexOf('_');
int num_a = Convert.ToInt32(a.Name.Substring(index_a__ + 1, index_a_dot - index_a__ - 1));
int index_b_dot = b.Name.LastIndexOf('.');
int index_b__ = b.Name.LastIndexOf('_');
int num_b = Convert.ToInt32(b.Name.Substring(index_b__ + 1, index_b_dot - index_b__ - 1));
return num_a < num_b ? -1 : 1;
}
}
这样就完成了,点击Tools/AnimatorController即可创建出Animation和AnimatorController,效果图如下:
同理,如果想创建UGUI动画,在Image上播放的话,将EditorCurveBinding
的type
设置为Image
就可以了。
以上。