[Unity tips] Unity explores the use of self-made object pool and official built-in object pool (ObjectPool)

foreword

Object Pool (Object Pool) is a software design pattern for managing and reusing created objects. In object pooling, a set of pre-created objects is maintained in a pool and used and recycled as needed. The role of the object pool is to provide an efficient way to create and destroy objects to reduce system overhead and improve performance.

The person who invented the object pool is definitely a genius. In games, we often encounter scenes where a large number of identical objects are frequently created and destroyed, such as enemy bullets
insert image description here

If we do not do any processing, but simply create and destroy, it may cause memory leaks, performance degradation, and Caton problems

Instantiate(gameobject)

Destroy(gameobject)

The emergence of object pools reduces the cost of frequently creating and destroying objects, and realizes the recycling and reuse of objects

In the object pool design concept, we no longer simply create and destroy. When creating an object, we will store the object in the object pool. When we need to use the object, we get the object from the pool. Store objects in the object pool to realize the recycling of objects and reduce the cost of frequently creating and destroying objects

Fortunately, since 2021年3月the version, unity is officially in my door 置了对象池, and I will use a simple example in the next tutorial to familiarize you with using the official object pool

Does not use object pool

Make a gold coin prefab, mount the rigid body, collision and Coin script
insert image description here
Add an empty object for generating gold coins, mount the CoinPool script
insert image description hereCoin script code, and the gold coin will be destroyed when it touches the ground

private void OnCollisionEnter2D(Collision2D collision) // 碰撞检测
{
    
    
    Debug.Log(collision.gameObject.layer);
    if (collision.gameObject.layer == LayerMask.NameToLayer("Ground"))
    {
    
    
        //销毁
        Destroy(gameObject);
    }
}

CoinPool script code

public GameObject coin; //金币预制体
public float time; //金币生成间隔时间
void Start()
{
    
    
    StartCoroutine(go());
}

IEnumerator go()
{
    
    
    while (true)
    {
    
    
        //协程每time秒执行一次
        CreateCoin();
        yield return new WaitForSeconds(time);
    }
}

//生成金币
private void CreateCoin()
{
    
    
    GameObject gb = Instantiate(coin, transform);//在当前对象处生成一个金币
    gb.transform.position = new Vector3(Random.Range(-80f, -67f), Random.Range(3f, 9f));//随机生成位置
}

Effect, you can see that we are simply creating and destroying gold coins
insert image description here

Use the official built-in object pool

1. Namespace

using UnityEngine.Pool;

2. Construction method

public ObjectPool(
	Func<T> createFunc, 
	Action<T> actionOnGet = null, 
	Action<T> actionOnRelease = null, 
	Action<T> actionOnDestroy = null, 
	bool collectionCheck = true, 
	int defaultCapacity = 10, 
	int maxSize = 10000
);

Parameter List Explanation

The right side of each parameter equal sign represents the default value, that is, the first parameter is required.

1.Func createFunc

    需填入一个带T类型返回值的方法,即自定义新建对象时的操作

2.Action actionOnGet, Action actionOnRelease, Action actionOnDestroy

   分别为出池、进池、销毁的响应事件。填入自定义方法名即可,用于拓展相应操作,比如在actionOnDestroy中通过Destroy()方法将因为池满而不能入池的对象直接删除

3.bool collectionCheck

    是否在进池前检查对象是否已经存在池中

4.int defaultCapacity, int maxSize

    初始容量,最大容量

3. Attribute
1.int CountAll

    所有的对象数,三个属性都为只读初始值为0,经测试,已知每调用一次createFunc委托该值就会+1

2.int CountActive

    被启用的对象数,已知每调用一次Release()方法就会-1,Get()方法+1

3.int CountInactive

    未被启用的对象数,已知每调用一次Release()方法就会+1,Get()方法-1,最大值为池的最大容量

4. Common methods
1.T Get()

    出池,返回一个池中对象。如果池为空,则先调用createFunc,再出池

2.void Relese(T element)

    进池,将对象element加入池。如果池已达到最大容量,则不入池并触发actionOnDestroy事件

3.void Clear()

    清空池

application

Modify the previous example
Coin script to use the official built-in object pool

using UnityEngine;
using UnityEngine.Pool;
public class Coin : MonoBehaviour
{
    
    
    public ObjectPool<GameObject> pool;
    private void OnCollisionEnter2D(Collision2D collision) // 碰撞检测
    {
    
    
        Debug.Log(collision.gameObject.layer);
        if (collision.gameObject.layer == LayerMask.NameToLayer("Ground"))
        {
    
    
            //销毁
            // Destroy(gameObject);
            pool.Release(gameObject);
        }

    }
}

CoinPoolScreenplay

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

public class CoinPool : MonoBehaviour
{
    
    
    public GameObject coin; //金币预制体
    public float time; //金币生成间隔时间
    public ObjectPool<GameObject> pool;
    public int poolMaxSize;//对象池最大容量
    void Start()
    {
    
    
        //是否在进池前检查对象是否已经存在池中,初始容量,最大容量
        pool = new ObjectPool<GameObject>(createFunc, actionOnGet, actionOnRelease, actionOnDestroy, true, 10, poolMaxSize);
        StartCoroutine(go());
    }

    IEnumerator go()
    {
    
    
        while (true)
        {
    
    
            //协程每time秒执行一次
            CreateCoin();
            Debug.Log("总对象数:"+pool.CountAll);
            Debug.Log("启用的对象数:"+pool.CountActive);
            Debug.Log("未启用的对象数:"+pool.CountInactive);
            yield return new WaitForSeconds(time);
        }
    }

    //生成金币
    private void CreateCoin()
    {
    
    
        // GameObject gb = Instantiate(coin, transform);//在当前对象处生成一个金币
        GameObject gb = pool.Get();
        gb.transform.position = new Vector3(Random.Range(-80f, -67f), Random.Range(3f, 9f));//随机生成位置
    }

    
    // 需填入一个带T类型返回值的方法,即自定义新建对象时的操作
    public GameObject createFunc()
    {
    
    
        GameObject obj = Instantiate(coin, transform);
        obj.GetComponent<Coin>().pool = pool;//将pool和Coin的pool赋值为同一个
        return obj;
    }
    void actionOnGet(GameObject gameObject)
    {
    
    
        gameObject.SetActive(true);//显示敌人
        Debug.Log(gameObject.name + "出池");
    }
    void actionOnRelease(GameObject gameObject)
    {
    
    
        gameObject.SetActive(false);//隐藏敌人
        Debug.Log(gameObject.name + "进池");
    }

    void actionOnDestroy(GameObject gameObject)
    {
    
    
        Debug.Log("池已满," + gameObject.name + "被销毁");
        Destroy(gameObject);
    }
}

As a result, we can see that we no longer simply create and destroy gold coins, but turn on and off the reuse of previously generated gold coins
insert image description here

self-made object pool

Add object pool script ObjectPool

using System.Collections.Generic;
using UnityEngine;

public class ObjectPool
{
    
    
    private static ObjectPool instance; // 单例模式
	// /**
    //  * 我们希望不同的物体可以被分开存储,在这种情况下使用字典是最合适的
    //  * 所以声明一个字典objectPool作为对象池主体,以字符串类型的物体的名字作为key
    //  * 使用队列存储物体来作为value,这里使用队列只是因为入队和出队的操作较为方便,也可以换成其他集合方式
    //  * 然后实例化这个字典以备后续使用
    //  * /
    private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>(); // 对象池字典
    private GameObject pool; // 为了不让窗口杂乱,声明一个对象池父物体,作为所有生成物体的父物体
    public static ObjectPool Instance // 单例模式
    {
    
    
        get
        {
    
    
            if (instance == null)
            {
    
    
                instance = new ObjectPool();
            }
            return instance;
        }
    }
    public GameObject GetObject(GameObject prefab) // 从对象池中获取对象
    {
    
    
        GameObject _object;
        if (!objectPool.ContainsKey(prefab.name) || objectPool[prefab.name].Count == 0) // 如果对象池中没有该对象,则实例化一个新的对象
        {
    
    
            _object = GameObject.Instantiate(prefab);
            PushObject(_object); // 将新的对象加入对象池
            if (pool == null)
                pool = new GameObject("ObjectPool"); // 如果对象池父物体不存在,则创建一个新的对象池父物体
            GameObject childPool = GameObject.Find(prefab.name + "Pool"); // 查找该对象的子对象池
            if (!childPool)
            {
    
    
                childPool = new GameObject(prefab.name + "Pool"); // 如果该对象的子对象池不存在,则创建一个新的子对象池
                childPool.transform.SetParent(pool.transform); // 将该子对象池加入对象池父物体中
            }
            _object.transform.SetParent(childPool.transform); // 将新的对象加入该对象的子对象池中
        }
        _object = objectPool[prefab.name].Dequeue(); // 从对象池中取出一个对象
        _object.SetActive(true); // 激活该对象
        return _object; // 返回该对象
    }
    public void PushObject(GameObject prefab) // 将对象加入对象池中
    {
    
    
		//获取对象的名称,因为实例化的物体名都会加上"(Clone)"的后缀,需要先去掉这个后缀才能使用名称查找
        string _name = prefab.name.Replace("(Clone)", string.Empty);
        if (!objectPool.ContainsKey(_name))
            objectPool.Add(_name, new Queue<GameObject>()); // 如果对象池中没有该对象,则创建一个新的对象池
        objectPool[_name].Enqueue(prefab); // 将对象加入对象池中
        prefab.SetActive(false); // 将对象禁用
    }
}

Coin script

using UnityEngine;
using UnityEngine.Pool;
public class Coin : MonoBehaviour
{
    
    
    private void OnCollisionEnter2D(Collision2D collision) // 碰撞检测
    {
    
    
        // Debug.Log(collision.gameObject.layer);
        if (collision.gameObject.layer == LayerMask.NameToLayer("Ground"))
        {
    
    
            //销毁
            // Destroy(gameObject);
            // pool.Release(gameObject);
            ObjectPool.Instance.PushObject(gameObject);
        }

    }
}

CoinPoolScreenplay

using System.Collections;
using UnityEngine;

public class CoinPool : MonoBehaviour
{
    
    
    public GameObject coin; //金币预制体
    public float time; //金币生成间隔时间
    void Start()
    {
    
    
        StartCoroutine(go());
    }

    IEnumerator go()
    {
    
    
        while (true)
        {
    
    
            //协程每time秒执行一次
            CreateCoin();
            yield return new WaitForSeconds(time);
        }
    }

    //生成金币
    private void CreateCoin()
    {
    
    
        // GameObject gb = Instantiate(coin, transform);//在当前对象处生成一个金币
        // GameObject gb = pool.Get();
        GameObject gb = ObjectPool.Instance.GetObject(coin);
        gb.transform.position = new Vector3(Random.Range(-80f, -67f), Random.Range(3f, 9f));//随机生成位置
    }
}

Effect
insert image description here

Summarize

Unity's official built-in object pool and self-written object pool have their own advantages and disadvantages, depending on your needs and the size of the project.

If your game or application is simple and the object pool needs are small, then using Unity's official built-in object pool is a convenient and fast choice. Unity's approach to object pooling is well-optimized and integrates well with the rest of the engine's functionality, and is very simple to use. You can use ObjectPoolclasses directly to create and manage object pools without writing extra code yourself.

However, when your game or application is more complex and requires more advanced object pooling functionality, you may need to write your own object pool. Writing your own object pool can be customized according to the specific needs of the project to meet specific performance requirements. You can implement your own pool management system, caching strategy, and object recycling mechanism, as well as other advanced features such as object prioritization, preloading, etc.

In general, if your project is small and simple, using Unity's official built-in object pool is a convenient choice. If your project is more complex or has specific needs, writing your own object pool may be more suitable. The best choice depends on your project requirements, time and resource constraints, and your specific requirements for object pooling capabilities.

If it were me, I would still choose to write the object pool script by myself, because this can ensure a certain degree of controllability, reusability and scalability.
insert image description here
A lot of money, hurry up and pick it up

source code

https://gitcode.net/unity1/objectpool
insert image description here

reference

【Video】https://www.bilibili.com/video/BV1Su411E7b2

end

Gifts of roses, hand a fragrance! If the content of the article is helpful to you, please don't be stingy with yours 点赞评论和关注, so that I can receive feedback as soon as possible. Every time you write 支持is the biggest motivation for me to continue to create. Of course, if you find something in the article 存在错误or something 更好的解决方法, you are welcome to comment and private message me!

Well, I am 向宇, https://xiangyu.blog.csdn.net

A developer who worked silently in a small company, out of hobbies, recently began to study unity by himself. If you encounter any problems, you are also welcome to comment and private message me. Although I may not necessarily know some problems, I will check the information of all parties and try to give the best suggestions. I hope it can help more people who want to learn programming People, encourage each other~
insert image description here

Guess you like

Origin blog.csdn.net/qq_36303853/article/details/132330320