您的位置:首页 > 移动开发 > Unity3D

关于对象池的初步理解与使用

2017-12-08 09:17 218 查看
在我们使用对象池之前我们需要知道以下两点:

1.什么是对象池?

  池(Pool),与集合在某种意义上有些相似。 水池,是一定数量的水的集合;内存池,是一定数量的已经分配好的内存的集合;线程池,是一定数量的已经创建好的线程的集合。那么,对象池,顾名思义就是一定数量的已经创建好的对象(Object)的集合[1]。

  在面向对象过程中,如果一种对象,你要经常使用,并且需要反复创建、销毁,这样子一方面开销会比较大,另一方面会产生很多内存碎片,程序运行时间一过长,性能就会下降。这个时候,就产生了对象池。我们可以事先创建好一批对象,并且放在一个集合中(对象池),以后每当程序需要使用到对象的时候,我们不是创建一个对象,而是从对象池里获取,程序用完该对象后,再把该对象归还给对象池。这样,就会少了很多的关于创建或者销毁的调用,在一定程度上提高了系统的性能,尤其在动态内存分配比较频繁的程序中效果较为明显。

2.Unity3d中的对象池

  在使用unity3d做游戏时,经常有同一个Prefab用到多次,需要反复实例化(Instantiate)。但实例化是很消耗资源的,所以在游戏加载时把一批Prefab实例化好放在对象池中,游戏中用的时候拿出来,不用的时候放回去,避免反复申请和销毁。

  存入对象池的元素应具有如下特征:1>场景中大量使用 2>存在一定的生命周期,会较为频繁的申请和释放。

下面不多说直接上代码:

usingSystem.Collections;

using
System.Collections.Generic;

using
UnityEngine;

public
class
ObjectPoolManager
:
MonoBehaviour
{

   
// 继承于monoBehaviour的单例可以简化为这样,方便使用

   
public
static
ObjectPoolManager
Instance;

   
// 定义一个大池子

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

   
void
Awake(

    {

       
Instance
=
this;

    }

   
void
Start()

    {

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

    }

   

   
// 两个主要方法,存、取

   
// 取对象

   
public
GameObject
GetObjectFromPool(string
objName,
Vector3
pos,
Quaternion
qua)

    {

       
GameObject
go;

       
// 当池子中有相应的键值对,并且里面有可以使用的对象,则直接拿出来用

       
if
(pool.ContainsKey(objName)
&&
pool[objName].Count
> 0)

        {

           
// 把相应的键值对中的第一个对象取出来,并从池子中移除

           
go
=
pool[objName][0];

           
pool[objName].RemoveAt(0);

           
// 激活这个对象

           
go.SetActive(true);

        }

       
else

        {

           
// 若不满足上面条件,则实例化一个新的对象出来

           
go
=
Instantiate(Resources.Load(objName)
as
GameObject);

        }

       
// 设置一下得到的对象的位置以及旋转角度

       
go.transform.position
=
pos;

       
go.transform.rotation
=
qua;

       
return
go;

    }

   
// 存对象(参数为我们即将存入的对象)

   
public
void
PushObjectToPool(GameObject
go)

    {

       
string
prefabName
=
go.name.Split('(')[0];

       
// 判断池子中有没有相应的键值对,没有则创建一个新的键值对,有则直接往里存

       
if
(pool.ContainsKey(prefabName))

        {

           
pool[prefabName].Add(go);

        }

       
else

        {

           
// 在池子中创建一个新的键值对,并初始化List

           
pool[prefabName]
=
new
List<GameObject>()
{go};

        }

       
// 取消激活该对象

       
go.SetActive(false);

    }
[align=left]}[/align]

[align=left]usingSystem.Collections;[/align]

using
System.Collections.Generic;

using
UnityEngine;

public
class
MyFight
:
MonoBehaviour
{

   
// 定义即将生成的预制体名字

   
const
string
redBullet
=
"RedBullet";

   
const
string
blueBullet
=
"BlueBullet";

   
// 获取两种子弹生成的位置及角度信息

   
public
Transform
redBulletPos;

   
public
Transform
blueBulletPos;

       // Use this for initialization

       void
Start
() {

              

       }

       

       // Update is called once per frame

       void
Update
() {

       
// 按下鼠标左键生成红色子弹

       
if
(Input.GetMouseButtonDown(0))

        {

           
// 生成的操作就是取对象的操作

           
GameObject
go
=
ObjectPoolManager.Instance.GetObjectFromPool(redBullet,
redBulletPos.position,
redBulletPos.rotation);

           
// 给子弹加力度

           
go.GetComponent<Rigidbody>().AddForce(go.transform.forward
* 500);

           
// 让子弹一秒钟之后消失(放入池子)

           
StartCoroutine(DestroyBullet(go));

        }

       
// 鼠标右键生成蓝色子弹

       
if
(Input.GetMouseButtonDown(1))

        {

           
// 生成的操作就是取对象的操作

           
GameObject
go
=
ObjectPoolManager.Instance.GetObjectFromPool(blueBullet,
blueBulletPos.position,
blueBulletPos.rotation);

           
// 给子弹加力度

           
go.GetComponent<Rigidbody>().AddForce(go.transform.forward
* 500);

           
// 让子弹一秒钟之后消失(放入池子)

           
StartCoroutine(DestroyBullet(go));

        }

       }

       

   
IEnumerator
DestroyBullet(GameObject
go)

    {

       
yield
return
new
WaitForSeconds(1);

       
// 重置子弹的速度为0

       
go.GetComponent<Rigidbody>().velocity
=
Vector3.zero;

       
ObjectPoolManager.Instance.PushObjectToPool(go);

    }
[align=left]}[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息