text:
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13

using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;

#pragma warning disable 1591
namespace DG.Tweening
{
    ///
    /// Shortcuts/functions that are not strictly related to specific Modules
    /// but are available only on some Unity versions
    ///
	public static class DOTweenModuleUnityVersion
    {
#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER
        #region Unity 4.3 or Newer

        #region Material

        /// Tweens a Material's color using the given gradient
        /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
        /// Also stores the image as the tween's inTarget so it can be used for filtered operations
        /// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
        public static Sequence DOGradientColor(this Material target, Gradient gradient, float duration)
        {
            Sequence s = DOTween.Sequence();
            GradientColorKey[] colors = gradient.colorKeys;
            int len = colors.Length;
            for (int i = 0; i < len; ++i) {
                GradientColorKey c = colors[i];
                if (i == 0 && c.time <= 0) {
                    target.color = c.color;
                    continue;
                }
                float colorDuration = i == len - 1
                    ? duration - s.Duration(false) // Verifies that total duration is correct
                    : duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
                s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
            }
            return s;
        }
        /// Tweens a Material's named color property using the given gradient
        /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
        /// Also stores the image as the tween's inTarget so it can be used for filtered operations
        /// <param name="gradient">The gradient to use</param>
        /// <param name="property">The name of the material property to tween (like _Tint or _SpecColor)</param>
        /// <param name="duration">The duration of the tween</param>
        public static Sequence DOGradientColor(this Material target, Gradient gradient, string property, float duration)
        {
            Sequence s = DOTween.Sequence();
            GradientColorKey[] colors = gradient.colorKeys;
            int len = colors.Length;
            for (int i = 0; i < len; ++i) {
                GradientColorKey c = colors[i];
                if (i == 0 && c.time <= 0) {
                    target.SetColor(property, c.color);
                    continue;
                }
                float colorDuration = i == len - 1
                    ? duration - s.Duration(false) // Verifies that total duration is correct
                    : duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
                s.Append(target.DOColor(c.color, property, colorDuration).SetEase(Ease.Linear));
            }
            return s;
        }

        #endregion

        #endregion
#endif

#if UNITY_5_3_OR_NEWER || UNITY_2017_1_OR_NEWER
        #region Unity 5.3 or Newer

        #region CustomYieldInstructions

        ///
        /// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or complete.
        /// It can be used inside a coroutine as a yield.
        /// <para>Example usage:</para>yield return myTween.WaitForCompletion(true);
        ///
        public static CustomYieldInstruction WaitForCompletion(this Tween t, bool returnCustomYieldInstruction)
        {
            if (!t.active) {
                if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
                return null;
            }
            return new DOTweenCYInstruction.WaitForCompletion(t);
        }

        ///
        /// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or rewinded.
        /// It can be used inside a coroutine as a yield.
        /// <para>Example usage:</para>yield return myTween.WaitForRewind();
        ///
        public static CustomYieldInstruction WaitForRewind(this Tween t, bool returnCustomYieldInstruction)
        {
            if (!t.active) {
                if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
                return null;
            }
            return new DOTweenCYInstruction.WaitForRewind(t);
        }

        ///
        /// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed.
        /// It can be used inside a coroutine as a yield.
        /// <para>Example usage:</para>yield return myTween.WaitForKill();
        ///
        public static CustomYieldInstruction WaitForKill(this Tween t, bool returnCustomYieldInstruction)
        {
            if (!t.active) {
                if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
                return null;
            }
            return new DOTweenCYInstruction.WaitForKill(t);
        }

        ///
        /// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or has gone through the given amount of loops.
        /// It can be used inside a coroutine as a yield.
        /// <para>Example usage:</para>yield return myTween.WaitForElapsedLoops(2);
        ///
        /// <param name="elapsedLoops">Elapsed loops to wait for</param>
        public static CustomYieldInstruction WaitForElapsedLoops(this Tween t, int elapsedLoops, bool returnCustomYieldInstruction)
        {
            if (!t.active) {
                if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
                return null;
            }
            return new DOTweenCYInstruction.WaitForElapsedLoops(t, elapsedLoops);
        }

        ///
        /// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or has reached the given position (loops included, delays excluded).
        /// It can be used inside a coroutine as a yield.
        /// <para>Example usage:</para>yield return myTween.WaitForPosition(2.5f);
        ///
        /// <param name="position">Position (loops included, delays excluded) to wait for</param>
        public static CustomYieldInstruction WaitForPosition(this Tween t, float position, bool returnCustomYieldInstruction)
        {
            if (!t.active) {
                if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
                return null;
            }
            return new DOTweenCYInstruction.WaitForPosition(t, position);
        }

        ///
        /// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or started
        /// (meaning when the tween is set in a playing state the first inTime, after any eventual delay).
        /// It can be used inside a coroutine as a yield.
        /// <para>Example usage:</para>yield return myTween.WaitForStart();
        ///
        public static CustomYieldInstruction WaitForStart(this Tween t, bool returnCustomYieldInstruction)
        {
            if (!t.active) {
                if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
                return null;
            }
            return new DOTweenCYInstruction.WaitForStart(t);
        }

        #endregion

        #endregion
#endif

#if UNITY_2018_1_OR_NEWER
        #region Unity 2018.1 or Newer

        #region Material

        /// Tweens a Material's named texture inOffset property with the given ID to the given value.
        /// Also stores the material as the tween's inTarget so it can be used for filtered operations
        /// <param name="endValue">The end value to reach</param>
        /// <param name="propertyID">The ID of the material property to tween (also called nameID in Unity's manual)</param>
        /// <param name="duration">The duration of the tween</param>
        public static TweenerCore<Vector2, Vector2, VectorOptions> DOOffset(this Material target, Vector2 endValue, int propertyID, float duration)
        {
            if (!target.HasProperty(propertyID)) {
                if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID);
                return null;
            }
            TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.GetTextureOffset(propertyID), x => target.SetTextureOffset(propertyID, x), endValue, duration);
            t.SetTarget(target);
            return t;
        }

        /// Tweens a Material's named texture scale property with the given ID to the given value.
        /// Also stores the material as the tween's inTarget so it can be used for filtered operations
        /// <param name="endValue">The end value to reach</param>
        /// <param name="propertyID">The ID of the material property to tween (also called nameID in Unity's manual)</param>
        /// <param name="duration">The duration of the tween</param>
        public static TweenerCore<Vector2, Vector2, VectorOptions> DOTiling(this Material target, Vector2 endValue, int propertyID, float duration)
        {
            if (!target.HasProperty(propertyID)) {
                if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID);
                return null;
            }
            TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.GetTextureScale(propertyID), x => target.SetTextureScale(propertyID, x), endValue, duration);
            t.SetTarget(target);
            return t;
        }

        #endregion

        #endregion
#endif
    }

    // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
    // ███ CLASSES █████████████████████████████████████████████████████████████████████████████████████████████████████████
    // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████

#if UNITY_5_3_OR_NEWER || UNITY_2017_1_OR_NEWER
    public static class DOTweenCYInstruction
    {
        public class WaitForCompletion : CustomYieldInstruction
        {
            public override bool keepWaiting { get {
                return t.active && !t.IsComplete();
            }}
            readonly Tween t;
            public WaitForCompletion(Tween tween)
            {
                t = tween;
            }
        }

        public class WaitForRewind : CustomYieldInstruction
        {
            public override bool keepWaiting { get {
                return t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0);
            }}
            readonly Tween t;
            public WaitForRewind(Tween tween)
            {
                t = tween;
            }
        }

        public class WaitForKill : CustomYieldInstruction
        {
            public override bool keepWaiting { get {
                return t.active;
            }}
            readonly Tween t;
            public WaitForKill(Tween tween)
            {
                t = tween;
            }
        }

        public class WaitForElapsedLoops : CustomYieldInstruction
        {
            public override bool keepWaiting { get {
                return t.active && t.CompletedLoops() < elapsedLoops;
            }}
            readonly Tween t;
            readonly int elapsedLoops;
            public WaitForElapsedLoops(Tween tween, int elapsedLoops)
            {
                t = tween;
                this.elapsedLoops = elapsedLoops;
            }
        }

        public class WaitForPosition : CustomYieldInstruction
        {
            public override bool keepWaiting { get {
                return t.active && t.position * (t.CompletedLoops() + 1) < position;
            }}
            readonly Tween t;
            readonly float position;
            public WaitForPosition(Tween tween, float position)
            {
                t = tween;
                this.position = position;
            }
        }

        public class WaitForStart : CustomYieldInstruction
        {
            public override bool keepWaiting { get {
                return t.active && !t.playedOnce;
            }}
            readonly Tween t;
            public WaitForStart(Tween tween)
            {
                t = tween;
            }
        }
    }
#endif
}


text:
fileFormatVersion: 2
guid: 188918ab119d93148aa0de59ccf5286b
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:

mime_type: text/plain


text:
fileFormatVersion: 2
guid: a060394c03331a64392db53a10e7f2d1
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 3b0c992d698c42a09600a72788570aab
timeCreated: 1563594820


text:
fileFormatVersion: 2
guid: 8ec6bccd24cdc6c4f977504daf1246ec
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 7c678c8a6cc79b243ad80182641b4f4c
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 8fbfd905e08010349b9af270b0b4c98d
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 2e2b0737972626c4591396e351c5175b
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: e1479e0d743b80f4fabce9b55ac5790d
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 8e47ff5e1039cad4dad518dfefb953fb
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 1f9e23d5cfc0a384b850e2529286fff5
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: b0c94ceb3d6b463f82efd0f843a3d79b
timeCreated: 1588131429


text:
fileFormatVersion: 2
guid: a34e53025789a9b4a961a502476d547a
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: ab8800a42e8a5b648a3c938c26b43984
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: d48d4564c04bb85429b5e0b4fdb4c4d6
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 237d023c6581e584fbf637d71b6b7b12
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: adbe55ff618f3594892776ba7a8db135
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: a8d9d34a14e2b3644ad9069de4908046
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: ba23f684065335c4497450f643ef45bf
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 29bd59861898bcf4ba7ac2e7305206ef
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using System.Collections.Generic;
using ReadyGamerOne.Utility;
using UnityEngine;

namespace ReadyGamerOne.Script
{
    public class TriggerContainer3D:MonoBehaviour
    {
        private LayerMask targetLayer=0;
        private List<Collider> contains = new List<Collider>();
        private Func<Collider, bool> IsOk;

        public void Init(LayerMask targetLayerMask, Func<Collider, bool> condition)
        {
            this.targetLayer = targetLayerMask;
            this.IsOk = condition;
        }

        /// <summary>
        /// 外部回去触发器内部东西
        /// </summary>
        public List<Collider> Content => contains;

        private void OnTriggerEnter(Collider other)
        {
            //判断层级
            if (1 == targetLayer.value.GetNumAtBinary(other.gameObject.layer))
            {
                if (!contains.Contains(other))
                {
                    if (IsOk(other))
                    {
                        Debug.Log("进入：" + other.name+other.GetInstanceID());
                        contains.Add(other);
                    }
                }
            }
        }

        private void OnTriggerExit(Collider other)
        {
            if (contains.Contains(other))
            {
                Debug.Log("移除："+other.name);
                contains.Remove(other);
            }
        }
    }
}


text:
using System;
using ReadyGamerOne.Common;
using ReadyGamerOne.EditorExtension;
using ReadyGamerOne.MemorySystem;
using UnityEngine.SceneManagement;

namespace ReadyGamerOne.Script
{
    /// <summary>
    /// 使用SceneMgr推荐用脚本继承这个类
    /// </summary>
    public abstract class AbstractGameMgr<T>:GlobalMonoSingleton<T>
        where T:AbstractGameMgr<T>
    {
        public static event Action onDrawGizomos;

        protected override void OnStateIsNull()
        {
            base.OnStateIsNull();
            print("AbstractGameMgr_Awake——这句话应该只显示一次");
            ResourceMgr.Init(ResourceLoader,PathData,OriginBundleData,AssetConstUtil);
            RegisterSceneEvent();
            QuickStartTool.RegisterUi(GetType());
        }

        protected abstract IResourceLoader ResourceLoader { get; }
        protected virtual IAssetConstUtil AssetConstUtil => null;
        protected virtual IHotUpdatePath PathData => null;
        protected virtual IOriginAssetBundleUtil OriginBundleData => null;

        protected virtual void RegisterSceneEvent()
        {
            SceneManager.sceneLoaded +=(scene,mode)=> this.OnAnySceneLoad();
            SceneManager.sceneUnloaded +=(scene)=> this.OnAnySceneUnload();
        }

        protected virtual void OnAnySceneLoad()
        {

        }

        protected virtual void OnAnySceneUnload()
        {
            MainLoop.Instance.Clear();
        }

        private void OnDrawGizmos()
        {
            onDrawGizomos?.Invoke();
        }

        protected override void OnDestroy()
        {
            base.OnDestroy();
            onDrawGizomos = null;
        }
    }
}


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.Script
{
    public class TriggerInputer : MonoBehaviour
    {
        public event Action<Collider> onTriggerEnterEvent;
        public event Action<Collider> onTriggerStayEvent;
        public event Action<Collider> onTriggerExitEvent;

        public event Action<Collider2D> onTriggerEnterEvent2D; //如果TriggerEnter会调用这个event
        public event Action<Collider2D> onTriggerStayEvent2D; //如果TriggerStay会调用这个event
        public event Action<Collider2D> onTriggerExitEvent2D; //同理

        public event Action<Collision2D> onCollisionEnterEvent2D; //如果TriggerEnter会调用这个event
        public event Action<Collision2D> onCollisionStayEvent2D; //如果TriggerStay会调用这个event
        public event Action<Collision2D> onCollisionExitEvent2D; //同理

        private void OnCollisionEnter2D(Collision2D other)
        {
            onCollisionEnterEvent2D?.Invoke(other);
        }

        private void OnCollisionExit2D(Collision2D other)
        {
            onCollisionExitEvent2D?.Invoke(other);
        }

        private void OnCollisionStay2D(Collision2D other)
        {
            onCollisionStayEvent2D?.Invoke(other);
        }

        private void OnTriggerEnter(Collider other)
        {
            onTriggerEnterEvent?.Invoke(other);
        }

        private void OnTriggerStay(Collider other)
        {
            onTriggerStayEvent?.Invoke(other);
        }

        private void OnTriggerExit(Collider other)
        {
            onTriggerExitEvent?.Invoke(other);
        }

        private void OnTriggerEnter2D(Collider2D col)
        {
            onTriggerEnterEvent2D?.Invoke(col);
        }

        private void OnTriggerStay2D(Collider2D col)
        {
            onTriggerStayEvent2D?.Invoke(col);
        }

        private void OnTriggerExit2D(Collider2D col)
        {
            onTriggerExitEvent2D?.Invoke(col);
        }

        public void Clear()
        {
            onTriggerEnterEvent = null;
            onTriggerStayEvent= null;
            onTriggerExitEvent= null;
            onTriggerEnterEvent2D= null;
            onTriggerStayEvent2D= null;
            onTriggerExitEvent2D= null;

        }
    }
}


text:
fileFormatVersion: 2
guid: 40e00c3e8dccf784c9f5a3afb8e6957b
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 200
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using ReadyGamerOne.Utility;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using GlobalVar = ReadyGamerOne.Global.GlobalVar;

namespace ReadyGamerOne.Script
{
    public class Joystick : MonoBehaviour,IDragHandler,IEndDragHandler
    {
        public Transform EnableRect;
        public Transform stick;
        public float maxR;
        public bool showGizmosR = false;
        private bool dragging = false;
        private Vector3 initPosition;

        private PointerEventData _currentPointerData;

        /// <summary>
        /// 触摸方向
        /// </summary>
        private Vector2 touchDir;
        public Vector2 TouchDir => touchDir;

        private void LogicUpdate()
        {
            if (this == null || this.gameObject == null)
                MainLoop.Instance.RemoveFixedUpdateFunc(LogicUpdate);

            if (!dragging)
            {
                if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.W) ||
                    Input.GetKeyDown(KeyCode.S))
                {
                    if(EnableRect)
                        this.gameObject.SetActive(true);
                }
                if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.W) ||
                    Input.GetKey(KeyCode.S))
                {
                    if(!this.gameObject.activeSelf && EnableRect)
                        this.gameObject.SetActive(true);

                    var simulatorInput=new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
                    Simulator(simulatorInput*maxR);
                }
                else
                {
                    if(EnableRect)
                        this.gameObject.SetActive(false);
                    Simulator(Vector2.zero);
                }
            }
        }

        private void Start()
        {
            this.initPosition = transform.position;
            this.stick.localPosition=Vector3.zero;

            MainLoop.Instance.AddFixedUpdateFunc(LogicUpdate);

            if (EnableRect)
            {
                stick.GetComponent<Image>().raycastTarget = false;
                var uiinputer = EnableRect.GetOrAddComponent<UIInputer>();
                uiinputer.eventOnBeginDrag+=evt=>SetJoyStickState(true, evt);
                uiinputer.eventOnDrag += evt => _currentPointerData = evt;
                uiinputer.eventOnEndDrag += evt => SetJoyStickState(false, evt);
                this.gameObject.SetActive(false);
            }
        }

        private void SetJoyStickState(bool enable,PointerEventData data)
        {
            _currentPointerData = data;
            if (enable)
            {
                dragging = true;
                transform.position = data.position;
                if(EnableRect)
                    this.gameObject.SetActive(true);
                MainLoop.Instance.AddFixedUpdateFunc(InternalDrag);
            }
            else
            {
                dragging = false;
                if(EnableRect)
                    this.gameObject.SetActive(false);
                transform.position = initPosition;
                MainLoop.Instance.RemoveFixedUpdateFunc(InternalDrag);
                OnEndDrag(data);
            }
        }

        private void InternalDrag()
        {
            OnDrag(_currentPointerData);
        }

        private void Simulator(Vector2 input)
        {
            var len = input.magnitude;

            if (len > maxR)
            {
                input = input.normalized * maxR;
            }

            this.touchDir = new Vector2(input.x / maxR, input.y / maxR);

            this.stick.localPosition = input;
        }

        public void OnDrag(PointerEventData eventData)
        {
            Assert.IsNotNull(GlobalVar.CanvasComponent);
            dragging = true;
            Vector2 pos=Vector2.zero;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                this.transform as RectTransform,
                eventData.position,
                GlobalVar.CanvasComponent.worldCamera, out pos);

            Simulator(pos);
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            dragging = false;
            Simulator(Vector2.zero);
        }

        private void OnDrawGizmos()
        {
            if(showGizmosR)
                Gizmos.DrawWireSphere(transform.position,maxR);
        }
    }
}


text:
fileFormatVersion: 2
guid: 7a5cf71bfa46c1547bee510dbcc06252
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using System.Collections.Generic;
using ReadyGamerOne.Common;
using ReadyGamerOne.MemorySystem;
using UnityEngine;
#if UNITY_EDITOR

#endif
namespace ReadyGamerOne.Script
{
    public class AudioMgr : GlobalMonoSingleton<AudioMgr>
    {
        #region Private

        private float effectVolume = 1;
        private List<AudioSource> effectSources = new List<AudioSource>();
        private AudioSource bgmAudioSource;

        /// <summary>
        /// 获取一个闲置的AudioEffect
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private AudioSource GetAudioSource()
        {
            foreach (var source in effectSources)
            {
                if (!source.isPlaying)
                    return source;
            }

            var newSource = gameObject.AddComponent<AudioSource>();
            newSource.volume = effectVolume;
            newSource.loop = false;

            effectSources.Add(newSource);

            return newSource;
        }

        #endregion

        /// <summary>
        /// 背景音乐AudioSource组件
        /// </summary>
        public AudioSource BgmAudioSource
        {
            get
            {
                if (bgmAudioSource == null)
                {
                    bgmAudioSource = GetComponent<AudioSource>();
                    if (!bgmAudioSource)
                        bgmAudioSource = gameObject.AddComponent<AudioSource>();
                }

                return bgmAudioSource;
            }
        }

        /// <summary>
        /// 音乐、音效播放开关
        /// </summary>
        public bool enableBgmAudio = true;

        public bool enableEffectAudio = true;

        /// <summary>
        /// 背景音乐音量
        /// </summary>
        public float BgmVolume
        {
            set => BgmAudioSource.volume = value;
            get => BgmAudioSource.volume;
        }

        /// <summary>
        /// 设置音效的音量
        /// </summary>
        public float EffectVolume
        {
            get => effectVolume;
            set
            {
                effectVolume = value;
                foreach (var audioSource in effectSources)
                {
                    audioSource.volume = value;
                }
            }
        }

        /// <summary>
        /// 播放指定名字的背景音乐
        /// </summary>
        /// <param CharacterName="name"></param>
        public void PlayBgm(string audioName,string bundleKey=null)
        {
            if (!enableBgmAudio)
                return;

            var clip = ResourceMgr.GetAsset<AudioClip>(audioName,bundleKey ?? OriginBundleKey.Audio);
            if (clip == null)
            {
                Debug.Log("音效获取失败：" + name);
                return;
            }

            BgmAudioSource.clip = clip;
            BgmAudioSource.loop = true;
            BgmAudioSource.volume = 1;
            BgmAudioSource.Play();
        }

        /// <summary>
        /// 播放指定名字音效
        /// </summary>
        /// <param CharacterName="name"></param>
        public void PlayEffect(string audioName,string bundleKey=null)
        {
            if (!enableEffectAudio)
                return;

            var clip = ResourceMgr.GetAsset<AudioClip>(audioName,bundleKey ?? OriginBundleKey.Audio );

            if (clip == null)
            {
                Debug.Log("音效获取失败：" + name);
                return;
            }

            var audioSource = GetAudioSource();
            audioSource.clip = clip;
            audioSource.loop = false;
            audioSource.Play();
        }

        /// <summary>
        /// 关闭指定名字音效
        /// </summary>
        /// <param CharacterName="name"></param>
        public void CloseEffect(string name)
        {
            foreach (var VARIABLE in effectSources)
            {
                if (VARIABLE.clip.name == name)
                    VARIABLE.Stop();
            }
        }

        /// <summary>
        /// 在指定位置播放音效
        /// </summary>
        /// <param CharacterName="audioName"></param>
        /// <param CharacterName="position"></param>
        public void PlayEffect(string audioName, Vector3 position,string bundleKey=null)
        {
            AudioSource.PlayClipAtPoint(ResourceMgr.GetAsset<AudioClip>(audioName,
                bundleKey ?? OriginBundleKey.Audio), position);
        }
    }
}


text:
fileFormatVersion: 2
guid: a93fc67e5b0c9d04082ad84b82f1a460
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: cceee204abd7491479ec62be5c30222b
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 190e41bdb6214db5933161efafc3b27e
timeCreated: 1563804072


text:
fileFormatVersion: 2
guid: 9198b355cd518a04da47aebf6c770d1d
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using System.Collections;
using System.Collections.Generic;
using ReadyGamerOne.Common;
using UnityEngine;

namespace ReadyGamerOne.Script
{
    /// <summary>
    /// 主循环basi
    /// 在外部调用，实现脱离MonoBehavior进行更新
    /// 封装多种协程便于调用
    /// </summary>
    public sealed class MainLoop : GlobalMonoSingleton<MainLoop>
    {
        #region Static

        #region PrivateFields

        private static event Action updateEvent;
        private static event Action fixedUpdateEvent;
        private static event Action guiEvent;
        private static event Action startEvent;

        private static List<UpdateTestPair> callBackPairs = new List<UpdateTestPair>();

        #endregion

        #region Method

        #region StartHelper

        public void AddStartFunc(Action func)
        {
            startEvent += func;
        }

        public void RemoveStartFunc(Action func)
        {
            startEvent -= func;
        }

        #endregion

        #region UpdateHelper

        public void AddUpdateTest(UpdateTestPair pair)
        {
            if (callBackPairs.Contains(pair))
                Debug.Log("注意！已经包含这个UpdateTestPair！");
            callBackPairs.Add(pair);
        }

        public void RemoveUpdateTest(UpdateTestPair pair)
        {
            callBackPairs.Remove(pair);
        }

        public  void AddUpdateFunc(Action func)
        {
            updateEvent += func;
        }

        public void RemoveUpdateFunc(Action func)
        {
            updateEvent -= func;
        }

        #endregion

        #region FixedUpdateHelper

        public void AddFixedUpdateFunc(Action func)
        {
            fixedUpdateEvent += func;
        }

        public void RemoveFixedUpdateFunc(Action func)
        {
            fixedUpdateEvent -= func;
        }

        #endregion

        #region GUIHelper

        public void AddGUIFunc(Action func)
        {
            guiEvent += func;
        }

        public void RemoveGUIFunc(Action func)
        {
            guiEvent -= func;
        }

        #endregion

        /// <summary>
        /// 清空所有辅助调用的事件
        /// </summary>
        public void Clear()
        {
            updateEvent = null;
            startEvent = null;
            fixedUpdateEvent = null;
            guiEvent = null;
        }

        #endregion

        #endregion

        public class UpdateTestPair
        {
            public Func<bool> IsOk;
            public Action func;

            public UpdateTestPair(Func<bool> isok, Action func)
            {
                this.IsOk = isok;
                this.func = func;
            }
        }

        #region 协程（延时调用，间隔调用，一段时间内每帧调用）

        #region 开始关闭协程

        /// <summary>
        /// 开始关闭协程
        /// </summary>
        /// <param CharacterName="Coroutine"></param>
        /// <returns></returns>
        public Coroutine StartCoroutines(IEnumerator Coroutine)
        {
            return StartCoroutine(Coroutine);
        }

        public void StopCoroutines(Coroutine Coroutine)
        {
            StopCoroutine(Coroutine);
        }

        #endregion

        #region 运行直到为真

        /// <summary>
        /// 运行直到为真
        /// </summary>
        /// <param CharacterName="method"></param>
        /// <param CharacterName="endCall"></param>
        /// <returns></returns>
        public Coroutine ExecuteUntilTrue(Func<bool> method, Action endCall = null)
        {
            return StartCoroutine(_ExecuteUntilTrue(method, endCall));
        }

        #endregion

        #region 延时调用

        /// <summary>
        /// 延时调用
        /// </summary>
        /// <param CharacterName="method"></param>          c
        /// <param CharacterName="seconds"></param>
        public Coroutine ExecuteLater(Action method, float seconds)
        {
            return StartCoroutine(_ExecuteLater(method, seconds));
        }

        public Coroutine ExecuteLater<T>(Action<T> method, float seconds, T args)
        {
            return StartCoroutine(_ExecuteLater_T<T>(method, seconds, args));
        }

        #endregion

        #region 间隔调用

        /// <summary>
        /// 间隔调用
        /// </summary>
        /// <param CharacterName="method"></param>
        /// <param CharacterName="times"></param>
        /// <param CharacterName="duringTime"></param>
        public Coroutine ExecuteEverySeconds(Action method, int times, float duringTime)
        {
            return StartCoroutine(_ExecuteSeconds(method, times, duringTime));
        }

        public Coroutine ExecuteEverySeconds<T>(Action<T> method, float times, float duringTime, T args)
        {
            return StartCoroutine(_ExecuteSeconds_T(method, times, duringTime, args));
        }

        public Coroutine ExecuteEverySeconds(Action method, float times, float duringTime, Action endCall)
        {
            return StartCoroutine(_ExecuteSeconds_Action(method, times, duringTime, endCall));
        }

        public Coroutine ExecuteEverySeconds<T>(Action<T> method, float times, float duringTime, T args,
            Action<T> endCall)
        {
            return StartCoroutine(_ExecuteSeconds_Action_T(method, times, duringTime, args, endCall));
        }

        #endregion

        #region 一段时间内每帧调用

        /// <summary>
        /// 一段时间内每帧调用
        /// </summary>
        /// <param CharacterName="method"></param>
        /// <param CharacterName="seconds"></param>
        public Coroutine UpdateForSeconds(Action method, float seconds, Action endCall)
        {
            return StartCoroutine(_UpdateForSeconds_Action(method, seconds, endCall));
        }

        public Coroutine UpdateForSeconds<T>(Action<T> method, float seconds, T arg, Action<T> endCall)
        {
            return StartCoroutine(_UpdateForSeconds_Action_T(method, seconds, arg, endCall));
        }

        public Coroutine UpdateForSeconds(Action method, float seconds, float delay = 0f)
        {
            return StartCoroutine(_UpdateForSeconds(method, seconds, delay));
        }

        public Coroutine UpdateForSeconds<T>(Action<T> method, float seconds, T args, float delay = 0f)
        {
            return StartCoroutine(_UpdateForSeconds_T(method, seconds, args, delay));
        }

        #endregion

        #region 内部调用

        private IEnumerator _ExecuteLater(Action mathdem, float time)
        {
            yield return new WaitForSeconds(time);
            mathdem();
        }

        private IEnumerator _ExecuteLater_T<T>(Action<T> mathdom, float time, T args)
        {
            yield return new WaitForSeconds(time);
            mathdom(args);
        }

        private IEnumerator _ExecuteSeconds(Action mathdom, int times, float duringTime)
        {
            if (times <= 0)
            {
                while (true)
                {
                    yield return new WaitForSeconds(duringTime);
                    mathdom?.Invoke();
                }
            }
            else
            {
                for (int i = 0; i < times; i++)
                {
                    for (var timer = 0f; timer < duringTime; timer += Time.deltaTime)
                        yield return 0;
                    mathdom();
                }
            }

        }

        private IEnumerator _ExecuteSeconds_T<T>(Action<T> mathdom, float times, float duringTime, T args)
        {
            for (int i = 0; i < times; i++)
            {
                for (var timer = 0f; timer < duringTime; timer += Time.deltaTime)
                    yield return 0;
                mathdom(args);
            }
        }

        private IEnumerator _ExecuteSeconds_Action(Action method, float times, float dur, Action endCall)
        {
            for (int i = 0; i < times; i++)
            {
                for (var timer = 0f; timer < dur; timer += Time.deltaTime)
                    yield return 0;
                method();
            }

            endCall();
        }

        private IEnumerator _ExecuteSeconds_Action_T<T>(Action<T> method, float times, float dur, T args,
            Action<T> endCall)
        {
            for (int i = 0; i < times; i++)
            {
                for (var timer = 0f; timer < dur; timer += Time.deltaTime)
                    yield return 0;
                method(args);
            }

            endCall(args);
        }

        private IEnumerator _UpdateForSeconds(Action mathdom, float seconds, float start)
        {
            for (var d = 0f; d < start; d += Time.deltaTime)
                yield return 0;
            for (var timer = 0f; timer < seconds; timer += Time.deltaTime)
            {
                yield return 0;
                mathdom();
            }
        }

        private IEnumerator _UpdateForSeconds_T<T>(Action<T> mathdom, float seconds, T args, float start)
        {
            for (var d = 0f; d < start; d += Time.deltaTime)
                yield return 0;
            for (var timer = 0f; timer < seconds; timer += Time.deltaTime)
            {
                yield return 0;
                mathdom(args);
            }
        }

        private IEnumerator _UpdateForSeconds_Action(Action method, float time, Action endcall)
        {
            for (var timer = 0f; timer < time; timer += Time.deltaTime)
            {
                yield return 0;
                method();
            }

            yield return 0;
            endcall();
        }

        private IEnumerator _UpdateForSeconds_Action_T<T>(Action<T> method, float seconds, T arg, Action<T> endCall)
        {
            for (var timer = 0f; timer < seconds; timer += Time.deltaTime)
            {
                yield return 0;
                method(arg);
            }

            yield return 0;
            endCall(arg);
        }

        private IEnumerator _ExecuteUntilTrue(Func<bool> method, Action endCall)
        {
            while (true)
            {
                if (method())
                {
                    endCall?.Invoke();
                    break;
                }

                yield return 0;
            }
        }

        #endregion

        #endregion

        #region MonoBehavior

        protected override void Start()
        {
            base.Start();
            startEvent?.Invoke();
        }

        protected override void Update()
        {
            base.Update();
            updateEvent?.Invoke();
            foreach (var pair in callBackPairs)
            {
                if (pair.IsOk())
                    pair.func();
            }
        }

        private void FixedUpdate()
        {
            fixedUpdateEvent?.Invoke();
        }

        void OnGUI()
        {
            guiEvent?.Invoke();
        }

        #endregion

        protected override void OnDestroy()
        {
            base.OnDestroy();
            Debug.LogWarning("MainLoop_OnDestory函数被调用！");
        }
    }
}


text:
using UnityEngine;

namespace ReadyGamerOne.Script
{
	[RequireComponent(typeof(CircleCollider2D))]
	public abstract class CloseEnough : MonoBehaviour
	{

		public LayerMask testLayer;
		protected bool isClose { private set; get; }
		protected virtual  void  Start()
		{
			this.isClose = false;
			this.gameObject.layer = LayerMask.NameToLayer("Trigger");
			this.GetComponent<CircleCollider2D>().isTrigger = true;
		}

		protected virtual  void  OnTriggerEnter2D(Collider2D col)
		{
			//Debug.Log("第" + col.gameObject.layer + "位");
			if (((this.testLayer.value>>(col.gameObject.layer))&1)!=0)
			{
				this.isClose = true;
//				Debug.Log("Close");
			}
		}

		protected virtual  void OnTriggerExit2D(Collider2D col)
		{
			//Debug.Log(this.testLayer.value);
			if (((this.testLayer.value >> (col.gameObject.layer)) & 1) != 0)
			{
				this.isClose = false;
//				Debug.Log("far");
			}
		}
	}

}


text:
fileFormatVersion: 2
guid: cd9d634e619f4810831bea9d01956380
timeCreated: 1565618065


text:
fileFormatVersion: 2
guid: a85a00821582eec4fab25b77955e8d3d
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using UnityEngine;
using UnityEngine.Serialization;

namespace ReadyGamerOne.Script
{
    public abstract class AbstractCharacterController : MonoBehaviour
    {
        #region Properties

        #region 环境类型设定

        /// <summary>
        /// 移动原理，运动学还是动力学
        /// </summary>
        public enum MoveType
        {
            Physical,
            Transform
        }

        public MoveType moveType = MoveType.Transform;

        public Space spaceType=Space.World;

        /// <summary>
        /// 2D世界还是 3D世界
        /// </summary>
        public enum WorldType
        {
            _2D,
            _3D
        }

        public WorldType worldType = WorldType._2D;

        /// <summary>
        /// 输入类型
        /// </summary>
        public enum InputType
        {
            Input_GetAxis,
            Input_GetKey
        }

        public InputType inputType = InputType.Input_GetAxis;

        public string horizontalAxis = "Horizontal";
        public string verticalAxis = "Vertical";

        public KeyCode leftKey = KeyCode.A;
        public KeyCode rightKey = KeyCode.D;
        public KeyCode upKey = KeyCode.W;
        public KeyCode downKey = KeyCode.S;

        [HideInInspector] public bool enableSimulator = false;

        /// <summary>
        /// 移动方向
        /// </summary>
        public enum DirType
        {
            X,
            Y,
            X_Y,
            X_Z
        }

        public DirType dirType = DirType.X;

        #endregion

        [FormerlySerializedAs("autoFitAnimation")] public bool FitDirByLocalScale = true;

        #region StateProperties

        #region AiIdle

        public string idleAniName;
        [SerializeField] private int idleAniIndex;

        private Action _onIdle;
        public virtual Action onIdle
        {
            get
            {
                if (_onIdle == null)
                    _onIdle = ToIdle;
                return _onIdle;
            }
            set
            {
                _onIdle = value;
            }
        }

        #endregion

        #region Walk

        public bool enableWalk = true;
        public abstract Func<Vector2, bool> CanWalk { get; }
        private Action<Vector2, Vector2> _onWalk;
        public virtual Action<Vector2,Vector2> onWalk
        {
            get
            {
                if (_onWalk == null)
                    _onWalk = ToWalk;
                return _onWalk;
            }
            set
            {
                _onWalk = value;
            }
        }

        public Vector2 walkScaler;
        public string walkAniName;

        [SerializeField] private int walkAniIndex;

        #endregion

        #region Run

        public bool enableRun = false;
        public virtual Func<Vector2, bool> CanRun => null;

        private Action<Vector2, Vector2> _onRun;
        public virtual Action<Vector2, Vector2> onRun
        {
            get
            {
                if (_onRun == null)
                    _onRun = ToRun;
                return _onRun;
            }
            set
            {
                _onRun = value;
            }
        }
        public Vector2 runScaler;
        public string runAniName;

        [SerializeField] private int runAniIndex;

        #endregion

        #region Dash

        public enum LerpType
        {
            Line,
            Sphere
        }

        public bool enableDash = false;
        public virtual Func<Vector2, bool> CanDash => null;
        public virtual Action<Vector2> onStartDash => ToDash;
        public string dashAniName;

        [SerializeField] private int dashAniIndex;

        public KeyCode dashKey = KeyCode.LeftShift;
        public float dashDistance;
        [FormerlySerializedAs("dashArg")] public float dashTime = 0.3f;
        public LerpType lerpType = LerpType.Sphere;

        #endregion

        #region Squat

        public KeyCode squatKey=KeyCode.LeftControl;
        public bool enableSquat = false;
        public virtual Func<Vector2, bool> CanSquat => null;
        public virtual Action<Vector2> onSquat => ToSquat;
        public string squatAniName;
        [SerializeField] private int squatAniIndex;

        #endregion

        #endregion

        #endregion

        #region Virtual

        #region MonoBehavior

        // Start is called before the first frame update
        protected virtual void Start()
        {
            //如果物理系统驱动，需要初始化刚体组件
            if (moveType == MoveType.Physical)
            {
                switch (worldType)
                {
                    case WorldType._2D:
                        _rigidbody2D = GetComponent<Rigidbody2D>();
                        if (_rigidbody2D == null)
                            throw new Exception("获取Rigidbody2D失败");
                        break;
                    case WorldType._3D:
                        _rigidbody = GetComponent<Rigidbody>();
                        if (_rigidbody == null)
                            throw new Exception("获取RigidBody失败");
                        break;
                }
            }
        }

        // Update is called once per frame
        protected virtual void Update()
        {
            if (enableSimulator)
                return;

            if (moveType == MoveType.Transform)
            {
                var input = GetInput();

                #region Fit_Dir

                if (FitDirByLocalScale)
                {
                    AutoFitDirByLocalScale(input);
                }

                #endregion

                #region Squat

                if (enableSquat && !LockState && CanSquat != null && CanSquat(input))
                {
                    onSquat(input);
                    if (EnableAni)
                        ani.Play(Animator.StringToHash(squatAniName));
                }

                #endregion

                #region Dash

                else if (enableDash && !LockState && CanDash != null && CanDash(input))
                {
                    if (IfCanMove(input))
                    {
                        onStartDash(input);
                    }

                    if(EnableAni)
                        ani.Play(Animator.StringToHash(dashAniName));
                }

                #endregion

                #region Run

                else if (enableRun && !LockState && CanRun != null && CanRun(input))
                {
                    if (IfCanMove(input))
                    {
                        onRun(input,runScaler);
                    }

                    if(EnableAni)
                        ani.Play(Animator.StringToHash(runAniName));
                }

                #endregion

                #region Walk

                else if (enableWalk && !LockState && CanWalk != null && CanWalk(input))
                {
                    if (IfCanMove(input))
                    {
                        onWalk(input,walkScaler);
                    }

                    if (EnableAni)
                        ani.Play(Animator.StringToHash(walkAniName));
                }

                #endregion

                #region AiIdle

                else if (!LockState)
                {
                    onIdle();
                }

                #endregion
            }
        }

        protected virtual void FixedUpdate()
        {
            if (moveType == MoveType.Physical)
            {
                var input = GetInput();
            }
        }

        #endregion

        #region CommonLogic

        /// <summary>
        /// 获取用户输入
        /// </summary>
        /// <returns></returns>
        public virtual Vector2 GetInput()
        {
            Vector2 input = Vector2.zero;
            switch (inputType)
            {
                case InputType.Input_GetAxis:
                    input = new Vector2(Input.GetAxis(horizontalAxis), Input.GetAxis(verticalAxis));
                    break;
                case InputType.Input_GetKey:
                    if (Input.GetKey(leftKey))
                        input.x = -1;
                    else if (Input.GetKey(rightKey))
                        input.x = 1;
                    if (Input.GetKey(upKey))
                        input.y = 1;
                    else if (Input.GetKey(downKey))
                        input.y = -1;
                    break;
            }

            return input;
        }

        /// <summary>
        /// 人物面向的方向
        /// </summary>
        protected virtual int Dir => transform.localScale.x > 0 ? 1 : -1;

        protected virtual Func<Vector2, bool> IfCanMove => (input) => true;

        #endregion

        #endregion

        #region Public

        public enum StateType
        {
            Idle,
            Walk,
            Run,
            Dash
        }

        /// <summary>
        /// 模拟用户输入后的效果
        /// </summary>
        /// <param CharacterName="type"></param>
        /// <param CharacterName="input"></param>
        public void Simulator(StateType type,Vector2 input)
        {
            AutoFitDirByLocalScale(input);
            switch (type)
            {
                case StateType.Idle:
                    ToIdle();
                    break;
                case StateType.Walk:
                    onWalk(input, walkScaler);
                    if (EnableAni)
                        ani.Play(walkAniName);
                    break;
                case StateType.Run:
                    onRun(input, runScaler);
                    if (EnableAni)
                        ani.Play(runAniName);
                    break;
                case StateType.Dash:
                    onStartDash(input);
                    if (EnableAni)
                        ani.Play(dashAniName);
                    break;
            }
        }

        #endregion

        #region Private

        #region Fields

        private Rigidbody _rigidbody;
        private Rigidbody2D _rigidbody2D;
        private Animator ani => GetComponent<Animator>();

        private bool LockState = false;

        #endregion

        #region Methods

        private int dirBefore = 1;

        private void TransformWithScaler(Vector3 input, Vector3 scale)
        {
            transform.Translate(
                Time.deltaTime * new Vector3(input.x * scale.x, input.y*scale.y, input.z * scale.z),
                spaceType);
        }

        #endregion

        #region StatesLogic

        /// <summary>
        /// 开始跑步，持续触发
        /// </summary>
        /// <param CharacterName="input"></param>
        private void ToWalk(Vector2 input,Vector2 walkScaler)
        {
            switch (dirType)
            {
                case DirType.X:
                    TransformWithScaler(new Vector2(input.x, 0), walkScaler);
                    break;
                case DirType.Y:
                    TransformWithScaler(new Vector2(0, input.y), walkScaler);
                    break;
                case DirType.X_Y:
                    TransformWithScaler(input, walkScaler);
                    break;
                case DirType.X_Z:
                    TransformWithScaler(new Vector3(input.x,0,input.y), new Vector3(walkScaler.x,0,walkScaler.y));
                    break;
            }
        }

        /// <summary>
        /// 开始跑步，持续调用
        /// </summary>
        /// <param CharacterName="input"></param>
        private void ToRun(Vector2 input,Vector2 runScaler)
        {
            switch (dirType)
            {
                case DirType.X:
                    TransformWithScaler(new Vector2(input.x, 0), runScaler);
                    break;
                case DirType.Y:
                    TransformWithScaler(new Vector2(0, input.y), runScaler);
                    break;
                case DirType.X_Y:
                    TransformWithScaler(input, runScaler);
                    break;
                case DirType.X_Z:
                    TransformWithScaler(new Vector3(input.x,0,input.y), new Vector3(runScaler.x,0,runScaler.y));
                    break;
            }
        }

        /// <summary>
        /// 开始冲刺，只调用一次！！
        /// </summary>
        /// <param CharacterName="input"></param>
        private void ToDash(Vector2 input)
        {
            LockState = true;

            var targetPos = transform.position + new Vector3(Dir * dashDistance, 0, 0);

            //球形插值
            var a = dashTime;
            var b = dashDistance * 4 / (Mathf.PI * a);
            var timer = 0f;

            //线性插值
            var v = dashDistance * 2 / dashTime;

            MainLoop.Instance.ExecuteUntilTrue(() =>
            {
                if (enableDash)
                {
                    if (IfCanMove(input))
                    {
                        var speed = 0f;
                        switch (lerpType)
                        {
                            case LerpType.Line:
                                speed=(-v/dashTime)*timer + v;
                                break;
                            case LerpType.Sphere:
                                speed=b * Mathf.Sqrt(1 - timer * timer / (a * a));
                                break;
                        }

                        if (float.IsNaN(speed)||speed<=0)
                            return true;

                        transform.Translate(new Vector3(Dir * speed * Time.deltaTime, 0, 0), spaceType);

                        timer += Time.deltaTime;

                        if(EnableAni)
                            ani.Play(Animator.StringToHash(dashAniName));

                    }
                    else
                        return true;

                    return Vector3.Distance(targetPos, transform.position) <= 0.01f;
                }

                return true;
            }, () => LockState = false);
        }

        /// <summary>
        /// 开始下蹲，持续调用
        /// </summary>
        /// <param CharacterName="input"></param>
        private void ToSquat(Vector2 input)
        {

        }

        /// <summary>
        /// Idle状态，持续触发
        /// </summary>
        private void ToIdle()
        {
            //AiIdle
            if (EnableAni)
                ani.Play(Animator.StringToHash(idleAniName));
        }

        private void AutoFitDirByLocalScale(Vector2 input)
        {
            var localScale = this.transform.localScale;
            var dir = 1;
            if (FitDirByLocalScale && Mathf.Abs(input.x) > 0.01f)
            {
                dir = input.x > 0 ? 1 : -1;
            }
            else
            {
                if (dir != dirBefore)
                    dir = dirBefore;
            }

            dirBefore = dir;
            this.transform.localScale = new Vector3(dir * Mathf.Abs(localScale.x), localScale.y, localScale.z);
        }

        #endregion

        #endregion

        public bool EnableAni => ani != null && ani.enabled;
    }
}


text:
using ReadyGamerOne.View;
using UnityEditor;
using UnityEditorInternal;

namespace ReadyGamerOne.Script.Editor
{
    [CustomEditor(typeof(TabBar))]
    public class TabBarEditor:UnityEditor.Editor
    {
        private ReorderableList list;
        private SerializedProperty listProp;
        private TabBar tb;
        private void OnEnable()
        {
            this.tb=target as TabBar;
            listProp = serializedObject.FindProperty("tabPairs");
            list = new ReorderableList(serializedObject, listProp, false, true, true, true);
            list.elementHeight = 3 * EditorGUIUtility.singleLineHeight;
            list.drawElementCallback = (rect, index, isActive, isFocused) =>
            {
                var prop = listProp.GetArrayElementAtIndex(index);
                EditorGUI.PropertyField(rect, prop);
            };
            list.drawHeaderCallback = rect => EditorGUI.LabelField(rect, listProp.displayName);
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            EditorGUI.BeginChangeCheck();

            list.DoLayoutList();

            if (EditorGUI.EndChangeCheck())
            {
                CheckTabs();
            }
            serializedObject.ApplyModifiedProperties();
        }

        private void CheckTabs()
        {
            for (var i = 0; i < listProp.arraySize; i++)
            {
                var prop = listProp.GetArrayElementAtIndex(i);
                if (prop.FindPropertyRelative("tab").objectReferenceValue != null
                    && prop.FindPropertyRelative("page").objectReferenceValue != null)
                {
                    prop.FindPropertyRelative("index").intValue = i;
                }
                else if( i>0 && !CheckTabAtIndex(i-1))
                {
                    listProp.DeleteArrayElementAtIndex(i);
                }
            }
        }

        private bool CheckTabAtIndex(int index)
        {
            var prop = listProp.GetArrayElementAtIndex(index);
            return prop.FindPropertyRelative("tab").objectReferenceValue != null && prop.FindPropertyRelative("page").objectReferenceValue != null;
        }
    }
}


text:
fileFormatVersion: 2
guid: 7ce60eba7ca6421cab556bc6663bce4f
timeCreated: 1582342073


text:
fileFormatVersion: 2
guid: c1689f294dfe478ba5c1d02ac4854698
timeCreated: 1582341440


text:
using ReadyGamerOne.Utility;
using ReadyGamerOne.View;
using UnityEditor;
using UnityEngine;

namespace ReadyGamerOne.Script.Editor
{
    [CustomPropertyDrawer(typeof(TabPair))]
    public class TabPairDrawer:PropertyDrawer
    {
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            return 3 * EditorGUIUtility.singleLineHeight;
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var index = 0;
            var indexProp = property.FindPropertyRelative("index");
            EditorGUI.LabelField(position.GetRectAtIndex(index++), indexProp.displayName, indexProp.intValue.ToString());
            EditorGUI.PropertyField(position.GetRectAtIndex(index++), property.FindPropertyRelative("tab"));
            EditorGUI.PropertyField(position.GetRectAtIndex(index++), property.FindPropertyRelative("page"));
        }
    }
}


text:
using UnityEditor;
using UnityEngine;

namespace ReadyGamerOne.Script.Editor
{
    [CustomEditor(typeof(AbstractCharacterController))]
    public class AbstractCharacterControllerEditor:UnityEditor.Editor
    {
        private SerializedProperty moveTypeProp;
        private SerializedProperty worldTypeProp;
        private SerializedProperty inputTypeProp;
        private SerializedProperty dirTypeProp;
        private SerializedProperty spaceTypeProp;

        private SerializedProperty hAxisProp;
        private SerializedProperty vAxisProp;
        private SerializedProperty lKeyProp;
        private SerializedProperty rKeyProp;
        private SerializedProperty uKeyProp;
        private SerializedProperty dKeyProp;
        private bool foldKeys = false;

        private SerializedProperty autoFitProp;

        private SerializedProperty idleAniNameProp;
        private SerializedProperty idleAniIndexProp;

        private SerializedProperty enableWalkProp;
        private SerializedProperty walkScalerProp;
        private SerializedProperty walkAniNameProp;
        private SerializedProperty walkAniIndexProp;
        private bool foldWalk=false;

        private SerializedProperty enableRunProp;
        private SerializedProperty runScalerProp;
        private SerializedProperty runAniNameProp;
        private SerializedProperty runAniIndexProp;
        private bool foldRun = false;

        private SerializedProperty enableDashProp;
        private SerializedProperty dashAniNameProp;
        private SerializedProperty dashAniIndexProp;
        private bool foldDash = false;
        private SerializedProperty dashKeyProp;
        private SerializedProperty dashDistanceProp;
        private SerializedProperty dashArgProp;
        private SerializedProperty lerpTypeProp;

        private SerializedProperty enableSquatProp;
        private SerializedProperty squatKeyProp;
        private SerializedProperty squatAniNameProp;
        private SerializedProperty squatAniIndexProp;
        private bool foldSquat = false;

        private AbstractCharacterController mb;
        private string[] aniNames;

        private Animator ani;
        private string[] GetAniNames()
        {
            if (aniNames == null)
            {
                var clips = ani.runtimeAnimatorController.animationClips;
                aniNames = new string[clips.Length];
                var index = 0;
                foreach (var clip in clips)
                {
                    aniNames[index++] = clip.name;
                }
            }

            return aniNames;
        }
        private void OnEnable()
        {
            //this.behavior = inTarget as BasicCharacterController;
            mb=target as AbstractCharacterController;

            ani = mb.GetComponent<Animator>();

            this.moveTypeProp = serializedObject.FindProperty("moveType");
            this.worldTypeProp = serializedObject.FindProperty("worldType");
            this.inputTypeProp = serializedObject.FindProperty("inputType");
            this.dirTypeProp = serializedObject.FindProperty("dirType");
            this.spaceTypeProp = serializedObject.FindProperty("spaceType");

            this.hAxisProp = serializedObject.FindProperty("horizontalAxis");
            this.vAxisProp = serializedObject.FindProperty("verticalAxis");
            this.lKeyProp = serializedObject.FindProperty("leftKey");
            this.rKeyProp = serializedObject.FindProperty("rightKey");
            this.uKeyProp = serializedObject.FindProperty("upKey");
            this.dKeyProp = serializedObject.FindProperty("downKey");

            this.autoFitProp = serializedObject.FindProperty("FitDirByLocalScale");

            this.idleAniNameProp = serializedObject.FindProperty("idleAniName");
            this.idleAniIndexProp = serializedObject.FindProperty("idleAniIndex");

            this.enableWalkProp = serializedObject.FindProperty("enableWalk");
            this.walkScalerProp = serializedObject.FindProperty("walkScaler");
            this.walkAniNameProp = serializedObject.FindProperty("walkAniName");
            this.walkAniIndexProp = serializedObject.FindProperty("walkAniIndex");

            this.enableRunProp = serializedObject.FindProperty("enableRun");
            this.runScalerProp = serializedObject.FindProperty("runScaler");
            this.runAniNameProp = serializedObject.FindProperty("runAniName");
            this.runAniIndexProp = serializedObject.FindProperty("runAniIndex");

            this.enableDashProp = serializedObject.FindProperty("enableDash");
            this.dashAniNameProp = serializedObject.FindProperty("dashAniName");
            this.dashAniIndexProp = serializedObject.FindProperty("dashAniIndex");
            this.dashDistanceProp = serializedObject.FindProperty("dashDistance");
            this.dashKeyProp = serializedObject.FindProperty("dashKey");
            this.dashArgProp = serializedObject.FindProperty("dashTime");
            this.lerpTypeProp = serializedObject.FindProperty("lerpType");

            this.enableSquatProp = serializedObject.FindProperty("enableSquat");
            this.squatKeyProp = serializedObject.FindProperty("squatKey");
            this.squatAniNameProp = serializedObject.FindProperty("squatAniName");
            this.squatAniIndexProp = serializedObject.FindProperty("squatAniIndex");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            EditorGUILayout.PropertyField(moveTypeProp);

            if (moveTypeProp.enumValueIndex == 0)//Physical
            {
                EditorGUILayout.PropertyField(worldTypeProp);
            }
            else// Transform
            {
                EditorGUILayout.PropertyField(spaceTypeProp);
            }

            EditorGUILayout.PropertyField(dirTypeProp);

            EditorGUILayout.PropertyField(inputTypeProp);

            if (foldKeys = EditorGUILayout.Foldout(foldKeys, "键位"))
            {
                switch (inputTypeProp.enumValueIndex)
                {
                    case 0://Input_GetAxis
                        switch (dirTypeProp.enumValueIndex)
                        {
                            case 0:// X
                                EditorGUILayout.PropertyField(hAxisProp);
                                break;
                            case 1:// Y
                                EditorGUILayout.PropertyField(vAxisProp);
                                break;
                            case 2:
                            case 3:
                                EditorGUILayout.PropertyField(hAxisProp);
                                EditorGUILayout.PropertyField(vAxisProp);
                                break;
                        }
                        break;
                    case 1://Input_GetKey
                        switch (dirTypeProp.enumValueIndex)
                        {
                            case 0:// X
                                EditorGUILayout.PropertyField(lKeyProp);
                                EditorGUILayout.PropertyField(rKeyProp);
                                break;
                            case 1:// Y
                                EditorGUILayout.PropertyField(uKeyProp);
                                EditorGUILayout.PropertyField(dKeyProp);
                                break;
                            case 2:
                            case 3:
                                EditorGUILayout.PropertyField(lKeyProp);
                                EditorGUILayout.PropertyField(rKeyProp);
                                EditorGUILayout.PropertyField(uKeyProp);
                                EditorGUILayout.PropertyField(dKeyProp);
                                break;
                        }
                        break;
                }
            }

            if (mb.EnableAni)
            {
                EditorGUILayout.PropertyField(autoFitProp);

                idleAniIndexProp.intValue = EditorGUILayout.Popup("Idle动画", idleAniIndexProp.intValue, GetAniNames());
                idleAniNameProp.stringValue = GetAniNames()[idleAniIndexProp.intValue];
            }

            #region Walk

            EditorGUILayout.PropertyField(enableWalkProp);
            if (enableWalkProp.boolValue)
            {
                if (foldWalk = EditorGUILayout.Foldout(foldWalk, "走路状态详情"))
                {
                    switch (moveTypeProp.enumValueIndex)
                    {
                        case 0:
                            break;
                        case 1://Transform
                            EditorGUILayout.PropertyField(walkScalerProp);
                            break;
                    }

                    if (mb.EnableAni)
                    {
                        walkAniIndexProp.intValue= EditorGUILayout.Popup("走路动画", walkAniIndexProp.intValue, GetAniNames());
                        walkAniNameProp.stringValue = GetAniNames()[walkAniIndexProp.intValue];
                    }
                }
            }

            #endregion

            #region Run

            EditorGUILayout.PropertyField(enableRunProp);
            if (enableRunProp.boolValue)
            {
                if (foldRun = EditorGUILayout.Foldout(foldRun, "跑步状态详情"))
                {
                    switch (moveTypeProp.enumValueIndex)
                    {
                        case 0:
                            break;
                        case 1://Transform
                            EditorGUILayout.PropertyField(runScalerProp);
                            break;
                    }

                    if (mb.EnableAni)
                    {
                        runAniIndexProp.intValue= EditorGUILayout.Popup("跑步动画",runAniIndexProp.intValue, GetAniNames());
                        runAniNameProp.stringValue = GetAniNames()[runAniIndexProp.intValue];
                    }
                }

            }

            #endregion

            #region Dash

            EditorGUILayout.PropertyField(enableDashProp);
            if (enableDashProp.boolValue)
            {
                if (foldDash = EditorGUILayout.Foldout(foldDash, "冲刺状态详情"))
                {
                    EditorGUILayout.PropertyField(dashKeyProp);
                    lerpTypeProp.enumValueIndex =
                        EditorGUILayout.Popup("插值类型", lerpTypeProp.enumValueIndex, new[] {"线性插值", "球形插值"});

                    switch (moveTypeProp.enumValueIndex)
                    {
                        case 1://Transform
                            EditorGUILayout.PropertyField(dashDistanceProp);
                            dashArgProp.floatValue = EditorGUILayout.Slider("DashTime", dashArgProp.floatValue, 0, 3f);
                            break;
                    }

                    if (mb.EnableAni)
                    {
                        dashAniIndexProp.intValue= EditorGUILayout.Popup("冲刺动画", dashAniIndexProp.intValue, GetAniNames());
                        dashAniNameProp.stringValue = GetAniNames()[dashAniIndexProp.intValue];
                    }
                }
            }

            #endregion

            #region Squat

            EditorGUILayout.PropertyField(enableSquatProp);
            if (enableSquatProp.boolValue)
            {
                if (foldSquat = EditorGUILayout.Foldout(foldSquat, "下蹲状态详情"))
                {
                    EditorGUILayout.PropertyField(squatKeyProp);
                    if (mb.EnableAni)
                    {
                        squatAniIndexProp.intValue =
                            EditorGUILayout.Popup("下蹲动画", squatAniIndexProp.intValue, GetAniNames());
                        squatAniNameProp.stringValue = GetAniNames()[squatAniIndexProp.intValue];
                    }
                }
            }

            #endregion

            serializedObject.ApplyModifiedProperties();

        }
    }
}


text:
fileFormatVersion: 2
guid: d6de3c6f958e41d8816f8a0c50d6f9b7
timeCreated: 1565618089


text:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace ReadyGamerOne.View
{
    [Serializable]
    public class TabPair
    {
        public bool hasInit = false;
        public int index;
        public Button tab;
        public GameObject page;
    }

    public class TabBar : UnityEngine.MonoBehaviour
    {
        private void OnEnable()
        {
            var temp = new List<TabPair>();
            foreach (var tabPair in tabPairs)
            {
                if (tabPair.page == null || tabPair.tab == null)
                    temp.Add(tabPair);
            }
            foreach (var tabPair in temp)
            {
                Debug.LogWarning("清除无效tabPair");
                tabPairs.Remove(tabPair);
            }
            var index = 0;
            foreach (var tabPair in tabPairs)
            {
                if (tabPair.hasInit)
                    return;
                tabPair.tab.onClick.AddListener(
                    () => OnClickTab(tabPair.index));
                tabPair.hasInit = true;
                SetTabState(index, index == 0);
                index++;
            }
        }

        /// <summary>
        /// 点击tab时触发
        /// <GameObject>点击的物体</GameObject>
        /// <int>点击物体的索引</int>
        /// </summary>
        public event Action<GameObject, int> onSelectChanged;

        /// <summary>
        /// 如何设置某个选项物体的开启与关闭状态，默认使用SetActive
        /// </summary>
        public Action<GameObject, bool> howSetTabState;

        /// <summary>
        /// 当前选择的选项卡索引
        /// </summary>
        public int SelectedIndex => _selectIndex;

        /// <summary>
        /// 当前选择的选项卡物体
        /// </summary>
        public GameObject SelectObj
        {
            get
            {
                if (tabPairs.Count==0)
                    return null;
                return tabPairs[_selectIndex].page;
            }
        }

        [SerializeField]
        private int _selectIndex = -1;

        /// <summary>
        /// 默认采用设置物体Active的方法控制激活与否
        /// </summary>
        /// <param name="page"></param>
        /// <param name="state"></param>
        private Action<int, bool> SetTabState =>
            (index, state) =>
            {
                var func = howSetTabState ?? DefaultSetTabState;
                func.Invoke(tabPairs[index].page, state);
                if (state)
                {
                    _selectIndex = index;
                    onSelectChanged?.Invoke(tabPairs[_selectIndex].page, _selectIndex);
                }
            };

        private void DefaultSetTabState(GameObject page, bool state)
        {
            if (null == page)
            {
                Debug.LogWarning("选项卡物体为空");
                return;
            }
            page.SetActive(state);
        }

        [SerializeField] private List<TabPair> tabPairs = new List<TabPair>();

        /// <summary>
        /// 添加TabPair，第三个参数用于编辑器，代码调用不能填
        /// </summary>
        /// <param name="btn"></param>
        /// <param name="page"></param>
        /// <param name="index"></param>
        public void AddTabPair(Button btn, GameObject page, int index = -1)
        {
            //遍历列表，避免重复
            foreach (var tabPair in tabPairs)
            {
                if (tabPair.tab != btn && tabPair.page != page) continue;
                Debug.LogWarning("重复加入tab或page");
                return;
            }

            var pair = new TabPair
            {
                hasInit = true,
                index = index == -1 ? tabPairs.Count : index,
                tab = btn,
                page = page,
            };

            //按钮添加监听事件
            btn.onClick.AddListener(
                () => OnClickTab(pair.index));
            tabPairs.Add(pair);

            //如果是第一个选项卡，默认选中
            if (pair.index == 0)
            {
                SetTabState(0, true);
            }
            else
            {
                SetTabState(pair.index, false);
            }
        }

        private void OnClickTab(int index)
        {
            if (_selectIndex == index)
                return;

            SetTabState(_selectIndex, false);
            SetTabState(index, true);
        }

    }
}


text:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;

namespace ReadyGamerOne.Script
{
    public class FreeGrid : MonoBehaviour
    {
        [Header("控制四周边距")]
        public RectOffset padding;

        [Header("控制子物体大小")]
        public bool controlChildrenSize;
        public Vector2 childSize = Vector2.one * 100;

        [Header("子物体Rect控制")]
        public Vector2 pivot = new Vector2(0, 1);
        public Vector2 anchorMin=new Vector2(0,1);
        public Vector2 anchorMax=new Vector2(0,1);

        [Header("控制子物体间距")]
        public Vector2 space;

        [Header("控制子物体行数")]
        public int rowCount = 4;

        private RectTransform selfRect;
        protected virtual void Awake()
        {
            selfRect = GetComponent<RectTransform>();
            Assert.IsTrue(selfRect);
        }

        protected virtual void Start()
        {
            ReBuild();
        }

        [ContextMenu("Sort")]
        public void ReBuild()
        {
            var list = new List<RectTransform>();
            for (var i = 0; i < selfRect.childCount; i++)
            {
                list.Add(selfRect.GetChild(i).GetComponent<RectTransform>());
            }

            var index = 0;
            foreach (var childRect in list)
            {
                if (!_CheckIfSort(childRect))
                {
                    SetChildState(childRect, false);
                    continue;
                }

                SetChildState(childRect, true);

                //设置锚点
                childRect.pivot = pivot;
                childRect.anchorMin = anchorMin;
                childRect.anchorMax = anchorMax;

                //设置大小
                if (controlChildrenSize)
                    childRect.sizeDelta = childSize;

                //设置位置
                var row = index % rowCount;
                var col = index / rowCount;

                var childRectSize = childRect.sizeDelta;
                var offset=  new Vector2(
                    padding.left + col*(childRectSize.x+space.x),
                    - (padding.top + row*(childRectSize.y+space.y)));

                SetPosition(childRect, offset);

                index++;
            }
        }

        protected virtual void SetChildState(RectTransform child, bool state)
        {
            child.gameObject.SetActive(state);
        }

        /// <summary>
        /// 外部可以赋值这个委托，进而重写CheckIfSort的操作
        /// </summary>
        public Func<RectTransform, bool> CheckIfSort { set; private get; } = null;

        /// <summary>
        /// 内部使用这个，优先采用CheckIfSort，否则采用默认方法
        /// </summary>
        private Func<RectTransform, bool> _CheckIfSort => CheckIfSort ?? _internal_check_if_sort_;

        private bool _internal_check_if_sort_(RectTransform childRect)
        {
            return childRect.gameObject.activeSelf;
        }

        protected virtual void SetPosition(RectTransform childRect, Vector2 targetAnchoredPosition)
        {
            childRect.anchoredPosition = targetAnchoredPosition;
        }
    }
}


text:
fileFormatVersion: 2
guid: 6191dba7bfcd0de4c9f7000725a46f8c
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using System.Collections.Generic;
using ReadyGamerOne.Global;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace ReadyGamerOne.Script
{
    public class Dragger : MonoBehaviour,IBeginDragHandler,IEndDragHandler,IDragHandler
    {
        public LayerMask testLayer;
        public bool dragOnce = true;

        //设置没有到达目的地会返回初始位置
        public bool backToStart = true;

        private enum DragType
        {
            GameObject,
            Ui
        }

        #region 回调事件
        public Action eventOnDrag;

        public Action eventOnBeginDrag;

        public Action eventOnEndDrag;

        public Action<GameObject> eventOnDrop;

        public Action<GameObject> eventOnEnter;

        public Func<GameObject,bool> IsTarget;

        public Action<GameObject> eventOnGetTarget;

        #endregion

        #region Private

        #region Field

        //判断是否拖拽过
        private bool dragged = false;
        //是否正在拖拽
        private bool draging = false;

        private GameObject lastGameObject_ui;
        private GameObject lastGameObject_obj;

        //保存开始时候的父物体和本地坐标
        private Vector3 beginLocalPosition;
        private Transform beforeParent;

        private DragType _dragType;

        private RectTransform parentRect;
        private RectTransform selfRect;
        private Vector2 offset;

        #endregion

        #region Properties

        //移动的时候把被拖物体设为不接受UI事件，拖拽结束取消设置，这个列表记录了被修改的UI组件
        private List<Graphic> gcs=new List<Graphic>();
        private bool Raycastable
        {
            set
            {
                if (value)
                {
                    //把修改过的值恢复
                    foreach (var gc in gcs)
                        gc.raycastTarget = true;
                    gcs.Clear();
                }
                else
                {
                    //把物体本身及子物体所有接收UI输入的组件都改成不接受
                    var graphics = GetComponents<Graphic>();
                    foreach (var gc in graphics)
                    {
                        if (gc.raycastTarget)
                        {
                            gc.raycastTarget = false;
                            gcs.Add(gc);
                        }
                    }
                    graphics = GetComponentsInChildren<Graphic>();
                    foreach (var gc in graphics)
                    {
                        if (gc.raycastTarget)
                        {
                            gc.raycastTarget = false;
                            gcs.Add(gc);
                        }
                    }
                }

            }
        }

        #endregion

        #region Methods

        private void BackToStart()
        {
            transform.SetParent(beforeParent);
            transform.localPosition = beginLocalPosition;
        }
        #endregion

        #endregion

        #region MonoBehavior

        private void Start()
        {
            if (this.gameObject.layer == LayerMask.NameToLayer("UI"))
            {
                this._dragType = DragType.Ui;
            }
            else
                this._dragType = DragType.GameObject;
        }

        void Update()
        {
            if (!draging)
                return;

            //如果鼠标按下
            if (_dragType==DragType.GameObject && Input.GetMouseButtonDown(0))
            {
                //获取碰撞信息
                var hit = Physics2D.RaycastAll(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero,testLayer);

                //如果点在某个物体上
                if (hit.Length>=1)
                {
                    //如果点击的物体是自己，可以开始拖拽！
                    if(hit[0].transform ==this.transform && !draging)
                        ToStartDrag();
                }
            }

            lastGameObject_obj = GetCurrentTarget();

            if (_dragType==DragType.GameObject && Input.GetMouseButtonUp(0))
            {
                ToEndDrag();

            }
            else
            {
//                print("OnDraging:  " + name);

                #region 判断是否进入某些物体

                 if (lastGameObject_obj)
                     eventOnEnter?.Invoke(lastGameObject_obj);

                #endregion

                switch (_dragType)
                {
                    case DragType.GameObject:
                        var pos = transform.position;
                        var mouseToPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                        this.transform.position = new Vector3(mouseToPoint.x, mouseToPoint.y, pos.z);
                        break;
                    case DragType.Ui:
                        var localPoint = Vector2.zero;
                        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
                            parentRect,
                            Input.mousePosition,
                            GlobalVar.CanvasComponent.worldCamera,
                            out localPoint))
                        {
                            var parentRectSizeDelta = parentRect.sizeDelta;
                            selfRect.anchoredPosition = offset + localPoint+new Vector2(parentRectSizeDelta.x/2,
                                                            -parentRectSizeDelta.y/2);
                        }

                        break;
                }

                eventOnDrag?.Invoke();
            }
        }

        #endregion

        private GameObject GetCurrentTarget()
        {
            var hit = Physics2D.RaycastAll(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero,testLayer);

            if (_dragType == DragType.GameObject && hit.Length>=2)
            {
                return hit[1].transform.gameObject;
            }

            if (_dragType == DragType.Ui && hit.Length >= 1)
            {
                return hit[0].transform.gameObject;
            }

            return null;
        }

        private void ToStartDrag()
        {
//            print("ToStartDrag:  "+transform.name);

            //如果之调用一次，并且调用过了，直接返回
            if (dragOnce && dragged)
                return;

            //记录开始的父物体和位置
            beforeParent = transform.parent;
            beginLocalPosition = transform.localPosition;

            if (_dragType == DragType.Ui)
            {
                //在UI最上层
                transform.SetParent(GlobalVar.GCanvasObj.transform);  ;
                transform.SetAsLastSibling();

                //设置拖拽物体不接受UI事件
                Raycastable = false;

                //记录新父亲和自己的Rect
                selfRect = GetComponent<RectTransform>();
                parentRect = transform.parent.GetComponent<RectTransform>();

                #region 计算offset

                var selfLocalPoint = Vector2.zero;
                var selfScreenPoint = RectTransformUtility.WorldToScreenPoint(
                    GlobalVar.CanvasComponent.worldCamera, transform.position);
                RectTransformUtility.ScreenPointToLocalPointInRectangle(
                    parentRect,
                    selfScreenPoint,
                    GlobalVar.CanvasComponent.worldCamera,
                    out selfLocalPoint);

                var mouseLocalPoint = Vector2.zero;
                RectTransformUtility.ScreenPointToLocalPointInRectangle(
                    parentRect,
                    Input.mousePosition,
                    GlobalVar.CanvasComponent.worldCamera,
                    out mouseLocalPoint);

                offset = selfLocalPoint - mouseLocalPoint;
//                Debug.Log($"inOffset:{inOffset}");

                #endregion

            }

            //修改标记
            draging = true;

            //回调
            eventOnBeginDrag?.Invoke();
        }

        private void ToEndDrag()
        {
//            Debug.Log("ToEndDrag:  "+transform.name);

            //如果只拖拽一次并且已经拖拽过了，就不在执行，直接返回
            if (dragOnce && dragged)
                return;

            //设置标记
            draging = false;

            if (_dragType == DragType.Ui)
            {
                //恢复刚刚做得修改
                Raycastable = true;
            }

            //回调
            eventOnEndDrag?.Invoke();

            //是否到达目的地

            GameObject testTarget;
            if(_dragType==DragType.Ui)
                testTarget =  lastGameObject_ui ? lastGameObject_ui : lastGameObject_obj;
            else
            {
                testTarget = GetCurrentTarget();
            }

            if (IsTarget == null)
            {
                Debug.LogWarning("IsTarget is null ???");
            }

            if (IsTarget !=null && testTarget && IsTarget(testTarget))
            {
                //已经到达，那就设置标记——已经拖拽过了
                dragged = true;
                eventOnGetTarget?.Invoke(testTarget);
            }
            else if(backToStart)
            {
                //没到达目的地并且设置了不到达返回起点，那么调用此函数
                BackToStart();
            }
            else
            {
                //就算没到达目的地，位置上不返回起点，父物体也还是要该回去
                transform.SetParent(beforeParent);
            }
        }

        private void OnEnter(GameObject target)
        {
//            print("Dragging " + name + "时，经过：" + inTarget.name);
            eventOnEnter?.Invoke(target);
        }

        #region drag_Interface

        public virtual void  OnBeginDrag(PointerEventData eventData)
        {
            if (draging)
                return;
            ToStartDrag();
        }
        public virtual void   OnEndDrag(PointerEventData eventData)
        {
            ToEndDrag();
        }
        public void OnDrag(PointerEventData eventData)
        {
            this.lastGameObject_ui = eventData?.pointerEnter;

            if(eventData!=null && eventData.pointerEnter && eventData.pointerEnter!=gameObject)
                OnEnter(eventData.pointerEnter);
        }

        #endregion

    }
}


text:
using System;
using UnityEngine;
using UnityEngine.EventSystems;

namespace ReadyGamerOne.Script
{
    public class UIInputer : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerUpHandler,
        IPointerDownHandler, IPointerClickHandler,IBeginDragHandler,IEndDragHandler,IDragHandler
    {
        public event Action<PointerEventData> eventOnPointerEnter;
        public event Action<PointerEventData> eventOnPointerExit;
        public event Action<PointerEventData> eventOnPointerUp;
        public event Action<PointerEventData> eventOnPointerDown;
        public event Action<PointerEventData> eventOnPointerClick;
        public event Action<PointerEventData> eventOnBeginDrag;
        public event Action<PointerEventData> eventOnEndDrag;
        public event Action<PointerEventData> eventOnDrag;

        public event Action<GameObject> eventOnClickObj;

        private void Update()
        {
            if (eventOnClickObj == null)
                return;
            //如果鼠标按下
            if (Input. GetMouseButtonDown(0))
            {
                //获取碰撞信息
                var hit = Physics2D.RaycastAll(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);

                //如果点在某个物体上
                if (hit.Length>=1)
                {
                    //如果点击的物体是自己，可以开始拖拽！
                    if (hit[0].transform == this.transform)
                        eventOnClickObj(hit[0].transform.gameObject);
                    else
                    {
                        Debug.Log("点击的是：" + hit[0].transform.name + "，不是" + gameObject.name);
                    }
                }
                else
                {
                    Debug.Log("没有点击物体");
                }
            }
        }

        public void OnPointerEnter(PointerEventData eventData)
        {
            eventOnPointerEnter?.Invoke(eventData);
        }

        public void OnPointerExit(PointerEventData eventData)
        {
            eventOnPointerExit?.Invoke(eventData);
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            eventOnPointerUp?.Invoke(eventData);
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            eventOnPointerDown?.Invoke(eventData);
        }

        public void OnPointerClick(PointerEventData eventData)
        {
            eventOnPointerClick?.Invoke(eventData);
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            eventOnBeginDrag?.Invoke(eventData);
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            eventOnEndDrag?.Invoke(eventData);
        }

        public void OnDrag(PointerEventData eventData)
        {
            eventOnDrag?.Invoke(eventData);
        }
    }
}


text:
fileFormatVersion: 2
guid: 5cd94f67b0585574c99ebbee1aea1d66
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 2e4af3d2c3255704099fb2cf3273d6a3
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 9e7872ba1ce7f5e40aa0c1c53df0a7a0
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 8f9b6fbb0e0177d4187527d6d7864bd1
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 386632bb19ed36f4fb9d204473d5443d
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant: