组件池(Component Pool)

组件池介绍

组件池是此框架内置的适用于Unity的Component的引用池,当组件Component进入该引用池时,此组件会被隐藏(默认是Component所挂在的GameObject将被SetActive(false)),而当Component从该引用池拿出时,此组件会被显示或者说取消隐藏(默认是Component所挂在的GameObject将被自动SetActive(true))。

内置的组件池策略实现

实现的是 IPoolPolicy,主要是DefaultComponentPoolPolicy,用于传给 DefaultPoolDefaultConcurrentPool作为实例化参数。

https://github.com/VMware233/VMFramework/blob/main/Assets/VMFramework/Main/Core/Collections/Pools/ComponentPool/ComponentPoolPolicy.cs
https://github.com/VMware233/VMFramework/blob/main/Assets/VMFramework/Main/Core/Collections/Pools/ComponentPool/DefaultComponentPoolPolicy.cs
https://github.com/VMware233/VMFramework/blob/main/Assets/VMFramework/Main/Core/Collections/Pools/ComponentPool/CustomComponentPoolPolicy.cs

示例

以下是一个组件池的使用示例,实现一个简单的音效管理器:

https://github.com/VMware233/VMFramework/blob/main/Assets/Examples/Core/Pools/AudioSpawner.cs
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Cysharp.Threading.Tasks;
using Sirenix.OdinInspector;
using UnityEngine;
using VMFramework.Core;
using VMFramework.Core.Pools;

namespace VMFramework.Examples
{
    public class AudioSpawner : UniqueMonoBehaviour<AudioSpawner>
    {
        #region Config

        /// <summary>
        /// The default transform parent for the AudioSource components.
        /// </summary>
        [SerializeField]
        private Transform audioSourceDefaultContainer;

        #endregion

        // The pool dictionary for the AudioSource components.
        [ShowInInspector]
        private static Dictionary<AudioClip, DefaultPool<AudioSource>> audioSourcePoolDictionary = new();

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static DefaultPool<AudioSource> CreatePool(AudioClip audioClip)
        {
            return new(new CustomComponentPoolPolicy<AudioSource>(() =>
            {
                var audioSource = new GameObject(audioClip.name).AddComponent<AudioSource>();
                audioSource.clip = audioClip;
                return audioSource;
            }, returnFunc: audioSource =>
            {
                audioSource.transform.SetParent(instance.audioSourceDefaultContainer);
                audioSource.SetActive(false);
                return true;
            }));
        }

        [Button]
        public static AudioSource Play(AudioClip audioClip, Vector3 position, bool autoCheckStop,
            Transform parent = null)
        {
            if (audioClip == null)
            {
                Debug.LogError("AudioClip is null");
                return null;
            }

            if (audioSourcePoolDictionary.TryGetValue(audioClip, out var audioSourcePool) == false)
            {
                audioSourcePool = CreatePool(audioClip);
                audioSourcePoolDictionary.Add(audioClip, audioSourcePool);
            }

            var audioSource = audioSourcePool.Get(parent);

            audioSource.transform.position = position;
            audioSource.loop = false;

            audioSource.Play();

            if (autoCheckStop)
            {
                _ = CheckStop(audioSource);
            }

            return audioSource;
        }

        [Button]
        public static void Return(AudioSource audioSource)
        {
            audioSource.Stop();

            if (audioSource.gameObject.activeSelf)
            {
                audioSource.transform.SetParent(instance.audioSourceDefaultContainer);

                if (audioSource.clip == null)
                {
                    Debug.LogError("AudioSource.clip is null");
                    return;
                }

                if (audioSourcePoolDictionary.TryGetValue(audioSource.clip, out var audioSourcePool) == false)
                {
                    audioSourcePool = CreatePool(audioSource.clip);
                    audioSourcePoolDictionary.Add(audioSource.clip, audioSourcePool);
                }

                audioSourcePool.Return(audioSource);
            }
        }

        /// <summary>
        /// Check if the audio has ended and return it if it has.
        /// </summary>
        /// <param name="audioSource"></param>
        /// <returns></returns>
        private static async UniTaskVoid CheckStop(AudioSource audioSource)
        {
            await UniTask.WaitUntil(() => audioSource.isPlaying == false);

            Return(audioSource);
        }
    }
}

如果顺利编译,并把此脚本挂到一个GameObject上,则应如下所示:

最后更新于

这有帮助吗?