Advertisement

Unity之对象池(单例对象池和泛型对象池)

阅读量:

众所周知,游戏开发中内存和性能一直是影响用户游戏体验的至关重要的两个因素,这次说一说对象池的概念。

对象池意义是将游戏中反复创建销毁的对象进行多次利用,从而避免大量对象的销毁与创建而造成CPU的负担。缺点是占用了更多的内存,但凡事都没有最好的解决办法,在移动平台上针对游戏的优化基本偏向于牺牲空间换取时间,所以以下两种对象池从本质上是为了回收对象服务的,废话不多说,直接上代码。

复制代码
 using UnityEngine;

    
 using System.Collections;
    
 using System;
    
 using System.Collections.Generic;
    
 /// <summary>
    
 /// 泛型非单例池,代码简洁,通用性广泛
    
 /// </summary>
    
 public class MyPool <T> where T : class {
    
 	private Action <T> mReset;							//重置对象的委托
    
 	private Func <T> mNew;								//创建新对象的委托
    
 	private Stack <T> stack;								//存放对象的池子,用List等动态数组也可以,推荐泛型数组
    
 	public MyPool (Func <T> mNew, Action <T> mReset = null) {
    
 		this.mNew = mNew;
    
 		this.mReset = mReset;
    
 		stack = new Stack<T> ();
    
 	}
    
 	//从池子中获取对象的方法,思路是若池子的数量为0,则调用创建新对象委托创建一个对象返回
    
 	//否则从池子中拿出一个对象并返回
    
 	public T New () {
    
 		if (stack.Count == 0) {
    
 			T t = mNew ();
    
 			return t;									
    
 		} else {
    
 			T t = stack.Pop ();
    
 			if (mReset != null)
    
 				mReset (t);
    
 			return t;
    
 		}
    
 	}
    
 	//此方法用于将销毁的对象存入池子
    
 	public void Store (T t) {
    
 		stack.Push (t);
    
 	}
    
 	//清空池子
    
 	public void Clear () {
    
 		stack.Clear ();
    
 	}
    
 }

此处推荐一个链接,这个对象池的写法很大程度参照这篇文章的,是一位代码节俭主义牛人写的非常好的文章。

点击打开链接

而他的使用方式如下:

复制代码
 using UnityEngine;

    
 using System.Collections;
    
 /// <summary>
    
 /// 使用池子的测试类
    
 /// </summary>
    
 public class Test : MonoBehaviour {
    
 	public GameObject ballet;										//子弹的预设体,在unity引擎中引用
    
 	private MyPool <GameObject> pool;
    
 	void Start () {
    
 		pool = new MyPool<GameObject> (NewBallet, Reset);
    
 	}
    
  
    
 	//实例化新子弹的方法
    
 	private GameObject NewBallet () {
    
 		GameObject g = Instantiate (ballet) as GameObject;		//实例化新子弹,实例化过程中需要设置子弹的位置等初始化操作写在这
    
 		return g;
    
 	}
    
 	//重置对象的方法,
    
 	private void Reset (GameObject g) {
    
 		g.transform.position = Vector3.zero;
    
 		g.transform.rotation = Quaternion.identity;
    
 		g.SetActive (true);					//从池子中取后将物体设为可见,也可用其他方法代替
    
 		//......
    
 	}
    
 	//销毁对象的方法
    
 	private void Destroy (GameObject g) {
    
 		g.SetActive (false);							//放入池子前将物体设为不可见
    
 		pool.Store (g);
    
 	}
    
 }

对于使用池子的类我只是写了最基本的应用,推荐将池子放在一个对象类型的控制类中。至于方法里的扩展根据各位看官的项目内容而定。

复制代码
 using UnityEngine;

    
 using System.Collections;
    
 using System.Collections.Generic;
    
 using System;
    
 /// <summary>
    
 /// 单例对象池,思路是为每种GameObject建立一个新的池子,并给他
    
 /// 一个字符串存在字典中。
    
 /// </summary>
    
 public class SinglePool {
    
 	#region 单例,此处使类继承MonoBehavior并写成继承MonoBehavior的单例也可以
    
 	private static SinglePool instance = null;
    
 	private SinglePool () {
    
  
    
 	}
    
 	public static SinglePool GetInstance () {
    
 		if (instance == null) {
    
 			instance = new SinglePool ();
    
 		}
    
 		return instance;
    
 	}
    
 	#endregion
    
  
    
 	#region 变量
    
 	private Dictionary <string, List <GameObject>> poolDic;		//存放池子的字典,池子用泛型List
    
 	private Action <GameObject> mReset;											//重置对象的委托
    
 	private Func <GameObject> mNew;												//创建新对象的委托
    
 	#endregion
    
  
    
 	#region 方法
    
 	//可以让字典存放Object而不是GameObject,适用性更广
    
 	//从对应字符串池子中取出对象的方法
    
 	public GameObject New (string str, Func <GameObject> mNew, Action <GameObject> mReset = null) {
    
 		if (poolDic.ContainsKey (str)) {		//如果字典存在该字符串,取出该池子										
    
 			if (poolDic [str].Count > 0) {		//如果池子里有对象则取出一个对象并返回
    
 				GameObject g = poolDic [str] [0];
    
 				poolDic [str].Remove (g);
    
 				if (mReset != null)
    
 					mReset (g);
    
 				return g;
    
 			} else {								//如果池子没有对象则返回一个创建的新对象
    
 				return mNew ();
    
 			}
    
 		} else {							//如果字典不存在该字符串则新创建一个池子,并返回一个创建的新对象
    
 			poolDic.Add (str, new List<GameObject> ());
    
 			return mNew ();
    
 		}
    
 	}
    
 	//销毁的对象存入池子的方法
    
 	public void Store (string str, GameObject g) {
    
 		if (poolDic.ContainsKey (str)) {
    
 			poolDic [str].Add (g);
    
 		}
    
 	}
    
 	//销毁对象池的方法
    
 	public void DestroyPool (string str) {
    
 		if (poolDic.ContainsKey (str)) {
    
 			poolDic.Remove (str);
    
 		}
    
 	}
    
 	#endregion
    
 }

单例池子的使用方式我就不写了,和上面大同小异,只需多传一个池子对应的string值存在字典即可。晚上继续第二天的一天一算法~

全部评论 (0)

还没有任何评论哟~