[Unity3D教程]Unity中如何编写对象重用池机制
来源:互联网 发布:libcurl c语言 编辑:程序博客网 时间:2024/05/21 19:49
[Unity3D教程]Unity中如何编写对象重用池机制
欢迎到CSDN学院观看我的Unity3D开发视频教程:http://edu.csdn.NET/lecturer/lecturer_detail?lecturer_id=107
(版权归蓝欧科技有限公司所有,任何单位或者个人不可以私自转载,如果有需有,请于蓝欧科技有限公司相关部门联系)
对象重用池的概念其实非常简单:创建使用后的对象不会直接销毁,而是存储在一个池子中,当需要时在可在池子中拿出再供使用。
对象池的最重要的特性,也就是对象池设计模式的本质是允许我们获取一个“新的”对象而不管它真的是一个新的对象还是循环使用的对象。
对象重用池是典型“空间换时间”案例。通过减少CPU调用系统调用时的资源消耗,转为对内存的长期占用,进而达到提升“处理速度”的效果。也就是说:对象重用池是对CUP的优化,而不是对内存的优化策略(反而是增加负担了呢)。
对象重用池机制在各个语言中都普遍存在,有些语言甚至将重用池机制封装到了框架底层,比如iOS中的TableViewCell的重用机制。在Unity中的用户自定义对象并没有现成类来提供重用管理,这个功能需要我们自己编写。
对象重用池的方案有非常多的成熟框架供我们使用,甚至三言两语就能勾勒出一幅重用池:
#使用堆栈模拟一个简单的对象重用池#
使用方法:
当然, 上述代码只能出现在演示Demo中, 它实在是太简单了。事实上,如果你搜索下用Unity实现的对象池类库,你会发现其中很多是相当复杂的。我们先来分析下一个合格的对象池应该具备哪些优秀品质:
• 对象进入对象池之时,应该提供接口事件,通知用户该事件。
• 从池子中拿出的对象时,应该提供接口事件,用户可以在方法内对该对象进行操作,比如重置、刷新数据。
• 能够管理多种对象。
• 能够提供清理池子的接口,甚至提供定期自动清理策略。
• 某些类型的资源是很珍贵的(如数据库连接),池需要显示上限并提供一个针对分配对象失败的安全措施;
• 对于需要长期持有的资源,如网络连接、数据库连接等资源,需要提供分配失败的安全措施。
• 线程安全的。
在此提供一种实现思路:
• 面向用户的ObjectPoolCtrl(对象池管理类)类:
该类直接与用户交互且负责管理多个对象池子.
• 能够进入池子的对象需要遵循的协议IReuse
• 能够进入池子的对象基类ReuseObject
• 池子类SubPool,真正妇科管理对象
关系示意图:
接口代码:
public interface IReuse {
void Spawn();
void UnSpawn();
}
基类代码:
using UnityEngine;
public abstract class ReuseObject : MonoBehaviour, IReuse {
// 所有类的基类, 想要进入池子的对象不要在继承MonoBehaviour了
// 而是要继承此类.
public abstract void Spawn();
public abstract void UnSpawn();
}
负责和用户交互的对象池管理类:
using UnityEngine;
using System.Collections.Generic;
public class ObjectPoolCtrl : MonoSingleton<ObjectPoolCtrl> {
#region 字段
// 总池子
Dictionary<string, SubPool> m_pools = new Dictionary<string, SubPool>();
#endregion
#region 面向用户的方法
public GameObject Spawn(string name) {
SubPool subPool;
// 如果总的池子中, 含有子池子的名称
if (m_pools.ContainsKey(name)) {
RegisterSubPools(name);
}
// 将刚刚创建好的子池子放入到大池子中
subPool = m_pools[name];
return subPool.Spawn();
}
private void RegisterSubPools(string name) {
GameObject prefab = ResourcesMgrBase.Instance.Load<GameObject>(name);
SubPool subPool = new SubPool(prefab);
m_pools.Add(subPool.Name, subPool);
}
private void UnSpawn(GameObject obj) {
foreach (SubPool pool in m_pools.Values) {
if (pool.Contains(obj)) { // 这里是比对的两个对象完全相等.
pool.UnSpawn(obj);
break;
}
}
}
// 清空所有池子的方法
private void UnSpawnALl() {
foreach (SubPool pool in m_pools.Values) {
pool.UnSpawnAll();
}
}
#endregion
}
池子对象:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SubPool {
#region 字段
// 这个list链表存放该池子内的所有对象
List<GameObject> m_subPool = new List<GameObject>();
// 池子中预设体的预设体类型.
GameObject m_prefab;
#endregion
#region 属性
// 当前池子的名称
public string Name {
get {
return m_prefab.name;
}
}
#endregion
#region 构造方法
// 外部可以通过传入一个预设体构造一个池子.
// 但是池子是什么时候创建的呢?
// 调用这个方法也没有new一个池子啊.
public SubPool (GameObject prefab) {
m_prefab = prefab;
}
public GameObject Spawn() {
GameObject obj = null;
foreach (GameObject Go in m_subPool) {
if (go.active == false) {
obj = go;
break;
}
}
if (obj == null) {
obj = GameObject.Instantiate(m_prefab) as GameObject;
m_subPool.Add(obj);
}
// 从池子出来后, 就要将激活状态设置为激活了.
obj.SetActive(true);
// 这里获取池子对象中的接口方法, 如果有才调用.
IReuse iReuse = obj.GetComponent<IReuse>();
if (iReuse != null) {
iReuse.Spawn();
}
return obj;
}
public void UnSpawn(GameObject obj) {
if (m_subPool.Contains(obj)) {
IReuse iReuse = obj.GetComponent<IReuse>();
if (iReuse != null) {
iReuse.UnSpawn();
}
obj.SetActive(false);
}
}
public void UnSpawnAll() {
foreach (GameObject obj in m_subPool) {
if (obj.activeSelf) {
UnSpawn(obj);
}
}
}
public bool Contains(GameObject go) {
return m_subPool.Contains(go);
}
#endregion
}
- [Unity3D教程]Unity中如何编写对象重用池机制
- [Unity3D教程]Unity中如何编写对象重用池机制
- unity 对象池编写
- Unity教程之-Unity3d中基于订阅者模式实现事件机制
- 【Unity 教程】对象池
- unity3d中怎样重用assets
- unity3d中怎样重用assets
- unity3d中怎样重用assets
- django 1.8 官方文档翻译: 1-3-1 高级教程:如何编写可重用的应用
- 9.Django入门:高级教程-如何编写可重用的应用
- Unity教程之-Unity3d中图片的灰度处理
- Unity教程之-Unity3d游戏中自定义贝塞尔曲线编辑器
- Django教程-编写可重用应用
- unity中对象池
- AbsListView中item重用机制
- 如何在unity3d中嵌入播放视频【unity3d教程】
- 【Unity3D基础教程】给初学者看的Unity教程(零):如何学习Unity3D
- 【Unity3D基础教程】给初学者看的Unity教程(零):如何学习Unity3D
- 【Android】播放音效——SoundPool
- 解决Spring MVC @ResponseBody返回中文字符串乱码问题
- js 创建遍历数组
- Java 23种设计模式 趣味解释,很有意思
- android webview 的使用
- [Unity3D教程]Unity中如何编写对象重用池机制
- android蓝牙源码分析
- 最长无重复字符的子串 lintcode
- txt文件插入数据到数据库
- CentOS 7 下Firewall防火墙配置用法详解
- 多列布局——Columns
- JS 冒泡排序
- 能够作图的软件都有哪些
- 视觉SLAM漫谈