[Unity基础] 对象池

对象池是一种通过空间来换取时间的思想
占内存,时间消耗少
适用性:频繁创建/销毁游戏对象

字典<类型,对象>
数据结构:Dictionary<string,List< GameObject >>
核心成员
1.通过对象池创建对象
2.回收对象

GameObjectPool

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

namespace Common
{
    /* 
     *使用方式
     * 1.所有频繁创建/销毁的游戏对象,通过对象池来使用,或创建或回收
     * GameObjectPool.Instance.CreateObjet(类别,预制体,位置,旋转);
     * GameObjectPool.Instance.CollectObjet(游戏对象);
     * 2.需要通过对象池创建的游戏对象,如需每次创建时执行,则让脚本实现IRestable接口
     */

    /// <summary>
    /// 如果游戏对象某些行为需要重置
    /// </summary>
    internal interface IRestable
    {
        void OnReset();
    }

    /// <summary>
    /// 对象池
    /// 只用一次,继承单例类
    /// </summary>
    public class GameObjectPool : MonoSingleton<GameObjectPool>
    {
        //数据结构
        //对象池:字典<类别,列表<对象>>
        private Dictionary<string , List<GameObject>> cache;

        //初始化
        public override void Init()
        {
            base.Init();
            cache = new Dictionary<string, List<GameObject>>();
        }

        /// <summary>
        /// 【重要一】通过对象池,创建对象
        /// </summary>
        /// <param name="key">类别</param>
        /// <param name="prefab">需要创建实例的预制体</param>
        /// <param name="pos">位置</param>
        /// <param name="rotate">旋转</param>
        /// <returns>返回需要的对象</returns>
        /// 结构清晰
        public GameObject CreateObject(string key,GameObject prefab,Vector3 pos,Quaternion rotate)
        {
            //1.找到可用的对象
            GameObject go = FindUsableObject(key);

            //2.如果未找到可以使用,创建新对象,并加入对象池
            if (go == null)
            {
                go =  AddObject(key, prefab); //创建游戏对象--->设置目标点--->设置位置、旋转
            }

            //3.设置对象的位置,旋转(提取方法)
            UseObject(pos, rotate, go);
            return go;

        }


        //1.查找可用的对象,返回对象
        private GameObject FindUsableObject(string key)
        {
            //1.查找指定类别,找到未使用(禁用、未激活)的对象
            //如果包含此类别
            if (cache.ContainsKey(key))
            {
                //找到未使用的对象
                return cache[key].Find(g => !g.activeInHierarchy);
            }
            return null;
        }

        //2.创建新的对象,并加入对象池,返回一个对象
        private GameObject AddObject(string key, GameObject prefab)
        {
            //2.创建新的对象,并加入对象池
            //创建新的对象
            GameObject go = Instantiate(prefab);
            //加入对象池,如果池中没有key类别
            if (!cache.ContainsKey(key))
            {
                //添加新的类别key
                cache.Add(key, new List<GameObject>());
                //把对象go加入这个key类别
                cache[key].Add(go);
            }
            return go;        
        }
        //钩子...
        //3.设置对象的位置,旋转
        private void UseObject(Vector3 pos, Quaternion rotate, GameObject go)
        {
            go.transform.position = pos;
            go.transform.rotation = rotate;
            go.SetActive(true);
            //设置目标点
            //抽象
            //go.GetComponent<IRestable>().OnReset();
            //遍历需要创建的对象所有组件,执行需要重置的逻辑,比如设计目标点等
            foreach (var item in go.GetComponents<IRestable>())
            {
                item.OnReset();
            }

        }


        /// <summary>
        /// 【重要二】回收对象
        /// </summary>
        /// <param name="go">需要被回收的对象</param>
        /// <param name="delay">延迟时间,默认为0</param>
        public void CollectObject(GameObject go ,float delay=0)
        {
            StartCoroutine(CollectObjectDelay(go,delay));
        }

        public IEnumerator CollectObjectDelay(GameObject go, float delay = 0)
        {
            yield return new WaitForSeconds(1);
            go.SetActive(false);
        }

        /// <summary>
        /// 清空某个key类别,和其游戏对象
        /// </summary>
        /// <param name="key">类别</param>
        public void Clear(string key)
        {
            顺序删除
            //for (int i = 0; i < cache[key].Count; i++)
            //{
            //    Destroy(cache[key][i]);
            //}

            //常规倒叙删除,游戏对象
            for (int i = cache[key].Count-1; i >=0; i--)
            {
                Destroy(cache[key][i]);
            }


            //删除类别
            cache.Remove(key);

        }

        /// <summary>
        /// 清除全部类别
        /// </summary>
        /// <param name="key"></param>
        public void ClearAll(string key)
        {
            //foreach只读元素,不能操作
            //异常:无效的操作
            //foreach (var item in cache.Keys)
            //{
            //    Clear(key);//删除字典记录
            //}

            //将所有字典的key存入list中
            List<string> keyList = new List<string>(cache.Keys);
            //读A删除B,遍历A集合,删除字典记录
            foreach (var item in keyList)
            {
                Clear(key);
            }
        }
    }  
}

Bullet

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

namespace ns
{
	/// <summary>
	/// 
	/// </summary>
	public class Bullet : MonoBehaviour ,IResetable
	{
        private Vector3 targetPos;

        //创建对象时执行一次
        //private void Awake()
        //{
        //    //计算正前方50m的世界坐标
        //    //TransformPoint :  自身坐标系 --->  世界坐标系
        //    targetPos = transform.TransformPoint(0, 0, 50);
        //}

        //每次通过对象池创建时执行一次
        public void OnReset()
        {
            targetPos = transform.TransformPoint(0, 0, 50);
        }

        private void Update()
        {
            transform.position = Vector3.MoveTowards(transform.position, targetPos, Time.deltaTime * 50);

            if (Vector3.Distance(transform.position, targetPos) < 0.1)
            {
                //Destroy(gameObject);
                GameObjectPool.Instance.CollectObject(gameObject); 
                //System.Object                     object      int     List<string>
                //UnityEngine.Object             Object     模型  贴图  组件
            }
        }
    }
}

Gun


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

namespace ns
{
	/// <summary>
	/// 
	/// </summary>
	public class Gun : MonoBehaviour 
	{
        public GameObject bulletPrefab;

        /*
        问题:子弹发射方向有误。
        解决:…… 
        */

        public void Fire()
        {
            //创建物体  -->  设置位置/旋转  -->  立即执行Awake(计算目标点)
            //Instantiate(bulletPrefab, transform.position, transform.rotation);
            //创建物体  --> 设置位置/旋转   --> 重置(计算目标点)
            GameObjectPool.Instance.CreateObject("bullet", bulletPrefab, transform.position, transform.rotation);
        }

        //************测试**************
        private void OnGUI()
        {
            if (GUILayout.Button("发射"))
            {
                Fire();
            }

            if (GUILayout.Button("清空类别"))
            {
                GameObjectPool.Instance.Clear("bullet");
            }

            if (GUILayout.Button("清空全部"))
            {
                GameObjectPool.Instance.ClearAll();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值