3.对象池模块

3.对象池模块


3.1 知识点

对象池模块的作用

  • 节约性能,减少 CPU 和内存消耗

对象池示意图

对象池

导入命名空间和引用

引用了必要的命名空间,包括 System.CollectionsSystem.Collections.GenericUnityEngine

定义 BaseGameObjectPool 类

创建名为 BaseGameObjectPool 的 C# 类,用于实现游戏对象池。

类属性和字段

声明了三个类属性:

  • gameObjectPath:存储游戏对象的资源路径。
  • baseGameObjectPoolNode:表示游戏对象池的根节点。
  • baseGameObjectPoolGameObjectList:用于存储游戏对象的列表。

构造函数

定义了一个构造函数,用于初始化游戏对象池。

构造函数接受三个参数:

  • baseGameObjectPoolManagerNode:表示游戏对象池的管理节点。
  • gameObjectPath:游戏对象的资源路径。
  • gameObject:初始的游戏对象。

在构造函数中执行以下步骤:

  • 创建一个名为 ${gameObjectPath} BaseGameObjectPoolNode 的新 GameObject,并将其设为根节点。
  • 将 gameObjectPath 属性设置为传入的资源路径。
  • 将根节点设为传入的管理节点的子节点。
  • 初始化 baseGameObjectPoolGameObjectList,创建一个空的游戏对象列表。
  • 调用 ReleaseGameObject 方法将初始游戏对象添加到游戏对象池中。

ReleaseGameObject 方法

用于将游戏对象释放到对象池中。

接受一个参数:gameObject,表示要释放的游戏对象。

在方法内部执行以下操作:

  • 将游戏对象设置为不活跃状态(禁用)。
  • 将游戏对象添加到游戏对象列表 baseGameObjectPoolGameObjectList 中。
  • 将游戏对象的父节点设置为游戏对象池的根节点,使其成为对象池的一部分。

GetGameObject 方法

用于从对象池中获取游戏对象。

不接受任何参数。

在方法内部执行以下操作:

  • 声明一个名为 gameObject 的局部变量,并初始化为 null。
  • 从游戏对象列表 baseGameObjectPoolGameObjectList 中获取第一个游戏对象。
  • 从游戏对象列表中移除该游戏对象。
  • 将游戏对象设置为活跃状态(激活)。
  • 将游戏对象的父节点设置为 null,使其脱离对象池的控制。
  • 返回获取的游戏对象。

对象池管理器

定义 BaseGameObjectPoolManager 类

创建名为 BaseGameObjectPoolManager 的 C# 类,用于管理多个游戏对象池。

类属性和字段

baseGameObjectPoolDictionary:声明一个私有字段,用于存储游戏对象池的字典。字典的键是游戏对象的资源路径,值是对应的游戏对象池。

baseGameObjectPoolManagerNode:声明一个私有字段,表示游戏对象池管理器的根节点。

GetGameObject 方法

用于从游戏对象池中获取游戏对象。

接受两个参数:

  • gameObjectPath:游戏对象的资源路径。
  • callBack:回调函数,用于在获取游戏对象后执行自定义操作。

在方法内部执行以下操作:

  • 检查游戏对象池字典中是否包含指定资源路径的对象池。
  • 检查对象池中是否有可用的游戏对象(通过检查对象池的游戏对象列表)。
  • 如果有可用的游戏对象,调用回调函数并传递该游戏对象。
  • 如果没有可用的游戏对象,通过资源管理器异步加载游戏对象,加载完成后设置名称为资源路径,然后调用回调函数并传递加载的游戏对象。

ReleaseGameObject 方法

用于释放游戏对象到对象池中。

接受两个参数:

  • gameObjectPath:游戏对象的资源路径。
  • gameObject:要释放的游戏对象。

在方法内部执行以下操作:

  • 检查游戏对象池管理器的根节点是否已创建,如果未创建,则创建一个新的根节点。
  • 检查游戏对象池字典中是否包含指定资源路径的对象池。
  • 如果包含,将游戏对象释放到对应的对象池中。
  • 如果不包含,创建一个新的对象池,并将游戏对象添加到该对象池中,然后将对象池添加到字典中。

Clear 方法

用于清空游戏对象池管理器的状态。

在方法内部执行以下操作:

  • 清空游戏对象池字典,删除所有对象池。
  • 重置对象池管理器的根节点为 null,以便在需要时重新创建。

进行测试

创建延迟释放脚本,创建方块和球体预制体到Resources下并挂载延迟释放

public class TestGameObjectPoolDelayRelease : MonoBehaviour
{
    void OnEnable()
    {
        Invoke("Release", 3);
        this.transform.position = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
        Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.position:{this.transform.position}");
    }

    void Release()
    {
        BaseGameObjectPoolManager.Instance.ReleaseGameObject(this.gameObject.name, this.gameObject);
    }
}

在 Update 方法中,鼠标左右键随机生成方块和球体

if (Input.GetMouseButtonDown(0))
{
    BaseGameObjectPoolManager.Instance.GetGameObject("Test/Cube", (gameObject) =>
    {
        gameObject.transform.eulerAngles = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
        Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.eulerAngles:{this.transform.eulerAngles}");
    });
}

if (Input.GetMouseButtonDown(1))
{
    BaseGameObjectPoolManager.Instance.GetGameObject("Test/Sphere", (gameObject) =>
    {
        gameObject.transform.localScale = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
        Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.localScale:{this.transform.localScale}");
    });
}

点击后可以看到,假如池下有对象会拿池中的对象


3.2 知识点代码

BaseGameObjectPool

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

// 基础游戏对象池类
public class BaseGameObjectPool
{
    // 游戏对象的资源路径
    public string gameObjectPath;

    // 游戏对象池的根节点
    public GameObject baseGameObjectPoolNode;

    // 存储游戏对象的列表
    public List<GameObject> baseGameObjectPoolGameObjectList;

    // 构造函数,用于初始化游戏对象池
    public BaseGameObjectPool(GameObject baseGameObjectPoolManagerNode, string gameObjectPath, GameObject gameObject)
    {
        // 创建游戏对象池的根节点,并命名
        baseGameObjectPoolNode = new GameObject($"{gameObjectPath} BaseGameObjectPoolNode");
        this.gameObjectPath = gameObjectPath;

        // 将游戏对象池的根节点设为传入的管理节点的子节点
        baseGameObjectPoolNode.transform.parent = baseGameObjectPoolManagerNode.transform;

        // 初始化游戏对象列表
        baseGameObjectPoolGameObjectList = new List<GameObject>();

        // 将传入的游戏对象添加到游戏对象池中
        ReleaseGameObject(gameObject);
    }

    // 释放游戏对象到对象池中
    public void ReleaseGameObject(GameObject gameObject)
    {
        // 将游戏对象设置为不活跃状态
        gameObject.SetActive(false);

        // 将游戏对象添加到对象池列表中
        baseGameObjectPoolGameObjectList.Add(gameObject);

        // 将游戏对象的父节点设为对象池的根节点
        gameObject.transform.parent = baseGameObjectPoolNode.transform;
    }

    // 从对象池中获取游戏对象
    public GameObject GetGameObject()
    {
        GameObject gameObject = null;

        // 从对象池列表中取出第一个游戏对象
        gameObject = baseGameObjectPoolGameObjectList[0];

        // 从对象池列表中移除该游戏对象
        baseGameObjectPoolGameObjectList.RemoveAt(0);

        // 将游戏对象设置为活跃状态
        gameObject.SetActive(true);

        // 将游戏对象的父节点设为null,使其脱离对象池的控制
        gameObject.transform.parent = null;

        // 返回获取的游戏对象
        return gameObject;
    }
}

BaseGameObjectPoolManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

// 游戏对象池管理器类,继承自 C# 基础单例类
public class BaseGameObjectPoolManager : BaseSingletonInCSharp<BaseGameObjectPoolManager>
{
    // 存储游戏对象池的字典,键为游戏对象的资源路径,值为游戏对象池
    private Dictionary<string, BaseGameObjectPool> baseGameObjectPoolDictionary = new Dictionary<string, BaseGameObjectPool>();

    // 游戏对象池管理器的根节点
    private GameObject baseGameObjectPoolManagerNode;

    // 从对象池中获取游戏对象的方法,包括资源路径和回调函数
    public void GetGameObject(string gameObjectPath, UnityAction<GameObject> callBack)
    {
        // 检查游戏对象池字典中是否包含指定资源路径的对象池,并且对象池中是否有可用的游戏对象
        if (baseGameObjectPoolDictionary.ContainsKey(gameObjectPath) && baseGameObjectPoolDictionary[gameObjectPath].baseGameObjectPoolGameObjectList.Count > 0)
        {
            // 如果有可用的游戏对象,调用回调函数返回游戏对象
            callBack(baseGameObjectPoolDictionary[gameObjectPath].GetGameObject());
        }
        else
        {
            // 如果没有可用的游戏对象,通过资源管理器异步加载游戏对象
            BaseResourceManager.Instance.LoadAsync<GameObject>(gameObjectPath, (gameObject) =>
            {
                // 设置加载的游戏对象的名称为资源路径
                gameObject.name = gameObjectPath;

                // 调用回调函数返回加载的游戏对象
                callBack(gameObject);
            });
        }
    }

    // 释放游戏对象到对象池的方法,包括资源路径和游戏对象
    public void ReleaseGameObject(string gameObjectPath, GameObject gameObject)
    {
        // 如果游戏对象池管理器的根节点尚未创建,创建一个新的根节点
        if (baseGameObjectPoolManagerNode == null)
        {
            baseGameObjectPoolManagerNode = new GameObject("BaseGameObjectPoolManagerNode");
        }

        // 检查游戏对象池字典中是否包含指定资源路径的对象池
        if (baseGameObjectPoolDictionary.ContainsKey(gameObjectPath))
        {
            // 如果包含,将游戏对象释放到对应的对象池中
            baseGameObjectPoolDictionary[gameObjectPath].ReleaseGameObject(gameObject);
        }
        else
        {
            // 如果不包含,创建一个新的对象池,并添加到对象池字典中
            baseGameObjectPoolDictionary.Add(gameObjectPath, new BaseGameObjectPool(baseGameObjectPoolManagerNode, gameObjectPath, gameObject));
        }
    }

    // 清空游戏对象池管理器的方法
    public void Clear()
    {
        baseGameObjectPoolDictionary.Clear(); // 清空对象池字典
        baseGameObjectPoolManagerNode = null; // 重置对象池管理器的根节点
    }
}

Lesson03_对象池模块

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

public class Lesson03_对象池模块 : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            BaseGameObjectPoolManager.Instance.GetGameObject("Test/Cube", (gameObject) =>
            {
                gameObject.transform.eulerAngles = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
                Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.eulerAngles:{this.transform.eulerAngles}");
            });
        }

        if (Input.GetMouseButtonDown(1))
        {
            BaseGameObjectPoolManager.Instance.GetGameObject("Test/Sphere", (gameObject) =>
            {
                gameObject.transform.localScale = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
                Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.localScale:{this.transform.localScale}");
            });
        }
    }
}

TestGameObjectPoolDelayRelease

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

public class TestGameObjectPoolDelayRelease : MonoBehaviour
{
    void OnEnable()
    {
        Invoke("Release", 3);
        this.transform.position = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
        Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.position:{this.transform.position}");
    }

    void Release()
    {
        BaseGameObjectPoolManager.Instance.ReleaseGameObject(this.gameObject.name, this.gameObject);
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏