using Spine; using Spine.Unity; using Spine.Unity.AttachmentTools; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Motion : MonoBehaviour { public enum Type { Idle, Run, RunBack, Attack, AttackUp, AttackDown, AttackEnd, Die, Hit, Idle2, Get, Appear } //public enum Emoji { Normal, Shoot } [System.Serializable] public class SpineControl { public Motion.Type type; //public Motion.Emoji emoji; [Space(10)] [SpineAnimation] public string name; public int layer = 1; public bool loop = false; [Space] public float timeScale = 1f; [Space] public bool useMixDuration = true; public float mixDuration = 0.1f; //public bool useChainToControl; //public int chainToControl; } public SkeletonAnimation skeletonAnimation; Spine.AnimationState spineState; Skeleton skeleton; [Space(10)] public List controls; Dictionary dicControls = null; List idles = null; void Start() { spineState = skeletonAnimation.state; skeleton = skeletonAnimation.Skeleton; if (dicControls == null) { dicControls = new Dictionary(); idles = new List(); for (int i = 0; i < controls.Count; i++) { if (controls[i].type == Type.Idle) idles.Add(controls[i]); else dicControls.Add(controls[i].type, controls[i]); } values = new List(dicControls.Values); } //Play(Type.Idle); } void OnEnable() { typeBefore = Motion.Type.AttackEnd; } void OnDisable() { Play(Type.Idle); } [Space(10)] public bool isATK = false; /// /// 공격 모션 중인지 확인합니다. /// /// public bool Check_ATK() { return typeBefore == Type.Attack; } /// /// 등장 모션 중인지 확인합니다. /// /// public bool Check_Appear() { return typeBefore == Type.Appear; } public Motion.Type typeBefore = Motion.Type.AttackEnd; /// /// 죽는 모션 중인지 확인합니다. /// /// public bool Check_Die() { return typeBefore == Type.Die; } /// /// 스파인 애니메이션을 재생합니다. /// /// /// true = 강제 재생 /// 모션 종료시 호출 /// 모션 이벤트 발생시 호출 /// public void Play(Motion.Type type, bool FORCE = false, System.Action OnEnd = null, System.Action OnEvent = null, bool RESET = false) { //if (Check_Die() && !FORCE)//원래 코드, 테스트 진행 후 이상 없으면 삭제 if (Check_Die()) return; if (FORCE || typeBefore != type) { if (dicControls == null) Start(); TrackEntry track = null; SpineControl control = null; if (type == Type.Idle) control = idles[Random.Range(0, idles.Count)]; else control = dicControls[type]; if (control == null) return; switch (type) { case Motion.Type.Attack: case Motion.Type.AttackUp: case Motion.Type.AttackDown: { isATK = true; typeBefore = type; track = spineState.SetAnimation(control.layer, control.name, control.loop); } break; case Type.AttackEnd: { if (isATK) { isATK = false; typeBefore = type; track = spineState.SetEmptyAnimation(control.layer, 0.2f); } } break; case Type.Hit: { typeBefore = type; track = spineState.SetAnimation(control.layer, control.name, control.loop); } break; default: { typeBefore = type; track = spineState.SetAnimation(control.layer, control.name, control.loop); } break; } if (track != null) { if (control != null) { track.MixDuration = control.useMixDuration ? control.mixDuration : 0; track.TimeScale = control.timeScale; } if (OnEnd != null) { track.Complete += delegate (TrackEntry entry) { OnEnd(); }; } if (OnEvent != null) { track.Event += delegate (TrackEntry trackEntry, Spine.Event e) { OnEvent(e); if (RESET) track.ResetEvent(); }; } } } } public bool isSkill = false; /// /// 애니메이션을 강제 재생 합니다. /// 현재는 캐릭터가 스킬을 사용할때만 사용되는 중입니다. /// /// /// /// /// public bool Play_Force(SpineControl control, System.Action OnEnd = null, System.Action OnEvent = null) { //if (Check_Die()) // return false; if (spineState == null) Start(); TrackEntry track = spineState.SetAnimation(control.layer, control.name, control.loop); if (track != null) { if (control != null) { track.MixDuration = control.useMixDuration ? control.mixDuration : 0; track.TimeScale = control.timeScale; } if (OnEnd != null) { track.Complete += delegate (TrackEntry entry) { OnEnd(); }; } if (OnEvent != null) { track.Event += delegate (TrackEntry trackEntry, Spine.Event e) { OnEvent(e); }; } } return true; } //public void Play_Force(string name, int layer, bool loop, System.Action OnEnd = null, System.Action OnEvent = null) //{ // if (Check_Die()) // return; // if (spineState == null) // Start(); // TrackEntry track = spineState.SetAnimation(layer, name, loop); // if (track != null) // { // if (OnEnd != null) // { // track.Complete += delegate (TrackEntry entry) // { // OnEnd(); // }; // } // if (OnEvent != null) // { // track.Event += delegate (TrackEntry trackEntry, Spine.Event e) // { // OnEvent(e); // }; // } // } //} //표정 변경 //public List controls_Emoji; //Dictionary dicControls_Emoji = new Dictionary(); //public void Play_Emoji(Motion.Emoji type) //{ // SpineControl control = dicControls_Emoji[type]; // spineState.SetAnimation(control.layer, control.name, control.loop); //} //public void ClearLayer(int layer) //{ // spineState.SetEmptyAnimation(layer, 0.2f); //} Vector3 scale = Vector3.one; /// /// 캐릭터가 바라볼 방향을 설정합니다. /// /// public void LookSet(float x) { scale.x = x == 0 ? 0 : (x < 0 ? -1 : 1); skeletonAnimation.transform.localScale = scale; } /// /// 바라보고 있는 방향을 확인합니다. /// /// public Vector3 LookDir() { return scale.x < 0 ? Vector3.right : Vector3.left; } [Space(10)] public List values; [Space(10)] //public float spdMovePer; public float spdDevision = 2f; /// /// 변경된 이동속도 값을 반영합니다. /// /// public void OnMoveSpeedChanged(float spd) { //spdMovePer = spd; //spdMovePer = 1 + (spd - (int)spd) * spdDevision; //values = new List(dicControls.Values); List list = values.FindAll(a => $"{a.type}".Contains("Run")); for (int i = 0; i < list.Count; i++) list[i].timeScale = timeScaleRun * spd; } /// /// 캐릭터의 모든 이동 애니메이션의 TimeSclae(재생 속도) 를 설정합니다. /// /// public float timeScaleRun = 1; public void RunMotionTimeScaleChanged(float value) { if (dicControls == null) Start(); SpineControl control = values.Find(a => a.type == Type.Run); control.timeScale = timeScaleRun = value; } public float spdAtkPer; /// /// 변경된 공격속도 값을 반영합니다. /// /// public void OnAttackSpeedChanged(float spd) { spdAtkPer = spd; //values = new List(dicControls.Values); List list = values.FindAll(a => $"{a.type}".Contains("Attack")); for (int i = 0; i < list.Count; i++) list[i].timeScale = spdAtkPer; } }