using System.Collections; using System.Collections.Generic; using UnityEngine; namespace BF { [System.Serializable] public struct CharacterSpineObjectInfo { public uint hashName; public UnityEngine.GameObject gameObject; } [ExecuteInEditMode] [DisallowMultipleComponent] public class CharacterSpineHelper : MonoBehaviour { public GameObject SpineObject; public List ObjectList = new List(); public float PositionX { get; private set; } public float PositionY { get; private set; } public float PositionZ { get; private set; } private Spine.Unity.SkeletonGraphic skeletonGraphic; private Spine.AnimationState animationState; void Awake() { skeletonGraphic = SpineObject.GetComponent(); animationState = skeletonGraphic.AnimationState; } public void Reload() { animationState = skeletonGraphic.AnimationState; } public void PlayAnimation(string animName, bool loop, bool forceRefresh) { #if UNITY_EDITOR float duration = GetAnimationDuration(animName); if(BFLog.LogAssert(duration > 0, this.gameObject.name + " not have " + animName)) { return; } #endif animationState.SetAnimation(0, animName, loop); if (forceRefresh) { skeletonGraphic.Update(0); } } public void SetAnimationSpeed(float timeScale) { skeletonGraphic.timeScale = timeScale; } public void SetLoop(bool isLoop) { skeletonGraphic.startingLoop = isLoop; } public GameObject GetSpineObject() { return SpineObject; } public Spine.Unity.SkeletonGraphic GetSkeletonGraphic() { return skeletonGraphic; } public int GetListCount() { return ObjectList.Count; } public GameObject GetGameObjectByIndex(int index) { if (index >= 0 && index < ObjectList.Count) { return ObjectList[index].gameObject; } else if (index < 0) { return this.gameObject; } return null; } public uint GetHashNameByIndex(int index) { if (index >= 0 && index < ObjectList.Count) { return ObjectList[index].hashName; } return 0; } public int GetInstanceID(int index) { if (index >= 0 && index < ObjectList.Count) { return ObjectList[index].gameObject.GetInstanceID(); } return gameObject.GetInstanceID(); } // Lua层可以使用PositionX,PositionY,PositionZ,减少直接传递localPosition的开销 public void CacheLocalPosition(int index) { if (index >= 0 && index < ObjectList.Count) { var localPosition = ObjectList[index].gameObject.transform.localPosition; PositionX = localPosition.x; PositionY = localPosition.y; PositionZ = localPosition.z; } else if (index < 0) { PositionX = this.transform.localPosition.x; PositionY = this.transform.localPosition.y; PositionZ = this.transform.localPosition.z; } } public void SetLocalPosition(int index, float x, float y, float z) { if (index >= 0 && index < ObjectList.Count) { ObjectList[index].gameObject.transform.localPosition = new Vector3(x, y, z); } else if (index < 0) { this.transform.localPosition = new Vector3(x, y, z); } } // Lua层可以使用PositionX,PositionY,PositionZ,减少直接传递position的开销 public void CachePosition(int index) { if (index >= 0 && index < ObjectList.Count) { var position = ObjectList[index].gameObject.transform.position; PositionX = position.x; PositionY = position.y; PositionZ = position.z; } else if (index < 0) { PositionX = this.transform.position.x; PositionY = this.transform.position.y; PositionZ = this.transform.position.z; } } public void CacheBonePosition(string name) { var skeleton = skeletonGraphic.Skeleton; var bone = skeleton.FindBone(name); if (bone != null) { Vector3 unityWorldPosition = skeletonGraphic.transform.TransformPoint(new Vector3(bone.WorldX, bone.WorldY, 0.0f)); PositionX = unityWorldPosition.x; PositionY = unityWorldPosition.y; PositionZ = unityWorldPosition.z; } else { PositionX = 0.0f; PositionY = 0.0f; PositionZ = 0.0f; } } public void SetPosition(int index, float x, float y, float z) { if (index >= 0 && index < ObjectList.Count) { ObjectList[index].gameObject.transform.position = new Vector3(x, y, z); } else if (index < 0) { this.transform.position = new Vector3(x, y, z); } } public void SetLocalEulerAngles(int index, float x, float y, float z) { if (index >= 0 && index < ObjectList.Count) { ObjectList[index].gameObject.transform.localEulerAngles = new Vector3(x, y, z); } else if (index < 0) { this.transform.localEulerAngles = new Vector3(x, y, z); } } public void setEulerAngles(int index, float x, float y, float z) { if (index >= 0 && index < ObjectList.Count) { ObjectList[index].gameObject.transform.eulerAngles = new Vector3(x, y, z); } else if (index < 0) { this.transform.eulerAngles = new Vector3(x, y, z); } } public void SetLocalScale(int index, float x, float y, float z) { if (index >= 0 && index < ObjectList.Count) { ObjectList[index].gameObject.transform.localScale = new Vector3(x, y, z); } else if (index < 0) { this.transform.localScale = new Vector3(x, y, z); } } public void SetLocalScaleX(int index, float x) { if (index >= 0 && index < ObjectList.Count) { var transform = ObjectList[index].gameObject.transform; transform.localScale = new Vector3(x, transform.localScale.y, transform.localScale.z); } else if (index < 0) { transform.localScale = new Vector3(x, transform.localScale.y, transform.localScale.z); } } public void SetMainSpineLocalPosition(float x, float y, float z) { SpineObject.transform.localPosition = new Vector3(x, y, z); } public float GetAnimationDuration(string name) { Spine.Animation animation = skeletonGraphic.skeletonDataAsset.GetAnimationStateData().SkeletonData.FindAnimation(name); if (animation == null){ return 0.0f; } return animation.Duration; } public float GetAnimationKeyFrameTime(string name) { float time = 0.0f; var animation = skeletonGraphic.skeletonDataAsset.GetAnimationStateData().SkeletonData.FindAnimation(name); foreach (var timeline in animation.Timelines) { var eventTimeline = timeline as Spine.EventTimeline; if (eventTimeline != null && eventTimeline.Events.Length > 0) { time = eventTimeline.Events[0].Time; } } return time; } public void SetDefaultMix(float mixDuration) { skeletonGraphic.skeletonDataAsset.GetAnimationStateData().DefaultMix = mixDuration; } public void PlayAnimationAndPause(string animName, float percent) { skeletonGraphic.timeScale = 1; animationState.SetAnimation(0, animName, false); var duration = GetAnimationDuration(animName); skeletonGraphic.Update(percent * duration); skeletonGraphic.timeScale = 0; } } }