IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> [Unity]简单对象池 -> 正文阅读

[游戏开发][Unity]简单对象池

池对象事件

接口名

IPoolObjectEvent

说明

需要接受池对象的事件时,可以实现该接口。

代码

namespace ZeroFramework
{
    /// <summary>
    /// 池对象事件接口
    /// </summary>
    public interface IPoolObjectEvent
    {
        /// <summary>
        /// 创建时
        /// </summary>
        void OnPoolObjectCreate();

        /// <summary>
        /// 请求时
        /// </summary>
        void OnPoolObjectRequest();

        /// <summary>
        /// 返还时
        /// </summary>
        void OnPoolObjectReturn();

        /// <summary>
        /// 销毁时
        /// </summary>
        void OnPoolObjectDestroy();
    }

    public class NullPoolObjectEvent : IPoolObjectEvent
    {
        public void OnPoolObjectCreate()
        {
        }

        public void OnPoolObjectRequest()
        {
        }

        public void OnPoolObjectReturn()
        {
        }

        public void OnPoolObjectDestroy()
        {
        }
    }
}

对象池

类名

UnityObjectPool

说明

对象池,不要调用构造函数创建,用对象池工厂创建。

代码

using System.Collections.Generic;
using UnityEngine;

namespace ZeroFramework
{
    /// <summary>
    /// Unity对象池
    /// </summary>
    /// <typeparam name="T">池对象预设类型</typeparam>
    public class UnityObjectPool<T> where T : Object
    {
        // 全局池: 存放所有生成的对象
        private readonly List<T> _globalPool = new List<T>();

        // 池: 存放当前可用的对象
        private readonly Queue<T> _pool = new Queue<T>();
        private readonly T _prefab;
        private IPoolObjectEvent _objectEvent;
        private Transform _root;


        public UnityObjectPool(T prefab)
        {
            _prefab = prefab;
        }

        /// <summary>
        /// 设置对象的根节点
        /// </summary>
        /// <param name="root"></param>
        public void SetObjectRoot(Transform root)
        {
            _root = root;
        }

        /// <summary>
        /// 生成对象池
        /// </summary>
        /// <param name="capacity"></param>
        public void Generate(int capacity)
        {
            for (int i = 0; i < capacity; i++)
            {
                CreatePoolObject();
            }
        }

        /// <summary>
        /// 创建池对象
        /// </summary>
        private void CreatePoolObject()
        {
            var poolObject = InstantiatePrefab();
            RegisterObjectToGlobalPool(poolObject);
            AddObjectToPool(poolObject);
            GetObjectEvent(poolObject).OnPoolObjectCreate();
        }

        /// <summary>
        /// 实例化预设
        /// </summary>
        /// <returns></returns>
        private T InstantiatePrefab()
        {
            var poolObject = Object.Instantiate(_prefab, _root);
            InactiveObject(poolObject);
            return poolObject;
        }

        /// <summary>
        /// 获取对象事件
        /// </summary>
        /// <returns></returns>
        private IPoolObjectEvent GetObjectEvent(T poolObject)
        {
            return _objectEvent ??= GetObjectComponent<IPoolObjectEvent>(poolObject) ?? new NullPoolObjectEvent();
        }

        /// <summary>
        /// 获取池对象的组件
        /// </summary>
        /// <param name="poolObject"></param>
        /// <typeparam name="TComponent"></typeparam>
        /// <returns></returns>
        /// <exception cref="ZeroFrameworkException"></exception>
        private TComponent GetObjectComponent<TComponent>(T poolObject)
        {
            return poolObject switch
            {
                GameObject gameObject => gameObject.GetComponent<TComponent>(),
                Component component => component.GetComponent<TComponent>(),
                _ => throw new ZeroFrameworkException("预设类型错误")
            };
        }

        /// <summary>
        /// 激活对象
        /// </summary>
        /// <param name="poolObject"></param>
        private void ActiveObject(T poolObject)
        {
            SetObjectActive(poolObject, true);
        }

        /// <summary>
        /// 不激活对象
        /// </summary>
        /// <param name="poolObject"></param>
        private void InactiveObject(T poolObject)
        {
            SetObjectActive(poolObject, false);
        }

        /// <summary>
        /// 设置对象激活
        /// </summary>
        /// <param name="poolObject"></param>
        /// <param name="isActive"></param>
        private void SetObjectActive(T poolObject, bool isActive)
        {
            switch (poolObject)
            {
                case GameObject gameObject:
                    gameObject.SetActive(isActive);
                    break;
                case Component component:
                    component.gameObject.SetActive(isActive);
                    break;
            }
        }

        /// <summary>
        /// 增加对象到池
        /// </summary>
        /// <param name="poolObject"></param>
        private void AddObjectToPool(T poolObject)
        {
            _pool.Enqueue(poolObject);
        }

        /// <summary>
        /// 注册对象到全局池
        /// </summary>
        /// <param name="poolObject"></param>
        private void RegisterObjectToGlobalPool(T poolObject)
        {
            _globalPool.Add(poolObject);
        }

        /// <summary>
        /// 请求对象
        /// </summary>
        /// <returns></returns>
        public T RequestObject()
        {
            if (IsPoolEmpty())
            {
                CreatePoolObject();
            }

            var poolObject = _pool.Dequeue();
            ActiveObject(poolObject);
            GetObjectEvent(poolObject).OnPoolObjectRequest();
            return poolObject;
        }

        /// <summary>
        /// 池是否空了
        /// </summary>
        /// <returns></returns>
        private bool IsPoolEmpty()
        {
            return _pool.Count <= 0;
        }

        /// <summary>
        /// 返还对象
        /// </summary>
        /// <param name="poolObject"></param>
        public void ReturnObject(T poolObject)
        {
            if (InPool(poolObject))
            {
                return;
            }

            InactiveObject(poolObject);
            AddObjectToPool(poolObject);
            GetObjectEvent(poolObject).OnPoolObjectReturn();
        }

        /// <summary>
        /// 返还所有对象
        /// </summary>
        public void ReturnAllObject()
        {
            foreach (var poolObject in _globalPool)
            {
                ReturnObject(poolObject);
            }
        }

        /// <summary>
        /// 对象是否在池中
        /// </summary>
        /// <param name="poolObject"></param>
        /// <returns></returns>
        private bool InPool(T poolObject)
        {
            return _pool.Contains(poolObject);
        }

        /// <summary>
        /// 清除对象池所有对象
        /// </summary>
        public void Clear()
        {
            foreach (var poolObject in _globalPool)
            {
                DestroyObject(poolObject);
                GetObjectEvent(poolObject).OnPoolObjectDestroy();
            }

            _globalPool.Clear();
            _pool.Clear();
        }

        /// <summary>
        /// 销毁对象
        /// </summary>
        /// <param name="poolObject"></param>
        private void DestroyObject(T poolObject)
        {
            switch (poolObject)
            {
                case GameObject gameObject:
                    Object.Destroy(gameObject);
                    break;
                case Component component:
                    Object.Destroy(component.gameObject);
                    break;
            }
        }
    }
}

对象池工厂

类名

UnityObjectPoolFactory

说明

用来创建对象池

代码

using UnityEngine;

namespace ZeroFramework
{
    /// <summary>
    /// Unity对象池工厂
    /// </summary>
    public static class UnityObjectPoolFactory
    {
        public static UnityObjectPool<T> Create<T>(T prefab, int capacity = 16, Transform root = null)
            where T : Object
        {
            var pool = new UnityObjectPool<T>(prefab);
            pool.SetObjectRoot(root);
            pool.Generate(capacity);
            return pool;
        }
    }
}

示例

子弹脚本

类名

Bullet

说明

  • 继承MonoBehaviour可挂载到预设对象上

  • 实现IPoolObjectEvent可监听池对象事件

代码

using UnityEngine;
using ZeroFramework;

public class Bullet : MonoBehaviour, IPoolObjectEvent
{
    private UnityObjectPool<Bullet> _pool;


    public void SetPool(UnityObjectPool<Bullet> pool)
    {
        _pool = pool;
    }

    public void ReturnToPool()
    {
        _pool.ReturnObject(this);
    }


    #region 池对象事件接口

    public void OnPoolObjectCreate()
    {
        Debug.Log(nameof(OnPoolObjectCreate));
    }

    public void OnPoolObjectRequest()
    {
        Debug.Log(nameof(OnPoolObjectRequest));
    }

    public void OnPoolObjectReturn()
    {
        Debug.Log(nameof(OnPoolObjectReturn));
    }

    public void OnPoolObjectDestroy()
    {
        Debug.Log(nameof(OnPoolObjectDestroy));
    }

    #endregion
}

使用子弹对象池脚本

类名

TestButtleObjectPool

说明

使用UnityObjectPoolFactory.Create创建对象池

代码

using UnityEngine;
using ZeroFramework;

public class TestButtleObjectPool : MonoBehaviour
{
    [SerializeField] private Bullet _bullet;
    [SerializeField] private Transform _poolRoot;
    private UnityObjectPool<Bullet> _pool;
    private Bullet _poolObject;


    private void Awake()
    {
        _pool = UnityObjectPoolFactory.Create(_bullet, 5, _poolRoot);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            _poolObject = _pool.RequestObject();
            // 返还方式2必须设置池
            _poolObject.SetPool(_pool);
        }

        if (Input.GetKeyDown(KeyCode.E))
        {
            if (_poolObject)
            {
                // 返还方式1
                // _pool.ReturnObject(_poolObject);

                // 返还方式2(需要先设置池)
                _poolObject.ReturnToPool();

                _poolObject = null;
            }
        }

        if (Input.GetKeyDown(KeyCode.R))
        {
            _pool.ReturnAllObject();
        }

        if (Input.GetKeyDown(KeyCode.T))
        {
            _pool.Clear();
        }
    }
}

仓库(代码会有差异)

https://gitee.com/ZeroRevival/zero-framework.git

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-08-24 15:52:55  更:2021-08-24 15:54:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 23:26:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码