Unity框架之缓存池模块

如今的Unity提供官方写好的缓存池,但我还是打算讲讲自定义缓存池怎么写。

缓存池用途

在射击游戏中,游戏中存在着频繁的子弹创建和销毁工作。如果内存大量频繁地创建和销毁物体,势必会带来很明显的卡顿和性能开销。游戏开发者思考,我是不是可以重复利用固定几个物体、减少内存浪费和性能开销?于是有了缓存池。

思路

以射击游戏为例,先去思考怎么实现子弹缓存效果,我的想法是,场上能看见的子弹也就五、六个,射出去的子弹超出玩家视野后、进行重复利用。于是分类:子弹类——子弹1、子弹2、子弹3、子弹4...
然而缓存池不一定只有子弹类,可能还有炮弹类、垃圾类等等,最后划分大概是这样的一张图表:
物体
子弹类 炮弹类 垃圾类 ...
子弹二 炮弹二 垃圾二 ...
子弹三 炮弹三 垃圾三 ...

这就类似于我们的衣柜,衣柜里有不同的抽屉,每个抽屉里放着不同的衣服,于是联想到字典和List,用Dictionary<string,Queue>来存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;

public class GamePoolManager : SingleMono<GamePoolManager>
{
[System.Serializable]
private class PoolItem
{
public string itemName;
public GameObject item;
public int itemCount;
}
[SerializeField]private List<PoolItem> poolList = new List<PoolItem>();
private Dictionary<string,Queue<GameObject>> poolDic = new Dictionary<string,Queue<GameObject>>();
private GameObject _poolParrent;

private void Awake()
{
_poolParrent = new GameObject("对象池父对象");
_poolParrent.transform.SetParent(transform);
InitPool();
}
//把东西塞池子里
private void InitPool()
{
//遍历池子
for (int i = 0; i < poolList.Count; i++)
{
for(int j = 0; j<poolList[i].itemCount; j++)
{
var item1 = Instantiate(poolList[i].item);
item1.transform.SetParent(_poolParrent.transform);
item1.SetActive(false);

//如果没有对应的池子,我们new一个
if (!poolDic.ContainsKey(poolList[i].itemName))
{
poolDic.Add(poolList[i].itemName, new Queue<GameObject>());
}
poolDic[poolList[i].itemName].Enqueue(item1);
}
}
}

public void TryGetPoolItem(string name,Vector3 position,Quaternion rotation)
{
if (poolDic.ContainsKey(name))
{
GameObject item = poolDic[name].Dequeue();
item.transform.position = position;
item.transform.rotation = rotation;
item.SetActive(true);
poolDic[name].Enqueue(item);
}
else
{
Debug.Log("你从对象池要拿的不存在");
}
}
public GameObject TryGetPoolItem(string name)
{
if (poolDic.ContainsKey(name))
{
GameObject item = poolDic[name].Dequeue();
item.SetActive(true);
poolDic[name].Enqueue(item);
return item;
}
else
{
Debug.Log("你从对象池要拿的不存在");
return null;
}
}
}