using System; 
 | 
using System.Collections; 
 | 
using System.Collections.Generic; 
 | 
using Spine.Unity; 
 | 
using UnityEngine; 
 | 
using Spine; 
 | 
using UnityEngine.UI; 
 | 
using System.Linq; 
 | 
  
 | 
// 特效播放器,对象池管理:unity特效和spine特效都是做好的预制体 
 | 
// unity特效预制体是特效师在制作的时候生成的,unity特效必须挂载设置播放时长脚本 EffectTime 
 | 
// spine特效是特效师制作的动画文件可直接加载用,制作成预制体可增加BoneFollower之类的进行逻辑处理 
 | 
public class BattleEffectPlayer : MonoBehaviour 
 | 
{ 
 | 
    [SerializeField] 
 | 
    private int m_EffectID; 
 | 
    public int effectId 
 | 
    { 
 | 
        get 
 | 
        { 
 | 
            return m_EffectID; 
 | 
        } 
 | 
        set 
 | 
        { 
 | 
            if (value != m_EffectID) 
 | 
            { 
 | 
                isInit = false; 
 | 
                m_EffectID = value; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private Bone followedBone; 
 | 
  
 | 
    public bool isBindBone = false; 
 | 
  
 | 
    public bool isRedCamp = true; 
 | 
    public EffectConfig effectConfig; 
 | 
  
 | 
    public float speedRate = 1.5f; 
 | 
  
 | 
    private float m_Alpha = 1f; 
 | 
  
 | 
    public float Alpha 
 | 
    { 
 | 
        get 
 | 
        { 
 | 
            return m_Alpha; 
 | 
        } 
 | 
        set 
 | 
        { 
 | 
            if (value == m_Alpha) 
 | 
                return; 
 | 
  
 | 
            m_Alpha = value; 
 | 
            OnAlphaChanged(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private void OnAlphaChanged() 
 | 
    { 
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            var skeleton = spineComp.Skeleton; 
 | 
            skeleton.A = Alpha; 
 | 
            spineComp.LateUpdate(); 
 | 
        } 
 | 
  
 | 
        for (int i = 0; i < rendererList.Count; i++) 
 | 
        { 
 | 
            var renderer = rendererList[i]; 
 | 
            if (renderer != null && renderer.material != null && renderer.material.HasProperty("_Color")) 
 | 
            { 
 | 
                Color color = renderer.material.color; 
 | 
                color.a = Alpha; 
 | 
                renderer.material.color = color; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    [Header("播放完毕立即回收")] 
 | 
    public bool isReleaseImmediately = false;  //界面特效一般不需要自我销毁,跟随界面或者父对象销毁就行 
 | 
  
 | 
    public Action<BattleEffectPlayer> onDestroy; 
 | 
  
 | 
    [HideInInspector] public GameObject effectTarget = null; 
 | 
  
 | 
    protected RendererAdjuster blocker = null; 
 | 
  
 | 
    protected bool isInit = false; 
 | 
  
 | 
    protected List<ParticleSystem> particleList = new List<ParticleSystem>(); 
 | 
  
 | 
    protected List<Animator> animatorList = new List<Animator>(); 
 | 
  
 | 
    protected List<Renderer> rendererList = new List<Renderer>(); 
 | 
  
 | 
    protected GameObject spineContainer; 
 | 
  
 | 
    protected SkeletonAnimation spineComp; 
 | 
    protected Spine.AnimationState spineAnimationState; 
 | 
  
 | 
    public GameObjectPoolManager.GameObjectPool pool; 
 | 
  
 | 
    public Action onComplete; 
 | 
  
 | 
    private bool isPlaying = false; 
 | 
  
 | 
    private float timer = 0f; 
 | 
  
 | 
    protected virtual void OnEnable() 
 | 
    { 
 | 
        // if (spineComp != null) 
 | 
        // { 
 | 
        //     //隐藏,会有静态显示问题 
 | 
        //     spineComp.enabled = false; 
 | 
        // } 
 | 
  
 | 
        ApplySortingOrder(); 
 | 
    } 
 | 
  
 | 
  
 | 
    protected void InitComponent(bool showLog = true) 
 | 
    { 
 | 
        Clear(); 
 | 
        if (effectId <= 0) 
 | 
        { 
 | 
            effectConfig = null; 
 | 
#if UNITY_EDITOR 
 | 
            if (showLog) 
 | 
            { 
 | 
                Debug.LogError("BattleEffectPlayer effectId is not set"); 
 | 
                UnityEditor.Selection.activeGameObject = gameObject; 
 | 
                UnityEditor.EditorGUIUtility.PingObject(gameObject); 
 | 
            } 
 | 
#endif 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        effectConfig = EffectConfig.Get(effectId); 
 | 
  
 | 
        if (null == effectConfig) 
 | 
        { 
 | 
#if UNITY_EDITOR 
 | 
            Debug.LogError("could not find effect config, effect id is " + effectId); 
 | 
            UnityEditor.Selection.activeGameObject = gameObject; 
 | 
            UnityEditor.EditorGUIUtility.PingObject(gameObject); 
 | 
#endif 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        //  初始化spine组件 
 | 
        if (effectConfig != null && effectConfig.isSpine != 0) 
 | 
        { 
 | 
            GameObject spineContainerPrefab = ResManager.Instance.LoadAsset<GameObject>("UIComp", "SpineAnimContainer"); 
 | 
            spineContainer = GameObject.Instantiate(spineContainerPrefab, transform, true); 
 | 
            spineContainer.transform.localPosition = Vector3.zero; 
 | 
        } 
 | 
        //  有特效可能带spine又带unity特效的情况 
 | 
        spineComp = gameObject.GetComponentInChildren<SkeletonAnimation>(true); 
 | 
  
 | 
        if (effectConfig.effectPos != null && effectConfig.effectPos.Length >= 2) 
 | 
        { 
 | 
            rectTrans.anchoredPosition += new Vector2((isRedCamp ? 1f : -1f) * effectConfig.effectPos[0], effectConfig.effectPos[1]); 
 | 
        } 
 | 
  
 | 
        if (effectConfig.effectScale > 0f) 
 | 
        { 
 | 
            rectTrans.localScale *= effectConfig.effectScale; 
 | 
        } 
 | 
  
 | 
        spineComp.loop = effectConfig.isLoop != 0; 
 | 
    } 
 | 
  
 | 
    protected virtual void Clear() 
 | 
    { 
 | 
        particleList.Clear(); 
 | 
        animatorList.Clear(); 
 | 
        rendererList.Clear(); 
 | 
        spineComp = null; 
 | 
        spineAnimationState = null; 
 | 
        if (null != spineContainer) 
 | 
            GameObject.DestroyImmediate(spineContainer); 
 | 
        spineContainer = null; 
 | 
        pool = null; 
 | 
    } 
 | 
  
 | 
    public virtual void Stop() 
 | 
    { 
 | 
        if (null != effectTarget) 
 | 
        { 
 | 
            // 如果使用了特效预制体池,则归还到池中 
 | 
            if (pool != null) 
 | 
            { 
 | 
                pool.Release(effectTarget); 
 | 
            } 
 | 
            effectTarget = null; 
 | 
        } 
 | 
  
 | 
        isInit = false; 
 | 
  
 | 
        Clear(); 
 | 
        onComplete?.Invoke(); 
 | 
    } 
 | 
  
 | 
    public Func<bool> funcIsHeroFront; 
 | 
  
 | 
    public void SetSortingOrder(Func<bool> _isHeroFrontCallback) 
 | 
    { 
 | 
        funcIsHeroFront = _isHeroFrontCallback; 
 | 
  
 | 
        ApplySortingOrder(); 
 | 
    } 
 | 
  
 | 
  
 | 
    public void ApplySortingOrder() 
 | 
    { 
 | 
        if (null != blocker && effectConfig != null && funcIsHeroFront != null) 
 | 
        { 
 | 
            bool isEffectFront = effectConfig.frontBack == 1; 
 | 
  
 | 
            bool isHeroFront = funcIsHeroFront(); 
 | 
  
 | 
            int finalSortingOrder = isHeroFront ? 
 | 
                (isEffectFront ? BattleConst.ActiveHeroActionSortingOrder : BattleConst.ActiveHeroBackSortingOrder) : (isEffectFront ? BattleConst.UnactiveHeroFrontSortingOrder : BattleConst.UnactiveHeroBackSortingOrder); 
 | 
  
 | 
  
 | 
            blocker.SetSortingOrder(finalSortingOrder); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public void FollowBoneXY() 
 | 
    { 
 | 
        if (followedBone == null || !isBindBone) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        Vector2 vector2 = Vector2.zero; 
 | 
  
 | 
        if (effectConfig.effectPos != null && effectConfig.effectPos.Length >= 2) 
 | 
        { 
 | 
            vector2 = new Vector2((isRedCamp ? 1f : -1f) * effectConfig.effectPos[0], effectConfig.effectPos[1]); 
 | 
        } 
 | 
  
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.transform.localPosition = new Vector3(followedBone.WorldX + vector2.x, followedBone.WorldY + vector2.y, 0); 
 | 
        } 
 | 
  
 | 
        if (effectTarget != null) 
 | 
        { 
 | 
            effectTarget.transform.localPosition = new Vector3(followedBone.WorldX + vector2.x, followedBone.WorldY + vector2.y, 0); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public virtual void Play(bool showLog = true) 
 | 
    { 
 | 
        if (!isInit) 
 | 
        { 
 | 
            InitComponent(showLog); 
 | 
            isInit = true; 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            //避免重复创建 
 | 
            if (!this.gameObject.activeSelf) 
 | 
            { 
 | 
                this.gameObject.SetActive(true); 
 | 
            } 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (EffectMgr.IsNotShowBySetting(effectId)) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (null != effectTarget) 
 | 
        { 
 | 
            if (pool != null) 
 | 
                pool.Release(effectTarget); 
 | 
            effectTarget = null; 
 | 
        } 
 | 
  
 | 
        if (!this.gameObject.activeSelf) 
 | 
        { 
 | 
            this.gameObject.SetActive(true); 
 | 
        } 
 | 
  
 | 
        isPlaying = true; 
 | 
        timer = 0f; 
 | 
  
 | 
        PlayEffect(); 
 | 
    } 
 | 
  
 | 
  
 | 
  
 | 
    public void Run() 
 | 
    { 
 | 
        if (null == effectConfig) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (!isPlaying) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (effectConfig.autoDestroy != 0) 
 | 
        { 
 | 
            timer += Time.deltaTime * speedRate; 
 | 
            if (timer >= effectConfig.destroyDelay) 
 | 
            { 
 | 
                GameObject.DestroyImmediate(gameObject); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    protected virtual void PlayEffect() 
 | 
    { 
 | 
        if (null == effectConfig) 
 | 
        { 
 | 
            Debug.LogError("BattleEffectPlayer effectConfig is null, effect id is " + effectId); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        //  如果delay小于等于0 那会立刻执行 
 | 
        this.DelayTime(effectConfig.delayPlay / speedRate, () => 
 | 
        { 
 | 
            PlayEffectInternal(); 
 | 
        }); 
 | 
    } 
 | 
  
 | 
    protected void PlayEffectInternal() 
 | 
    { 
 | 
        if (effectConfig.isSpine != 0) 
 | 
        { 
 | 
            PlaySpineEffect(); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            PlayUnityEffect(); 
 | 
        } 
 | 
        OnAlphaChanged(); 
 | 
    } 
 | 
  
 | 
    protected void PlaySpineEffect() 
 | 
    { 
 | 
        //  这里是纯spine的逻辑 
 | 
  
 | 
        if (spineComp == null) 
 | 
        { 
 | 
            Debug.LogError("BattleEffectPlayer spineComp is null, effect id is " + effectId); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        SkeletonDataAsset skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("UIEffect/" + effectConfig.packageName, effectConfig.fxName); 
 | 
        spineComp.skeletonDataAsset = skeletonDataAsset; 
 | 
        spineComp.Initialize(true); 
 | 
        spineComp.timeScale = speedRate; 
 | 
  
 | 
        spineComp.skeleton.A = Alpha; 
 | 
  
 | 
        spineAnimationState = spineComp.state; 
 | 
        spineAnimationState.Complete -= OnSpineAnimationComplete; 
 | 
        spineAnimationState.Complete += OnSpineAnimationComplete; 
 | 
  
 | 
        // 添加特效穿透阻挡器 
 | 
        blocker = spineComp.AddMissingComponent<RendererAdjuster>(); 
 | 
  
 | 
        blocker.onSortingChanged = OnSortingChanged; 
 | 
  
 | 
        ApplySortingOrder(); 
 | 
  
 | 
        spineComp.enabled = true; 
 | 
  
 | 
        spineComp.timeScale = speedRate; 
 | 
  
 | 
        Spine.Animation animation = spineAnimationState.Data.SkeletonData.Animations.First(); 
 | 
        spineAnimationState.SetAnimation(0, animation, effectConfig.isLoop != 0); 
 | 
  
 | 
        SoundPlayer.Instance.PlayUIAudio(effectConfig.audio); 
 | 
  
 | 
    } 
 | 
  
 | 
    private bool CheckForAdditiveBlend(Spine.Skeleton skeleton) 
 | 
    { 
 | 
        // 遍历所有插槽,检查是否有相加模式 
 | 
        foreach (var slot in skeleton.Slots) 
 | 
        { 
 | 
            if (slot.Data.BlendMode == Spine.BlendMode.Additive) 
 | 
            { 
 | 
                return true; 
 | 
            } 
 | 
        } 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    protected void PlayUnityEffect() 
 | 
    { 
 | 
        //  这里是纯unity特效的逻辑 
 | 
  
 | 
        var effectPrefab = ResManager.Instance.LoadAsset<GameObject>("UIEffect/" + effectConfig.packageName, effectConfig.fxName); 
 | 
        if (effectPrefab == null) 
 | 
        { 
 | 
            Debug.LogError($"加载UI特效失败: {effectConfig.packageName}"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.enabled = true; 
 | 
        } 
 | 
  
 | 
        // 从特效预制体池获取特效 
 | 
        pool = GameObjectPoolManager.Instance.RequestPool(effectPrefab); 
 | 
        effectTarget = pool.Request(); 
 | 
        // 设置父节点和位置 
 | 
        effectTarget.transform.SetParent(transform); 
 | 
        effectTarget.transform.localPosition = Vector3.zero; 
 | 
        effectTarget.transform.localScale = Vector3.one; 
 | 
        effectTarget.transform.localRotation = Quaternion.identity; 
 | 
        effectTarget.name = $"Effect_{effectConfig.fxName}"; 
 | 
  
 | 
        //挂载组件后 开始收集 
 | 
        particleList.AddRange(gameObject.GetComponentsInChildren<ParticleSystem>(true)); 
 | 
        animatorList.AddRange(gameObject.GetComponentsInChildren<Animator>(true)); 
 | 
        rendererList.AddRange(gameObject.GetComponentsInChildren<Renderer>(true)); 
 | 
  
 | 
        OnUnityAnimationComplete(); 
 | 
  
 | 
  
 | 
        // 添加特效穿透阻挡器 
 | 
        blocker = effectTarget.AddMissingComponent<RendererAdjuster>(); 
 | 
  
 | 
        blocker.onSortingChanged = OnSortingChanged; 
 | 
  
 | 
        SoundPlayer.Instance.PlayUIAudio(effectConfig.audio); 
 | 
  
 | 
    } 
 | 
  
 | 
    void LateUpdate() 
 | 
    { 
 | 
        if (string.IsNullOrEmpty(sortingLayer)) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        OnSortingChanged(sortingLayer, sortingOrder); 
 | 
    } 
 | 
  
 | 
    public string sortingLayer; 
 | 
    public int sortingOrder; 
 | 
    public RectTransform rectTrans; 
 | 
  
 | 
    protected void OnSortingChanged(string _sortingLayer, int _sortingOrder) 
 | 
    { 
 | 
        if (null == spineComp) 
 | 
            return; 
 | 
             
 | 
        sortingLayer = _sortingLayer; 
 | 
        sortingOrder = _sortingOrder; 
 | 
        // 处理排序变化 
 | 
        var renderers = spineComp.GetComponents<Renderer>(); 
 | 
        foreach (var renderer in renderers) 
 | 
        { 
 | 
            renderer.sortingLayerName = sortingLayer; 
 | 
            renderer.sortingOrder = sortingOrder; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    protected void OnDestroy() 
 | 
    { 
 | 
        if (onDestroy != null) 
 | 
        { 
 | 
            onDestroy.Invoke(this); 
 | 
            onDestroy = null; 
 | 
        } 
 | 
        // 停止特效并归还到池中  
 | 
        Stop(); 
 | 
  
 | 
        if (spineAnimationState != null) 
 | 
        { 
 | 
            spineAnimationState.Complete -= OnSpineAnimationComplete; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    //单次播放完毕就会触发,即使是循环 
 | 
    protected virtual void OnSpineAnimationComplete(Spine.TrackEntry trackEntry) 
 | 
    { 
 | 
        if (isReleaseImmediately) 
 | 
        { 
 | 
            spineComp.enabled = false; 
 | 
            Stop(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
    private void OnUnityAnimationComplete() 
 | 
    { 
 | 
        var timeObj = effectTarget.GetComponent<EffectTime>(); 
 | 
        if (!timeObj.isLoop) 
 | 
        { 
 | 
            this.SetWait(timeObj.playTime); 
 | 
            this.DoWaitRestart(); 
 | 
            this.OnWaitCompelete(OnEffectComplete); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private void OnEffectComplete(Component comp) 
 | 
    { 
 | 
        this.DoWaitStop(); 
 | 
        if (isReleaseImmediately) 
 | 
            Stop(); 
 | 
    } 
 | 
  
 | 
  
 | 
    //  创建后的特效会自动隐藏 需要手动调用Play才能播放 
 | 
    public static BattleEffectPlayer Create(int effectId, Transform parent, bool isRedCamp) 
 | 
    { 
 | 
        // 直接创建特效播放器,不使用对象池 
 | 
        BattleEffectPlayer battleEffectPlayer = null; 
 | 
  
 | 
        GameObject newGo = new GameObject("BattleEffectPlayer_" + effectId); 
 | 
        newGo.transform.SetParent(parent, false); 
 | 
        battleEffectPlayer = newGo.AddComponent<BattleEffectPlayer>(); 
 | 
        battleEffectPlayer.rectTrans = newGo.AddMissingComponent<RectTransform>(); 
 | 
         
 | 
        battleEffectPlayer.effectId = effectId; 
 | 
  
 | 
        // 设置阵营 
 | 
        battleEffectPlayer.isRedCamp = isRedCamp; 
 | 
  
 | 
        battleEffectPlayer.SetActive(true); 
 | 
        return battleEffectPlayer; 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 设置游戏对象激活状态 
 | 
    // /// </summary> 
 | 
    // public void SetActive(bool active) 
 | 
    // { 
 | 
    //     if (gameObject != null) 
 | 
    //     { 
 | 
    //         gameObject.SetActive(active); 
 | 
    //     } 
 | 
    // } 
 | 
  
 | 
    public void Pause() 
 | 
    { 
 | 
        // if (effectTarget == null) return; 
 | 
  
 | 
        // Spine动画 
 | 
        // var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(true); 
 | 
        // foreach (var sg in spineGraphics) 
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.timeScale = 0f; 
 | 
        } 
 | 
  
 | 
        // Animator动画 
 | 
        foreach (var animator in animatorList) 
 | 
        { 
 | 
            animator.speed = 0f; 
 | 
        } 
 | 
  
 | 
        // 粒子特效 
 | 
        foreach (var ps in particleList) 
 | 
        { 
 | 
            ps.Pause(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public void Resume() 
 | 
    { 
 | 
        // if (effectTarget == null) return; 
 | 
  
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.timeScale = speedRate; 
 | 
        } 
 | 
  
 | 
        // Animator动画 
 | 
        foreach (var animator in animatorList) 
 | 
        { 
 | 
            animator.speed = speedRate; 
 | 
        } 
 | 
  
 | 
        // 粒子特效 
 | 
        foreach (var ps in particleList) 
 | 
        { 
 | 
            ps.Play(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public bool IsFinish() 
 | 
    { 
 | 
        if (effectTarget == null) return true; 
 | 
  
 | 
        // Spine动画 
 | 
        if (!spineComp.AnimationState.GetCurrent(0).IsComplete) 
 | 
        { 
 | 
            return false; 
 | 
        } 
 | 
  
 | 
        // Animator动画 
 | 
        foreach (var animator in animatorList) 
 | 
        { 
 | 
            AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); 
 | 
  
 | 
            //  循环动画不考虑结束的问题 
 | 
            if (!stateInfo.loop && stateInfo.normalizedTime < 1f) 
 | 
            { 
 | 
                return false; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        // 粒子特效 
 | 
        foreach (var ps in particleList) 
 | 
        { 
 | 
            if (ps.IsAlive()) 
 | 
            { 
 | 
                return false; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    public void SetSpeedRatio(float ratio) 
 | 
    { 
 | 
        speedRate = ratio; 
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.timeScale = speedRate; 
 | 
        } 
 | 
  
 | 
        // Animator动画 
 | 
        foreach (var animator in animatorList) 
 | 
        { 
 | 
            animator.speed = speedRate; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public void BindBone(SkeletonAnimation skeletonAnim, string v) 
 | 
    { 
 | 
        Bone bone = skeletonAnim.skeleton.FindBone(v); 
 | 
  
 | 
        if (null == bone) 
 | 
        { 
 | 
             return; 
 | 
        } 
 | 
  
 | 
        isBindBone = true; 
 | 
        followedBone = bone; 
 | 
  
 | 
        BoneFollower boneFollower = gameObject.AddMissingComponent<BoneFollower>(); 
 | 
        boneFollower.boneName = v; 
 | 
        boneFollower.skeletonRenderer = skeletonAnim; 
 | 
         
 | 
        boneFollower.followBoneRotation = false; 
 | 
        boneFollower.followXYPosition = true; 
 | 
        boneFollower.followZPosition = false; 
 | 
        boneFollower.followLocalScale = false; 
 | 
        boneFollower.followParentWorldScale = false; 
 | 
        boneFollower.followSkeletonFlip = false; 
 | 
  
 | 
        boneFollower.Initialize(); 
 | 
        boneFollower.LateUpdate(); 
 | 
    } 
 | 
} 
 |