对象池简单介绍

理论参考:http://www.cnblogs.com/mezero/p/3955130.html

代码参考:http://www.omuying.com/article/78.aspx

 

背景:首先为什么会去了解对象池技术,原因是我的游戏在iOS上运行时出现了问题,有时会闪退,于是网上寻找解决方法,大神给出的答案是内存爆了。因为游戏中会频繁而且相对大量的创建( Instantiate  )和( Destroy  ),不仅导致游戏整个性能降低,而且如果创建的数量过多,内存很容易爆了。

目的:研究并实现对象池技术。

每次我都会先去看技术的理论知识,网上很多实现对象池技术的代码,但是理论就没有过多的介绍,因为对象池本身就很简洁形象。对象池技术就是:第一次创建的时候就将对象存储在一个池子中,当需要销毁的时候不直接销毁而是隐藏,当需要时在再次使用,就不需要再次实例化一个新的对象,直接把隐藏的对象显示并拿出来用。如果对象池中已经被隐藏的物体太久没有被重新使用,应该被真正的销毁。

 

池的最重要的特性,也就是对象池设计模式的本质是允许我们获取一个“新的”对象而不管它真的是一个新的对象还是循环使用的对象。

 

理论还是很容易理解的,估计有的人看了理论就可以自己去实现了~我没有那么大神,所以去网上找了很多代码资源自己看,去理解。接下来我把怎样实现一个对象池并应用于unity中的思路和代码写出来。

 

首先根据对象池概念,我们要怎样创建一个可以随时利用的对象池、怎样把实例化的物体放进对象池、怎样从对象池中取出对象、怎样实现超时的物体可以自动删除。

 

为了解决以上问题,首先我们要分好层级:对象池管理层(PoolManager),对象池组层(PoolItem),对象池组中成员层(PoolItemTime)。简单解释一下:

1:对象池管理层(PoolManager)这个很容易理解,即直接进行对象池操作的脚本。

2:对象池组层(PoolItem),为什么要分组呢?因为我们存进对象池同类型的东西可能不止一个,比如我生成一个Cube放进对象池中,如果在上一个Cube还没有被隐藏的时候我又需要一个,那么这个时候我必须从新生成一个Cube,因为对象池中并没有可以重复使用的对象(即被隐藏的Cube)。

3:对象池组中成员层(PoolItemTime),这个类的名字我是直接采用参考代码的名字,这个类就是用来管理单个物体的。

 

接下来:

1:我们要怎样创建一个可以随时利用的对象池,我们可以直接在对象池管理类(PoolManager)里面把要用的函数直接用Static修饰就可以了(类似于文档操作之类的),这样其他的脚本可以随时调用对象池操作。

2:怎样把实例化的物体放进对象池,我们需要Push()操作来完成,其中有一个关键性的问题就是,不同类的对象很容易管理,用一个Dictionary<T, T>就可以了,同类的怎么放在一起呢?仔细研究后发现自己思维受限,同类的物品直接用一个类似数组的东西存不就好了吗?下面的代码选择用Dictionary<int, GameObject>存起来,int是获取对象的HashCode存入,其实这个并没有什么用....跟数组的效果其实是一样的, 看3就知道为什么没用了。

3:怎样从对象池中取出对象,首先找到对象所在组,然后取组中第一个对象即可,知道为什么HashCode没用了吧?你也可以将2的int全部存成1。

 

解决上上面的问题其实整个对象池就没什么了,下面贴上代码,里面的注释和我的解释对应,应该很容易明白的。

 

PoolItemTime.cs

using UnityEngine;
using System.Collections;
 
public class PoolItemTime {
 
    ///<summary>
    /// 对象
    /// </summary>
    public GameObject gameObject;
 
    ///<summary>
    /// 存取时间
    /// </summary>
    public float aliveTime;
 
    ///<summary>
    /// 销毁状态
    /// </summary>
    public bool destoryStatus;
 
    public PoolItemTime(GameObject _gameObject){
        this.gameObject = _gameObject;
        this.destoryStatus = false;
    }
 
    ///<summary>
    /// 激活对象,将对象显示
    /// </summary>
    public GameObject Active(){
        this.gameObject.SetActive (true);
        this.destoryStatus = false;
        aliveTime = 0;
        return this.gameObject;
 
    }
 
    ///<summary>
    /// 销毁对象,不是真正的销毁
    /// </summary>
    public void Destroy(){//重置对象状态
        this.gameObject.SetActive (false);
        this.destoryStatus = true;
        this.aliveTime = Time.time;
    }
 
    ///<summary>
    /// 检测是否超时,返回true或false,没有其他的操作
    /// </summary>
    public bool IsBeyondAliveTime(){
        if (!this.destoryStatus)
            return false;
        if (Time.time - this.aliveTime >= PoolManager.Alive_Time) {
            Debug.Log ("已超时!!!!!!");
            return true;
        }
        return false;
    }
}


 

 

PoolItem.cs

using UnityEngine;
using System.Collections.Generic;
 
public class PoolItem{
 
    /// <summary>
    /// 名称,作为标识
    /// </summary>
    public string name;
 
    /// <summary>
    /// 对象列表,存储同一个名称的所有对象
    /// </summary>
    public Dictionary<int, PoolItemTime> objectList;
 
    public PoolItem(string _name)
    {
        this.name = _name;
        this.objectList = new Dictionary<int, PoolItemTime> ();
    }
 
    /// <summary>
    /// 添加对象,往同意对象池里添加对象
    /// </summary>
    public void PushObject(GameObject _gameObject)
    {
        int hashKey = _gameObject.GetHashCode ();
        if (!this.objectList.ContainsKey (hashKey)) {
            this.objectList.Add (hashKey, new PoolItemTime (_gameObject));
        } else {
            this.objectList [hashKey].Active ();
        }
    }
 
    /// <summary>
    /// 销毁对象,调用PoolItemTime中的destroy,即也没有真正销毁
    /// </summary>
    public void DestoryObject(GameObject _gameObject){
        int hashKey = _gameObject.GetHashCode ();
        if (this.objectList.ContainsKey (hashKey)) {
            this.objectList [hashKey].Destroy ();
        }
    }
 
    /// <summary>
    /// 返回没有真正销毁的第一个对象(即池中的destoryStatus为true的对象)
    /// </summary>
    public GameObject GetObject(){
        if (this.objectList == null || this.objectList.Count == 0) {
            return null;
        }
        foreach (PoolItemTime poolIT in this.objectList.Values) {
            if (poolIT.destoryStatus) {
                return poolIT.Active ();
            }
        }
        return null;
    }
 
    /// <summary>
    /// 移除并销毁单个对象,真正的销毁对象!!
    /// </summary>
    public void RemoveObject(GameObject _gameObject){
        int hashKey = _gameObject.GetHashCode ();
        if (this.objectList.ContainsKey (hashKey)) {
            GameObject.Destroy (_gameObject);
            this.objectList.Remove (hashKey);
        }
    }
 
    /// <summary>
    /// 销毁对象,把所有的同类对象全部删除,真正的销毁对象!!
    /// </summary>
    public void Destory(){
        IList<PoolItemTime> poolIList = new List<PoolItemTime> ();
        foreach (PoolItemTime poolIT in this.objectList.Values) {
            poolIList.Add (poolIT);
        }
        while (poolIList.Count > 0) {
            if (poolIList [0] != null && poolIList [0].gameObject != null) {
                GameObject.Destroy (poolIList [0].gameObject);
                poolIList.RemoveAt (0);
            }
        }
        this.objectList = new Dictionary<int, PoolItemTime> ();
    }
 
    /// <summary>
    /// 超时检测,超时的就直接删除了,真正的删除!!
    /// </summary>
    public void BeyondObject(){
        IList<PoolItemTime> beyondTimeList = new List<PoolItemTime> ();
        foreach (PoolItemTime poolIT in this.objectList.Values) {
            if (poolIT.IsBeyondAliveTime ()) {
                beyondTimeList.Add (poolIT);
            }
        }
        int beyondTimeCount = beyondTimeList.Count;
        for (int i = 0; i < beyondTimeCount; i++) {
            this.RemoveObject (beyondTimeList [i].gameObject);
        }
    }
}

PoolManager.cs

using UnityEngine;
using System.Collections.Generic;
 
public class PoolManager {
 
    /// <summary>
    /// 超时时间
    /// </summary>
    public const int Alive_Time = 1 * 60;
 
    /// <summary>
    /// 对象池
    /// </summary>
    public static Dictionary<string, PoolItem> itemList;
 
    /// <summary>
    /// 添加一个对象组
    /// </summary>
    public static void PushData(string _name){
        if (itemList == null)
            itemList = new Dictionary<string, PoolItem> ();
        if (!itemList.ContainsKey (_name))
            itemList.Add (_name, new PoolItem (_name));
    }
 
    /// <summary>
    /// 添加单个对象(首先寻找对象组->添加单个对象)
    /// </summary>
    public static void PushObject(string _name, GameObject _gameObject){
        if (itemList == null || !itemList.ContainsKey (_name))
            PushData (_name);//添加对象组
        //添加对象
        itemList [_name].PushObject (_gameObject);
    }
 
    /// <summary>
    /// 移除单个对象,真正的销毁!!
    /// </summary>
    public static void RemoveObject(string _name, GameObject _gameObject){
        if (itemList == null || !itemList.ContainsKey (_name))
            return;
        itemList [_name].RemoveObject (_gameObject);
    }
 
    /// <summary>
    /// 获取缓存中的对象
    /// </summary>
    public static GameObject GetObject(string _name){
        if (itemList == null || !itemList.ContainsKey (_name)) {
            return null;
        }
        return itemList [_name].GetObject ();
    }
 
    /// <summary>
    /// 销毁对象,没有真正的销毁!!
    /// </summary>
    public static void DestroyActiveObject(string _name, GameObject _gameObject){
        if (itemList == null || !itemList.ContainsKey (_name)) {
            return;
        }
        itemList [_name].DestoryObject (_gameObject);
    }
 
    /// <summary>
    /// 处理超时对象
    /// </summary>
    public static void BeyondTimeObject(){
        if (itemList == null) {
            return;
        }
        foreach (PoolItem poolI in itemList.Values) {
            poolI.BeyondObject ();
        }
    }
 
    /// <summary>
    /// 销毁对象,真正的销毁!!
    /// </summary>
    public static void Destroy(){
        if (itemList == null) {
            return;
        }
        foreach (PoolItem poolI in itemList.Values) {
            poolI.Destory ();
        }
        itemList = null;
    }
 
}

 

上面的代码可以直接用,用法是:

1:在每次需要Instantiate时先从对象池中获取出来,然后判断获取的是否为空,为空就Instantiate一个,然后放入对象池中管理。

2:每次需要destroy的时候不执行默认destroy而是执行Poolmanager中的没有真正删除的destroy(DestroyActiveObject)。

3:在GameManager的Update中执行超时检测(BeyondTimeObject)。

 

注意:

1:对象池中获取的对象需要必要的Init操作。

2:真正频繁删除复用的对象才加入对象池管理,否则并不能达到优化目的。

3:上代码没有对数量进行控制,可以自行修改添加。

4:对象池的应用Unity已经有插件可以使用(PoolManager插件),只需要使用功能的同学可以看:http://www.xuanyusong.com/archives/2974

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值