引言:
以前写c++ IOCP服务器的投递对象回收池,大量的对所谓对象池概念的泛滥接触,随便找一个游戏demo就见到某某入门初学者贴出一个:该游戏具有对象池概念…之前在学一个以介绍委托事件监听的demo为主没有用对象池的2D项目,被一个自以为很了解对象池,且自己很能的zz给“说教了”:你还有很长的路要走…
本次游戏里面有两个需要用到对象池优化缓存的地方:
1.连线物体
2.小兵对象
下面以小兵对象为例
1.先贴一下使用的初级代码(某年某大厂笔试题),后面再展示一下,一个仅仅靠装模作样写出来的继承关系代码(c#抽象接口模板虚函数)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SoldierPool
{
public static SoldierPool _instance = new SoldierPool();
public static SoldierPool Instance
{
get
{
if (_instance == null) _instance = new SoldierPool();
return _instance;
}
}
Queue<GameObject> pool = new Queue<GameObject>();
//concurrennt_queue
GameObject PoolRoot;
//代替生成函数Instantiate,接口GameObject s = SoldierPool.Instance.GetSoilder(),然后改变一下Transform
public GameObject GetSoilder()
{
GameObject result = null;
if(pool.Count<=0)
{
GameObject prefab = Resources.Load<GameObject>("Prefabs/Cylinder");
if (prefab != null)
{
result = GameObject.Instantiate(prefab);
result.SetActive(false);
pool.Enqueue(result);
}
else
{
Debug.LogError("load error Prefabs/Cylinder");
}
}
else
{
result = pool.Dequeue();
// Debug.Log("load one prefab from pool!");
}
result.SetActive(true);
return result;
}
//代替Destroy函数,接口 SoliderPool.Instance.ResetSoldier(s)
public void ResetSoldier(GameObject soldier)
{
soldier.SetActive(false);
PoolRoot = GameObject.Find("PoolRoot");
if(PoolRoot == null)
{
PoolRoot = new GameObject("PoolRoot");
}
soldier.transform.SetParent(PoolRoot.transform);
pool.Enqueue(soldier);
// Debug.Log("pool count:"+pool.Count);
}
}
在代码片段里面的使用
1.代替Instantiate
foreach (int i in Determinations)
{
Debug.Log(ID + "->" + i);
//从对象池获得一个prefabs
GameObject s = SoldierPool.Instance.GetSoilder();
//保证了prefab兵种阵营和初生大楼保持一致
s.GetComponent<Fighter>().faction = this.faction;
//初始化了兵线位置,和from起始位置保持一致
s.transform.position = transform.position - new Vector3(0, transform.position.y, 0) + new Vector3(0, 50, 0);
//设置了兵线的起始和终点,在Fighter.cs中,将使用rigidbody调用velocity进行移动
s.GetComponent<Fighter>().from = MapManager.instance.maptr[ID];
s.GetComponent<Fighter>().to = MapManager.instance.maptr[i];
s.GetComponent<Renderer>().material = MapManager.instance.lm[faction];
if (this.type == skyscraperType.ATTACK) s.GetComponent<Fighter>().rate = 2.0f;//to = MapManager.instance.maptr[i];
}
2.代替Destroy
SoldierPool.Instance.ResetSoldier(this.gameObject);
下面是自我创作部分
算是一种尝试,c#接口,模板,抽象,虚函数,重新,set、get,单例…
但是比较偏形式主义,稍微有一点c#多态性,其实是想把本次游戏里面的两种对象池使用模板进行编码调用,泛型编程
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IPool
{
void FindOrCreatePoolRoot();
}
public abstract class Pool<T> : IPool
{
protected Queue<T> pool = new Queue<T>();
protected GameObject PoolRoot;
protected T obj;
public Pool(T t)
{
obj = t;
FindOrCreatePoolRoot();
}
public void FindOrCreatePoolRoot()
{
PoolRoot = GameObject.Find("PoolRoot");
if (PoolRoot == null)
PoolRoot = new GameObject("PoolRoot");
}
public abstract T GetPrefab();
public virtual void ResetPrefab(T obj)
{
pool.Enqueue(obj);
}
//单例类设计冗余
private static Pool<T> _instance ;
public static Pool<T> Instance
{
get
{
return _instance;
}
set
{
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public sealed class Test_Pool:Pool<GameObject>
{
public Test_Pool(GameObject t) : base(t)
{
base.obj = t;
if (Instance == null) Instance = this;
}
public override GameObject GetPrefab()
{
if(pool.Count>0)
return base.pool.Dequeue();
else
{
GameObject res = null;
if(obj!=null)
{
res = GameObject.Instantiate(obj);
res.transform.SetParent(base.PoolRoot.transform);
base.pool.Enqueue(res);
return res;
}
else
{
Debug.LogError("load error :");
return null;
}
}
}
public override void ResetPrefab(GameObject obj)
{
obj.transform.SetParent(base.PoolRoot.transform);
obj.gameObject.SetActive(false);
base.ResetPrefab(obj);
}
}
public class test_application : MonoBehaviour
{
Test_Pool sp;
Test_Pool st;
private void Awake()
{
GameObject t = Resources.Load<GameObject>("Prefabs/Cylinder");
st = new Test_Pool(t);
GameObject s = Resources.Load<GameObject>("Prefabs/line_Empty");
sp = new Test_Pool(s);
}
void Update()
{
GameObject res = sp.GetPrefab();
//Test_Pool.Instance.ResetPrefab(res);
GameObject ts = st.GetPrefab();
}
}
但是基类的单例设计其实是完全没有必要的,这样就完成了使用一个基类完成多个对象池的多态性实现
如果改写Test_Pool,把T设置为其他泛型比如:.cs,Transform等,就可以更好发挥c#的多态性!