Unity下简单对象池的创建与使用

   我们知道不限于工程 代码之中 万事之中 总是不断寻找最好的方案 方法去解决同一样事 当然 一个事物 这样做可以 那样做也行 但是我们所要的解决当然是基于一种理解下 的“最好” 比如 计算1+2+3+...100点结果 可以咯 你可以1+2=3 3+3 =6.。。 对啊 结果是可以出来 但是我们所说的计算这个值绝对是有意义的计算  同样的 在接触一样新事物的时候 我们可能为了实现功能 采取的就是1+2=3 3+3=6.。。。 随着学习的深入与理解 自然而然会有新的方案 没错 在程序中 对象池就是解决重复利用同一资源而出现的新方案 是不是最好 我现在的知识有限 基于目前 我所能用的知识 却是最好的 

    什么是对象池?我们将需要重复利用对象存储在一个池子中,当需要时在再次使用,而不是每次都实例化一个新的对象。 比如我们在工程中开枪射击所用到的“子弹” 子弹射出去后 会消失 当再次射击 是否重新生成呢? 可不可以把消失的子弹在此拿出来使用呢? 让我们来试一下

   我们已子弹为模型-预设体来简单讲解一下


    三个脚本

  1.ObjectPool脚本 (保存对象到对象池与获取对象)该脚本不需要挂在任何游戏对象上

  2.GameManager脚本(加载生成对象)第一次加载预设体 该脚本挂在一个空物体上就行

3.SphereObj脚本 (控制保存到对象池的对象)挂在预设体上

ObjectPool脚本 ()注意 此脚本不继承MonoBehaviour 否则保存到对象池不成功 为什么? 留给读者自己思考一下

usingSystem.Collections;

usingSystem.Collections.Generic;

using UnityEngine ;


public class ObjectPool{

// 创建单例

public static ObjectPool _instant ;

public static ObjectPool GetInstant()

{

if(_instant ==null)

{

_instant = new ObjectPool() ;

}

return _instant ;

}

// 对象池 就是一个字典 键是预设体的名字string类型 值是一个数组存储GameObject的数组

private Dictionary<string,List<GameObject>> pool ;

// 字典需要初始化 在构造方法中初始化

public ObjectPool(){

pool = new Dictionary<string,List<GameObject>>();

}

// 获取对象 也是判断对象池是否有这个对象 

public GameObject GetObj(string objName,Vector3pos,Quaternionqua))

{

     // 要获取的对象 

    GameObject currentObj = null ;

// 根据键去判断字典是否有这个对象 也是判断对象池中是否有

if(pool.ContainsKey(objName))

  {

     // 对象池中有剩余 这句话的意思是说 当我射击子弹很快很快或者需求子弹数大时 对象池存储的对象是否够 不够就重新产生且添加到对象池

      if(pool[objName].count>0)

  {

      //获取当前的对象

currentObj = pool[objName][0] ;

//   一个对象利用完取出去后 就要移除  为啥?不是添加吗 怎么还要从对象池中移除呢 我们说了。有时候需求子弹数很大 利用过的在一定时间内就不能利用了 在后面的方法会在此添加进来

pool[objeName].Remove(currentObj) ;

}

}

// 如果对象为空 意思是第一次程序运行 还没有一个产生 或者是需求大 对象池中没有这么多 对象池就增加对象 

if(currentObj==Null)

{

//实例化对象

currentObj = GameManager.instance.Load(objName) ;

// 设置好对象的位置和角度 就是子弹的位置和角度

currentObj.transform.position = pos ;

currentObj.transform.rotation = qua ;

//激活对象 

currentObj.SetActive(true);

}

// 保存对象

public void SaveObj(GameObject go)

{

go.setActive(false) ;

//获取对象池名称


stringobjPoolName=go.name.Replace("(Clone)","");

Debug.Log(objPoolName);

//如果该类型的对象池存在

if(pool.ContainsKey(objPoolName))

{

//将对象保存到对象池

pool[objPoolName].Add(go);

}

else

{

//创建对象池,并保存对象到对象池

pool.Add(objPoolName,newList()

{

go

});

Debug.Log(objPoolName);

}

}

2.GameManager脚本

using System.Collections ;

using System.Collections.Generic ;

using UnityEngine ;

public class GameManager:MonBehaviour

{

// 单例

public static GameManager instance ;

void Awake()

{

   instance = this ;

}

// 加载并声称对象

public GameObject LoadObj(string objName)

{

    // 加载预设体 "Prefab"是创建的文件夹

   GameObject currentPrefab = Resources.LoAD<GameObject>("Prefab/"+objName);

return Instantite(currentPregab) ;

}

void Start()

{

}

// 这里我们模拟 每按下空格 产生一个子弹

void Update()

{

if(Input.GetKeyDown(KeyCode.Space))

{

ObjectPool.GetInstant(),GetObj("Sphere",Vector3.zero,Quaternion.identity);


}

}


}


SphereObj脚本 这个是加到对象池中对象所带的脚本 这里我们用到协程 每2s去调用一次 读者可以自己去试一下 看自己按空格的手速有多快 最多能有几个预设体产生 手速越快 对象池能提供的不足 就会重新产生一个来补充 并添加到对象池

usingSystem.Collections;

usingSystem.Collections.Generic;

usingUnityEngine;

publicclassSphereObj:MonoBehaviour{

voidOnEnable()

{

StartCoroutine(Recycle());

}

IEnumeratorRecycle()

{

yieldreturnnewWaitForSeconds(2f);

ObjectPool.GetInstant().SaveObj(gameObject);

}

//Usethisforinitialization

voidStart(){

}

//Updateiscalledonceperframe

voidUpdate(){

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容