经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
Unity日记—对象缓存池
来源:cnblogs  作者:青空哲也  时间:2019/3/29 8:41:23  对本文有异议

最近都在忙别的事了,今天忙里偷闲了解了一下对象池是啥玩意,简单记录一下。

还是个正在学习的萌新,如果写的不好请见谅。

 

1.对象池是啥

在了解对象池之后,我才意识到以前写的代码有多么蠢,当场景中有一些重复的需要生成和销毁的物体时(比如地上可拾取的金币),我们常常调用Instantiate和Destroy函数去实现,这造成了大量的性能开销,尤其是当游戏物体挂载脚本时,脚本中的Awake()、OnEnable()、OnDestroy()等方法不断被调用,对性能造成了很大的负担,所以在复用性强的游戏中缓存池是十分重要的。

对象池的原理就是我们把需要复用的物体存在池子里,需要“销毁物体”时,通过SetActive方法暂时让物体隐藏而不是真的销毁,需要“生成物体”时,先看看池子里有没有之前隐藏的物体,如果有就直接将其激活,没有的话再去生成物体,这样我们真正需要去生成物体的次数永远是场景中同时存在该物体的最大值,而不是每次使用都去生成和销毁。

 

2.对象池实现

我在unity中简单实现了一个对象池,用字典的形式存储每种物体对应的池子(也就是List),取出物体时使用一个字符串代表该物体,然后将该物体的预制体放在Resources目录下,注意预制体的名字要和传入的参数相同。

需要注意的是,我们只是隐藏了物体,而物体的位置、旋转等信息并没有改变,所以当我们下次取出它时,它的数据还和原来一样,这种数据通常称为“脏数据”,所以我们可以让复用的物体都继承一个父类,提供两个抽象方法,让子物体去重写,当把物体取出和放回池子时调用这两个方法去处理数据。

  1. public abstract class RecyclableObject:MonoBehaviour
  2. {
  3. public abstract void OnSpawn();
  4. public abstract void OnUnspawn();
  5. }

取出和放回物体时,可以使用SendMessage来调用子类身上的方法处理脏数据,比如调整位置之类的。

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class ObjectPool
  5. {
  6. //单例
  7. private static ObjectPool _instance;
  8. public static ObjectPool Instance
  9. {
  10. get
  11. {
  12. if (_instance == null)
  13. {
  14. _instance = new ObjectPool();
  15. }
  16. return _instance;
  17. }
  18. }
  19. public Dictionary<string, List<GameObject>> poolsDict = new Dictionary<string, List<GameObject>>();
  20. //取出物体
  21. public void Spawn(string name,Transform parent)
  22. {
  23. //如果没有这个类型的池子就创建一个
  24. if(!poolsDict.ContainsKey(name))
  25. {
  26. poolsDict.Add(name, new List<GameObject>());
  27. }
  28. //得到池子
  29. List<GameObject> ObjList;
  30. poolsDict.TryGetValue(name, out ObjList);
  31. //在池子里寻找被隐藏的游戏物体
  32. GameObject go = null;
  33. foreach(var obj in ObjList)
  34. {
  35. if(!obj.activeSelf)
  36. {
  37. go = obj;
  38. }
  39. }
  40. if(go==null)//不存在隐藏的游戏物体
  41. {
  42. go = Object.Instantiate(Resources.Load<GameObject>(name));
  43. ObjList.Add(go);
  44. }
  45. else//存在隐藏的游戏物体
  46. {
  47. go.SetActive(true);
  48. }
  49. go.transform.parent = parent;
  50. go.SendMessage("OnSpawn", SendMessageOptions.DontRequireReceiver);
  51. }
  52. //回收物体
  53. public void Unspawn(GameObject go)
  54. {
  55. foreach(List<GameObject> list in poolsDict.Values)
  56. {
  57. if(list.Contains(go)&&go.activeSelf)
  58. {
  59. go.SendMessage("OnUnspawn", SendMessageOptions.DontRequireReceiver);
  60. go.SetActive(false);
  61. }
  62. }
  63. }
  64. //销毁池子
  65. public void ClearPool(string name)
  66. {
  67. if(poolsDict.ContainsKey(name))
  68. {
  69. foreach(GameObject go in poolsDict[name])
  70. {
  71. Object.Destroy(go);
  72. }
  73. poolsDict.Remove(name);
  74. }
  75. }
  76. }

 

 

 

马上要参加计算机设计大赛的省赛和蓝桥杯的国赛,所以暂时没时间学游戏开发了,希望比赛能有个好结果,加油吧。

 

原文链接:http://www.cnblogs.com/LiveForGame/p/10612007.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号