UGUI Others 3 (fill in the gaps)

        IndexedSet is an internal class of UGUI. It is a table in which the same object does not exist. If necessary, you can copy it directly into the project.

        ​​​​Mainly look at these codes:

        readonly List<T> m_List = new List<T>();
        Dictionary<T, int> m_Dictionary = new Dictionary<T, int>();
 
        public void Add(T item)
        {
            if (m_Dictionary.ContainsKey(item))
                return;
 
            m_List.Add(item);
            m_Dictionary.Add(item, m_List.Count - 1);
        }

        In fact, an additional m_Dictionary is maintained, item is used as the key, and item is used as the subscript of the m_List as the value.
        The Add method is very simple, but the Remove method is a little more troublesome.

        public bool Remove(T item)
        {
            int index = -1;
            if (!m_Dictionary.TryGetValue(item, out index))
                return false;
 
            RemoveAt(index);
            return true;
        }
RemoveAt:
        public void RemoveAt(int index)
        {
            T item = m_List[index];
            m_Dictionary.Remove(item);
            if (index == m_List.Count - 1)
                m_List.RemoveAt(index);
            else
            {
                int replaceItemIndex = m_List.Count - 1;
                T replaceItem = m_List[replaceItemIndex];
                m_List[index] = replaceItem;
                m_Dictionary[replaceItem] = index;
                m_List.RemoveAt(replaceItemIndex);
            }
        }

        If it is not the last one, move the last item to the removed position. It should be noted here that if your IndexedSet is ordered, it may need to be reordered after removing the objects.
Sort:

        //Sorts the internal list, this makes the exposed index accessor sorted as well.
        //But note that any insertion or deletion, can unorder the collection again.
        public void Sort(Comparison<T> sortLayoutFunction)
        {
            //There might be better ways to sort and keep the dictionary index up to date.
            m_List.Sort(sortLayoutFunction);
            //Rebuild the dictionary index.
            for (int i = 0; i < m_List.Count; ++i)
            {
                T item = m_List[i];
                m_Dictionary[item] = i;
            }
        }

        After sorting m_List, the subscripts saved in m_Dictionary will also be modified.


        ​​​​ ObjectPool is an object pool used to recycle released objects to save memory.

        The methods are very simple:

    internal class ObjectPool<T> where T : new()
    {
        private readonly Stack<T> m_Stack = new Stack<T>();
        private readonly UnityAction<T> m_ActionOnGet;
        private readonly UnityAction<T> m_ActionOnRelease;
 
        public int countAll { get; private set; }
        public int countActive { get { return countAll - countInactive; } }
        public int countInactive { get { return m_Stack.Count; } }
 
        public ObjectPool(UnityAction<T> actionOnGet, UnityAction<T> actionOnRelease)
        {
            m_ActionOnGet = actionOnGet;
            m_ActionOnRelease = actionOnRelease;
        }
 
        public T Get()
        {
            T element;
            if (m_Stack.Count == 0)
            {
                element = new T();
                countAll++;
            }
            else
            {
                element = m_Stack.Pop();
            }
            if (m_ActionOnGet != null)
                m_ActionOnGet(element);
            return element;
        }
 
        public void Release(T element)
        {
            if (m_Stack.Count > 0 && ReferenceEquals(m_Stack.Peek(), element))
                Debug.LogError("Internal error. Trying to destroy object that is already released to pool.");
            if (m_ActionOnRelease != null)
                m_ActionOnRelease(element);
            m_Stack.Push(element);
        }
    }

        When getting, if it is not in the stack, it will be created, and if it is, it will be popped out as the return value. When releasing, put the object into the stack.

        ListPool is a special application of ObjectPool, which is often used in UGUI to recycle the released List.

accomplish:

    internal static class ListPool<T>
    {
        // Object pool to avoid allocations.
        private static readonly ObjectPool<List<T>> s_ListPool = new ObjectPool<List<T>>(null, l => l.Clear());
 
        public static List<T> Get()
        {
            return s_ListPool.Get();
        }
 
        public static void Release(List<T> toRelease)
        {
            s_ListPool.Release(toRelease);
        }
    }


        Because it is a static generic class, there is only one s_ListPool for each type.
        s_ListPool is an ObjectPool of type List<T>, and a lamda callback during Release is added, that is, the List is cleared.

        CoroutineTween is a namespace (namespace UnityEngine.UI.CoroutineTween), which includes the ITweenValue interface, the two structures ColorTween and FloatTween inherited from ITweenValue, and the TweenRunner with ITweenValue as a generic type. This class is used in Graphic, respectively. Used to achieve color and transparency gradient effects.

        public void StartTween(T info)
        {
            if (m_CoroutineContainer == null)
            {
                Debug.LogWarning("Coroutine container not configured... did you forget to call Init?");
                return;
            }
 
            if (m_Tween != null)
            {
                m_CoroutineContainer.StopCoroutine(m_Tween);
                m_Tween = null;
            }
 
            if (!m_CoroutineContainer.gameObject.activeInHierarchy)
            {
                info.TweenValue(1.0f);
                return;
            }
 
            m_Tween = Start(info);
            m_CoroutineContainer.StartCoroutine(m_Tween);
        }


使用m_CoroutineContainer(Init时传入的组件)的协程执行Start方法。

        private static IEnumerator Start(T tweenInfo)
        {
            if (!tweenInfo.ValidTarget())
                yield break;
 
            var elapsedTime = 0.0f;
            while (elapsedTime < tweenInfo.duration)
            {
                elapsedTime += tweenInfo.ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime;
                var percentage = Mathf.Clamp01(elapsedTime / tweenInfo.duration);
                tweenInfo.TweenValue(percentage);
                yield return null;
            }
            tweenInfo.TweenValue(1.0f);
        }

        Get the percentage based on the elapsed time (elapsedTime) divided by the duration of tweenInfo (duration), and call the TweenValue method.
        ColorTween’s TweenValue method:

        public void TweenValue(float floatPercentage)
        {
            if (!ValidTarget())
                return;
 
            var newColor = Color.Lerp(m_StartColor, m_TargetColor, floatPercentage);
 
            if (m_TweenMode == ColorTweenMode.Alpha)
            {
                newColor.r = m_StartColor.r;
                newColor.g = m_StartColor.g;
                newColor.b = m_StartColor.b;
            }
            else if (m_TweenMode == ColorTweenMode.RGB)
            {
                newColor.a = m_StartColor.a;
            }
            m_Target.Invoke(newColor);
        }


        Calculate the color value or Alpha based on the input percentage, and send an event to pass the new color value to the listening method.
        FloatTween’s TweenValue method:

        public void TweenValue(float floatPercentage)
        {
            if (!ValidTarget())
                return;
 
            var newValue = Mathf.Lerp(m_StartValue, m_TargetValue, floatPercentage);
            m_Target.Invoke(newValue);
        }

It seems there is no need to say more.
        The above are very simple classes, which may not necessarily be used in actual development (for example, DOTween is a more complete implementation of CoroutineTween), but it is worth learning as a reference. .

Guess you like

Origin blog.csdn.net/ttod/article/details/135016765