淘先锋技术网

首页 1 2 3 4 5 6 7

推荐阅读:

前言

      以前去面试,总是会被问及优化方面的问题,使用对象池是优化的一种常见方式。所谓对象池:在一部分内存空间(池子)中事先实例化好固定数量的对象,当需要使用池中的对象时,首先判断该池中是否有闲置(暂未使用)的对象,如果有,则取出使用,如果没有,则在池中创建该对象。当一个对象不再被使用时,其应该将其放回对象池,以便后来的程序使用

对象池的使用场景

1.需要使用大量对象
2.实例化开销比较大且生存期比较短。
例如:
(1)在飞行射击类的游戏中,子弹的发射。当用户射击的时候,会创建很多“子弹”对象,当“子弹”对象碰到敌人时,会被销毁。
(2)在跳跃台阶类的游戏中,台阶的生成与销毁。当跳跃上升一个台阶时,需要在最上面生成一个台阶,同时最下面也会销毁一个台阶。

实际操作

1.创建一个空物体,命名为ObjectPool,创建一个C#脚本,命名为ObjectPool,并将该脚本挂载到对应名字的空物体上。
在这里插入图片描述
2.打开ObjectPool脚本,创建单例模式

public class ObjectPool : MonoBehaviour 
{
    public static ObjectPool Instance;

    void Awake()
    {
        Instance = this;
    }
}

2.创建需要放在对象池中的对象的指定个数

private int initCount=5;//默认每种对象初始实例化5个
private ManagerVars vars;//管理资源器
public List<GameObject> normalPlatform = new List<GameObject>();//普通的平台对象(对象1)
public List<GameObject> commonPlatformGroup = new List<GameObject>();//通用平台对象(对象2)

private void Init()
{
	for (int i = 0; i < initCount; i++)
	{
    	InstantiateObject(vars.normalPlatformPre, normalPlatform);
	}
	for (int i = 0; i < initCount; i++)
	{
	    for (int j = 0; j < vars.commonPlatformGroup.Count; j++)
	    {
	        InstantiateObject(vars.commonPlatformGroup[j], commonPlatformGroup);
	    }
	}
}
/// <summary>
/// 实例化prefab预制体,将该预制体添加到addList类型的list中
/// </summary>
private GameObject InstantiateObject(GameObject prefab,List<GameObject> addList)
{
    GameObject go = Instantiate(prefab, transform);
    go.SetActive(false);//未使用该实例对象时隐藏
    addList.Add(go);//将该对象添加到该对象列表中
    return go;
}

3.提供取出对象的方法

    /// <summary>
    /// 获取一个单个平台
    /// </summary>
    public GameObject GetNormalPlatform(List<GameObject> getList)
    {
        for (int i = 0; i < getList.Count; i++)
        {
            if (getList[i].activeInHierarchy == false)//未使用
            {
                return getList[i];
            }
        }
        return InstantiateObject(vars.normalPlatformPre,getList);
    }
    /// <summary>
    /// 获取一个指定类型的组合平台
    /// </summary>
    public GameObject GetCommonPlatform(List<GameObject> getList)
    {
        for (int i = 0; i < getList.Count; i++)
        {
            if (getList[i].activeInHierarchy == false)//未使用
            {
                return getList[i];
            }
        }
        int ran = Random.Range(0, getList.Count);//随机公用平台的类型
        return InstantiateObject(getList[ran], getList);
    }

4.向对象池存对象

    public GameObject AddToPool(GameObject go)
    {
        go.SetActive(false);
    }

5.在客户端使用

//GameObject go = Instantiate(vars.normalPlatformPre, transform);//原始实例化方法
GameObject go= ObjectPool.Instance.GetNormalPlatform(ObjectPool.Instance.normalPlatform);//使用对象池实例化方法
go.SetActive(true);//使用该实例对象时显示

对象池脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectPool : MonoBehaviour {
    public static ObjectPool Instance;//单例模式

    public List<GameObject> normalPlatform = new List<GameObject>();
    public List<GameObject> commonPlatformGroup = new List<GameObject>();
    
    private ManagerVars vars;
    private int initCount=5;

    void Awake()
    {
        Instance = this;
    }
    void Start () {
        vars = ManagerVars.GetManagerVars();
        Init();
	}
    private void Init()
    {
        for (int i = 0; i < initCount; i++)
        {
            InstantiateObject(vars.normalPlatformPre, normalPlatform);
        }
        for (int i = 0; i < initCount; i++)
        {
            for (int j = 0; j < vars.commonPlatformGroup.Count; j++)
            {
                InstantiateObject(vars.commonPlatformGroup[j], commonPlatformGroup);
            }
        }
    }
    private GameObject InstantiateObject(GameObject prefab,List<GameObject> addList)
    {
        GameObject go = Instantiate(prefab, transform);
        go.SetActive(false);
        addList.Add(go);
        return go;
    }
    /// <summary>
    /// 获取一个单个平台
    /// </summary>
    /// <param name="getList"></param>
    /// <returns></returns>
    public GameObject GetNormalPlatform(List<GameObject> getList)
    {
        for (int i = 0; i < getList.Count; i++)
        {
            if (getList[i].activeInHierarchy == false)
            {
                return getList[i];
            }
        }
        return InstantiateObject(vars.normalPlatformPre,getList);
    }
    /// <summary>
    /// 获取一个指定类型的组合平台
    /// </summary>
    /// <param name="getList"></param>
    /// <returns></returns>
    public GameObject GetPlatformGroup(List<GameObject> getList)
    {
        for (int i = 0; i < getList.Count; i++)
        {
            if (getList[i].activeInHierarchy == false)
            {
                return getList[i];
            }
        }
        int ran = Random.Range(0, getList.Count);
        return InstantiateObject(getList[ran], getList);
    }
    public GameObject AddToPool(GameObject go)
    {
        go.SetActive(false);
    }
}

效果

      运行发现,在ObjectPool空物体下的子物体都属于对象池中的对象,并且可以发现都是隐藏的,代表当前对象池中的对象都未使用。
在这里插入图片描述

注意

      在初始实例化对象池中的对象时,记得使用SetActive隐藏对象;在使用对象池中的对象时,记得使用SetActive显示对象。