博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity日记—对象缓存池
阅读量:5308 次
发布时间:2019-06-14

本文共 2694 字,大约阅读时间需要 8 分钟。

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

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

 

1.对象池是啥

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

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

 

2.对象池实现

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

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

public abstract class RecyclableObject:MonoBehaviour{    public abstract void OnSpawn();    public abstract void OnUnspawn();}

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

using System.Collections;using System.Collections.Generic;using UnityEngine;public class ObjectPool{    //单例    private static ObjectPool _instance;    public static ObjectPool Instance    {        get        {            if (_instance == null)            {                _instance = new ObjectPool();            }            return _instance;        }    }    public Dictionary
> poolsDict = new Dictionary
>(); //取出物体 public void Spawn(string name,Transform parent) { //如果没有这个类型的池子就创建一个 if(!poolsDict.ContainsKey(name)) { poolsDict.Add(name, new List
()); } //得到池子 List
ObjList; poolsDict.TryGetValue(name, out ObjList); //在池子里寻找被隐藏的游戏物体 GameObject go = null; foreach(var obj in ObjList) { if(!obj.activeSelf) { go = obj; } } if(go==null)//不存在隐藏的游戏物体 { go = Object.Instantiate(Resources.Load
(name)); ObjList.Add(go); } else//存在隐藏的游戏物体 { go.SetActive(true); } go.transform.parent = parent; go.SendMessage("OnSpawn", SendMessageOptions.DontRequireReceiver); } //回收物体 public void Unspawn(GameObject go) { foreach(List
list in poolsDict.Values) { if(list.Contains(go)&&go.activeSelf) { go.SendMessage("OnUnspawn", SendMessageOptions.DontRequireReceiver); go.SetActive(false); } } } //销毁池子 public void ClearPool(string name) { if(poolsDict.ContainsKey(name)) { foreach(GameObject go in poolsDict[name]) { Object.Destroy(go); } poolsDict.Remove(name); } }}

 

 

 

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

 

转载于:https://www.cnblogs.com/LiveForGame/p/10612007.html

你可能感兴趣的文章
《javascript dom编程艺术》笔记(一)——优雅降级、向后兼容、多个函数绑定onload函数...
查看>>
IIS日志详解--logfiles
查看>>
bind cname
查看>>
python手记(7)------字典dict基础
查看>>
关于齐次坐标的理解
查看>>
mptcp 主机无法多IP直连同一路由器
查看>>
37.数字在排序数组中出现的次数
查看>>
人,绩效和职业道德
查看>>
[CSS3] Understand CSS Selector Specificity
查看>>
[D3] 7. Quantitative Scales
查看>>
神奇的python系列8:函数(一)
查看>>
BZOJ1965: [Ahoi2005]SHUFFLE 洗牌(exgcd 找规律)
查看>>
P3376 【模板】网络最大流
查看>>
20180908 2018-2019-2 《密码与安全新技术专题》第7周作业
查看>>
AliCTF 2015-题目解析之代码血案
查看>>
Spring如何解析XML文件——Spring源码之XML初解析
查看>>
单调队列模板浅谈
查看>>
linux命令学习之:chown
查看>>
禁止Centos7系统yum自动下载更新
查看>>
基本类型和包装类
查看>>