|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | using System; | 
|---|
|  |  |  | using Spine.Unity; | 
|---|
|  |  |  | using UnityEngine; | 
|---|
|  |  |  | using UnityEngine.EventSystems; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public class UIHeroController : MonoBehaviour | 
|---|
|  |  |  | { | 
|---|
|  |  |  | public static UIHeroController Create(HeroSkinConfig skinCfg, Transform _parent = null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | // GameObject battleGO = ResManager.Instance.LoadAsset<GameObject>("Hero/SpineRes", skinCfg == null ? "Hero_001" : skinCfg.SpineRes); | 
|---|
|  |  |  | GameObject battleGO = ResManager.Instance.LoadAsset<GameObject>("Hero/SpineRes", "Hero_001"); | 
|---|
|  |  |  | GameObject instanceGO = null; | 
|---|
|  |  |  | if (_parent != null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | instanceGO = GameObject.Instantiate(battleGO, _parent); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | else | 
|---|
|  |  |  | { | 
|---|
|  |  |  | instanceGO = GameObject.Instantiate(battleGO); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | UIHeroController heroController = instanceGO.AddMissingComponent<UIHeroController>(); | 
|---|
|  |  |  | return heroController; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private GameObjectPoolManager.GameObjectPool pool; | 
|---|
|  |  |  | private int skinID; | 
|---|
|  |  |  | protected SkeletonGraphic skeletonGraphic; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | protected Spine.AnimationState spineAnimationState; | 
|---|
|  |  |  | private GameObject instanceGO; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private Spine.TrackEntry currentTrackEntry; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private UIEventTrigger uiEventTrigger; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | void Awake() | 
|---|
|  |  |  | private Action onComplete; | 
|---|
|  |  |  | public void Create(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | skeletonGraphic = gameObject.GetComponentInChildren<SkeletonGraphic>(true); | 
|---|
|  |  |  | uiEventTrigger = UIEventTrigger.Get(skeletonGraphic.gameObject); | 
|---|
|  |  |  | if (skinID == _skinID) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | //避免重复创建 | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | uiEventTrigger.OnClick = OnClick; | 
|---|
|  |  |  | skinID = _skinID; | 
|---|
|  |  |  | onComplete = _onComplete; | 
|---|
|  |  |  | pool = GameObjectPoolManager.Instance.RequestPool(UILoader.LoadPrefab("UIHero")); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!transform.gameObject.activeSelf) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | transform.SetActive(true); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (instanceGO == null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | instanceGO = pool.Request(); | 
|---|
|  |  |  | instanceGO.transform.SetParent(transform); | 
|---|
|  |  |  | //transform 的Pivot Y是0,让instanceGO 居中 | 
|---|
|  |  |  | instanceGO.transform.localPosition = new Vector3(0, instanceGO.GetComponent<RectTransform>().sizeDelta.y * 0.5f); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //instanceGO.transform.localPosition = Vector3.zero; | 
|---|
|  |  |  | instanceGO.transform.localScale = Vector3.one; | 
|---|
|  |  |  | instanceGO.transform.localRotation = Quaternion.identity; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | skeletonGraphic = instanceGO.GetComponentInChildren<SkeletonGraphic>(true); | 
|---|
|  |  |  | var skinConfig = HeroSkinConfig.Get(skinID); | 
|---|
|  |  |  | if (isLh) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | skeletonGraphic.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("Hero/SpineRes/", skinConfig.Tachie); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | else | 
|---|
|  |  |  | { | 
|---|
|  |  |  | skeletonGraphic.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("Hero/SpineRes/", skinConfig.SpineRes); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (skeletonGraphic.skeletonDataAsset == null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | transform.SetActive(false); | 
|---|
|  |  |  | if (pool != null) | 
|---|
|  |  |  | pool.Release(instanceGO); | 
|---|
|  |  |  | skeletonGraphic = null; | 
|---|
|  |  |  | Destroy(instanceGO); | 
|---|
|  |  |  | Debug.LogError("未配置spine"); | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | skeletonGraphic.Initialize(true); | 
|---|
|  |  |  | this.transform.localScale = Vector3.one * scale; | 
|---|
|  |  |  | spineAnimationState = skeletonGraphic.AnimationState; | 
|---|
|  |  |  | PlayAnimation(MotionName.idle, true); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | spineAnimationState.Data.DefaultMix = 0f; | 
|---|
|  |  |  | if (motionName == "") | 
|---|
|  |  |  | motionName = GetFistSpineAnim(); | 
|---|
|  |  |  | PlayAnimation(motionName, true); | 
|---|
|  |  |  | spineAnimationState.Complete -= OnAnimationComplete; | 
|---|
|  |  |  | spineAnimationState.Complete += OnAnimationComplete; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | void Destroy() | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | protected void OnDestroy() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | spineAnimationState.Complete -= OnAnimationComplete; | 
|---|
|  |  |  | if (spineAnimationState != null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | spineAnimationState.Complete -= OnAnimationComplete; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (pool != null) | 
|---|
|  |  |  | pool.Release(instanceGO); | 
|---|
|  |  |  | skeletonGraphic = null; | 
|---|
|  |  |  | pool = null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public virtual Spine.TrackEntry PlayAnimation(MotionName motionName, bool loop = false) | 
|---|
|  |  |  | public virtual void PlayAnimation(string motionName, bool loop = false) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (spineAnimationState == null) return null; | 
|---|
|  |  |  | if (spineAnimationState == null) return; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 直接使用 ToString() 而不是调用 GetAnimationName | 
|---|
|  |  |  | currentTrackEntry = spineAnimationState.SetAnimation(0, motionName.ToString(), loop); | 
|---|
|  |  |  | return currentTrackEntry; | 
|---|
|  |  |  | // 直接使用 ToString() 而不是调用 GetAnimationName | 
|---|
|  |  |  | spineAnimationState.SetAnimation(0, motionName.ToString(), loop); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /// <summary> | 
|---|
|  |  |  | /// 动画完成事件处理 | 
|---|
|  |  |  | /// </summary> | 
|---|
|  |  |  | protected virtual void OnAnimationComplete(Spine.TrackEntry trackEntry) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | // string animation = trackEntry.Animation.Name; | 
|---|
|  |  |  | PlayAnimation(MotionName.idle, true); | 
|---|
|  |  |  | // 播放第一个动画(作为默认动画) | 
|---|
|  |  |  | string GetFistSpineAnim() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | var skeletonData = skeletonGraphic.Skeleton.Data; | 
|---|
|  |  |  | if (skeletonData.Animations.Count > 0) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | return skeletonData.Animations.Items[0].Name; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | else | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogError("Spine 数据中没有找到任何动画!武将皮肤:" + skinID); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return ""; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | protected void OnClick(GameObject go,PointerEventData eventData) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | PlayAnimation(MotionName.attack); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | /// <summary> | 
|---|
|  |  |  | /// 动画完成事件处理 | 
|---|
|  |  |  | /// </summary> | 
|---|
|  |  |  | protected virtual void OnAnimationComplete(Spine.TrackEntry trackEntry) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | onComplete?.Invoke(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|