關於自動產生動畫,雨松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; } } }