关于自动生成动画,雨松MOMO有一篇比较完整的文章了,链接在此 点击打开链接
生成AnimationClip、Controller以及设置State等都是参考了他提供的代码,这里我主要补充一下如何给2d texture设置锚点。
这里主要看代码吧,值得一提的是,设置自定义锚点必须将spriteAlignment设置为9(customer),否则设置的pivot将不起作用。
[MenuItem("JyGame/BuildClip")]
static void BuildClip()
{
//AnimationXml xml = ResourceManager.Get
ResourceManager.Init();
List<string> actionList = new List<string>();
foreach(var d in TargetDir.GetDirectories())
{
string animationName = d.Name;
Debug.Log("building " + animationName);
if (ResourceManager.Get<JyGame.AnimationNode>(animationName) == null)
{
Debug.LogWarning("错误, 找不到xml中锚点描述!" + animationName);
continue;
}
//调整锚点
foreach(var f in new DirectoryInfo(d.FullName + "\\rawdata").GetFiles("*.png"))
{
string[] paras = f.Name.Replace(".png","").Split('-');
string animation = paras[0];
string action = paras[1];
int count = int.Parse(paras[2]);
AnimationImage img = null;
try
{
img = ResourceManager.Get<JyGame.AnimationNode>(animation).GetGroup(action).images[count];
}
catch
{
Debug.Log("找不到文件对应的描述,删除" + f.FullName);
File.Delete(f.FullName);
continue;
}
string path = DataPathToAssetPath(f.FullName);
TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
TextureImporterSettings tis = new TextureImporterSettings();
textureImporter.ReadTextureSettings(tis);
tis.spriteAlignment = 9; //customer
tis.spritePixelsPerUnit = 1;
tis.mipmapEnabled = false;
tis.spritePivot = new Vector2((float)img.anchorx / img.w, (float)(img.h - img.anchory) / img.h);
textureImporter.SetTextureSettings(tis);
if(!actionList.Contains(action))
{
actionList.Add(action);
}
AssetDatabase.ImportAsset(path);
}
List<AnimationClip> clips = new List<AnimationClip>();
//创建clip
foreach(var action in actionList)
{
FileInfo[] images = new DirectoryInfo(d.FullName + "\\rawdata").GetFiles(string.Format("*-{0}-*.png",action));
AnimationClip clip = new AnimationClip();
AnimationUtility.SetAnimationType(clip, ModelImporterAnimationType.Generic);
EditorCurveBinding curveBinding = new EditorCurveBinding();
curveBinding.type = typeof(SpriteRenderer);
curveBinding.path = "";
curveBinding.propertyName = "m_Sprite";
ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[images.Length];
float frameTime = 1 / 10f;
if(action == "stand")
{
frameTime = 1 / 4f;
}
for (int i = 0; i < images.Length; i++)
{
Sprite sprite = Resources.LoadAssetAtPath<Sprite>(DataPathToAssetPath(images[i].FullName));
keyFrames[i] = new ObjectReferenceKeyframe();
keyFrames[i].time = frameTime * i;
keyFrames[i].value = sprite;
}
clip.frameRate = 10;
if (action == "stand") clip.frameRate = 4;
if (action != "attack")
{
//设置idle文件为循环动画
SerializedObject serializedClip = new SerializedObject(clip);
AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings"));
clipSettings.loopTime = true;
serializedClip.ApplyModifiedProperties();
}
AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyFrames);
AssetDatabase.CreateAsset(clip, TARGET_DIR + animationName + "\\" + action + ".anim");
clips.Add(clip);
AssetDatabase.SaveAssets();
}
//创建controller
AnimatorController animatorController =
AnimatorController.CreateAnimatorControllerAtPath(TARGET_DIR + animationName + "\\controller.controller");
AnimatorControllerLayer layer = animatorController.GetLayer(0);
UnityEditorInternal.StateMachine sm = layer.stateMachine;
//animatorController.AddParameter("attack", AnimatorControllerParameterType.Trigger);
//animatorController.AddParameter("move", AnimatorControllerParameterType.Trigger);
//animatorController.AddParameter("stand", AnimatorControllerParameterType.Trigger);
State standState = null;
State attackState = null;
State moveState = null;
foreach (AnimationClip newClip in clips)
{
State state = sm.AddState(newClip.name);
state.SetAnimationClip(newClip, layer);
if (newClip.name == "stand")
{
sm.defaultState = state;
standState = state;
}else if(newClip.name =="move")
{
moveState = state;
}else if(newClip.name == "attack")
{
attackState = state;
}
Transition trans = sm.AddAnyStateTransition(state);
trans.RemoveCondition(0);
}
if(attackState != null && standState!=null)
{
var trans = sm.AddTransition(attackState, standState);
//var condition = trans.AddCondition();
//condition.mode = TransitionConditionMode.ExitTime;
}
AssetDatabase.SaveAssets();
//生成Prefab 添加一张预览用的Sprite
FileInfo tagImage = new DirectoryInfo(d.FullName + "\\rawdata").GetFiles("*.png")[0];
GameObject go = new GameObject();
go.name = animationName;
SpriteRenderer spriteRender = go.AddComponent<SpriteRenderer>();
spriteRender.sprite = Resources.LoadAssetAtPath<Sprite>(DataPathToAssetPath(tagImage.FullName));
Animator animator = go.AddComponent<Animator>();
animator.runtimeAnimatorController = animatorController;
PrefabUtility.CreatePrefab(TARGET_DIR + animationName + "/sprite.prefab", go);
DestroyImmediate(go);
}
}
public static string DataPathToAssetPath(string path)
{
if (Application.platform == RuntimePlatform.WindowsEditor)
return path.Substring(path.IndexOf("Assets\\"));
else
return path.Substring(path.IndexOf("Assets/"));
}
class AnimationClipSettings
{
SerializedProperty m_Property;
private SerializedProperty Get(string property) { return m_Property.FindPropertyRelative(property); }
public AnimationClipSettings(SerializedProperty prop) { m_Property = prop; }
public float startTime { get { return Get("m_StartTime").floatValue; } set { Get("m_StartTime").floatValue = value; } }
public float stopTime { get { return Get("m_StopTime").floatValue; } set { Get("m_StopTime").floatValue = value; } }
public float orientationOffsetY { get { return Get("m_OrientationOffsetY").floatValue; } set { Get("m_OrientationOffsetY").floatValue = value; } }
public float level { get { return Get("m_Level").floatValue; } set { Get("m_Level").floatValue = value; } }
public float cycleOffset { get { return Get("m_CycleOffset").floatValue; } set { Get("m_CycleOffset").floatValue = value; } }
public bool loopTime { get { return Get("m_LoopTime").boolValue; } set { Get("m_LoopTime").boolValue = value; } }
public bool loopBlend { get { return Get("m_LoopBlend").boolValue; } set { Get("m_LoopBlend").boolValue = value; } }
public bool loopBlendOrientation { get { return Get("m_LoopBlendOrientation").boolValue; } set { Get("m_LoopBlendOrientation").boolValue = value; } }
public bool loopBlendPositionY { get { return Get("m_LoopBlendPositionY").boolValue; } set { Get("m_LoopBlendPositionY").boolValue = value; } }
public bool loopBlendPositionXZ { get { return Get("m_LoopBlendPositionXZ").boolValue; } set { Get("m_LoopBlendPositionXZ").boolValue = value; } }
public bool keepOriginalOrientation { get { return Get("m_KeepOriginalOrientation").boolValue; } set { Get("m_KeepOriginalOrientation").boolValue = value; } }
public bool keepOriginalPositionY { get { return Get("m_KeepOriginalPositionY").boolValue; } set { Get("m_KeepOriginalPositionY").boolValue = value; } }
public bool keepOriginalPositionXZ { get { return Get("m_KeepOriginalPositionXZ").boolValue; } set { Get("m_KeepOriginalPositionXZ").boolValue = value; } }
public bool heightFromFeet { get { return Get("m_HeightFromFeet").boolValue; } set { Get("m_HeightFromFeet").boolValue = value; } }
public bool mirror { get { return Get("m_Mirror").boolValue; } set { Get("m_Mirror").boolValue = value; } }
}