关于对象池的初步理解与使用
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]
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]
相关文章推荐
- 关于使用LoadRunner对Appeon Web应用进行压力测试的初步介绍
- 关于使用LoadRunner对Appeon Web应用进行压力测试的初步介绍
- 关于使用LoadRunner对Appeon Web应用进行压力测试的初步介绍
- 关于使用LoadRunner对Appeon Web应用进行压力测试的初步介绍
- 关于多线程同步的初步教程--Barrier的设计及使用
- 关于eclipse的初步使用
- 关于.NET 使用堆栈来维护值类型变量的思考和理解
- 关于utl_file的初步使用
- 关于在VS2008以下版本的MFC程序使用VS 2008 FeaturePack出现内存泄露的理解
- 关于VS的延迟加载dll的使用和理解
- 关于元件2801-4与MAX604项目延展使用理解
- 关于strdup的使用与理解
- 关于Xcode4.2中的release“不能”使用的理解
- 关于oracle中使用nvl函数时,对空字符串的理解
- 关于REST架构风格的初步理解
- __atribute__使用:关于_attribute__ ((used,__section__(".xxxx")))的理解
- ExcelVBA编程系列之对象模型(2):初步理解和使用Excel对象模型
- 初步理解和使用Excel对象模型
- 关于在VS2008以下版本的MFC程序使用VS 2008 FeaturePack出现内存泄露的理解
- 关于多线程同步的初步教程--使用synchronized