unity对象池的使用

来源:互联网 发布:全球数据化时代txt 编辑:程序博客网 时间:2024/06/06 13:27

对象池,简单的来说,就是当你想GameObject消失时,而这个GameObject又需要经常用到时,你就不必去Destroy掉,而是隐藏掉,为了便于管理,就把这些GameObject统一放在一个“池”中。许多时候,实例化一个物体需要消耗一定的性能,不直接Destroy掉就会提高性能。


下面实现的对象池,是针对Resources.Load来设计的。

1.根据Resources下的预制物生成配置文件

using UnityEngine;using System.Collections;using System.Collections.Generic;using UnityEditor;using System.IO;//生成配置信息,供对象池使用public class PoolConfigure {    private static List<string> allFiles;    //右键菜单      [MenuItem("Assets/Build Pool Configure")]    static void Build()    {        string path = AssetDatabase.GetAssetPath(Selection.objects[0]);        if (!path.Contains("Resources"))        {            Debug.Log("请选中Resources文件夹");            return;        }        path = Application.dataPath + path;        path = path.Replace("AssetsAssets", "Assets");        Debug.Log(path);        allFiles = new List<string>();        GetAllFiles(path);        allFiles.RemoveAll((s) => { return s.Contains("meta");});        //for (int i = 0; i < allFiles.Count; i++)        //{        //    Debug.Log(allFiles[i]);        //}        //对路径进行处理,使其可以直接通过Resources.Load进行加载        for (int i = 0; i < allFiles.Count; i++)        {            allFiles[i] = allFiles[i].Replace("\\", "/");            allFiles[i] = allFiles[i].Substring(allFiles[i].IndexOf("Resources/") + 10);            allFiles[i] = allFiles[i].Replace(".prefab", "");            Debug.Log(allFiles[i]);        }        //生成配置文件        string outputPath = Application.dataPath + "/Script/ObjectPool/PoolInfo.cs";        ClassTemplate.Start(outputPath);        ClassTemplate.WriteClass("");        for (int i = 0; i < allFiles.Count; i++)        {            string name = allFiles[i].Substring(allFiles[i].LastIndexOf('/') + 1);            ClassTemplate.WriteField("string", name, "public const", "\"" + allFiles[i] + "\"");        }        ClassTemplate.End();        AssetDatabase.Refresh();    }    //获取一个根目录下的所有文件    public static void GetAllFiles(string dir)    {        string[] files = Directory.GetFiles(dir);        foreach (var item in files)        {            allFiles.Add(item);        }        string[] dirs = Directory.GetDirectories(dir);        foreach (var item in dirs)        {            GetAllFiles(item);        }    }}

using UnityEngine;using System.Collections;using System.Collections.Generic;using System.Text;using System.IO;//创建类模板(文件)//统一在语句末加上"\n"public class ClassTemplate {    private static StringBuilder builder;    private static string path;    private static string className;    private static bool useNameSpace = false;    private static string fourSpace = "    ";    public static void Start(string savaPath)    {        builder = new StringBuilder();        path = savaPath;        className = savaPath.Substring(savaPath.LastIndexOf("/") + 1);        className = className.Substring(0, className.IndexOf('.'));        useNameSpace = false;        //Debug.Log("className:" + className);    }    public static void End()    {        if (useNameSpace) Write(fourSpace + "}\n}");        else Write("\n}");        File.WriteAllText(path, builder.ToString());    }    public static void WriteUsing(string s)    {        Write("using " + s + ";" + "\n");    }    public static void WriteNameSpace(string s)    {        useNameSpace = true;        Write("\nnamespace " + s + "\n{\n");    }    public static void WriteClass(string parentName)    {        if (!useNameSpace) Write("\n");        WriteZeroOrOneInterval();        Write("public class " + className);        if (!string.IsNullOrEmpty(parentName)) Write(" : " + parentName + " ");        else Write(" ");        WriteZeroOrOneInterval();        Write("{\n\n");    }    //prefix即变量修饰符,如public static     public static void WriteField(string type, string name, string prefix = "public", string value = "")    {        WriteOneOrTwoInterval();        if (string.IsNullOrEmpty(value)) Write(prefix + " " + type + " " + name + ";\n");        else Write(prefix + " " + type + " " + name + " = " + value + ";\n");    }    /// <summary>    /// methodInfo:如public static void Init()    /// </summary>    /// <param name="methodInfo"></param>    public static void StartMethod(string methodInfo)    {        Write("\n");        WriteOneOrTwoInterval();        Write(methodInfo);        Write("\n");        WriteOneOrTwoInterval();        Write("{\n");    }    public static void MethodProcess(string s)    {        WriteTwoOrThreeInterval();        Write(s + "\n");    }    public static void EndMethod()    {        WriteOneOrTwoInterval();        Write("}\n");    }    public static void WriteConstructionRead(List<string> name, List<string> readMethod)    {        Write("\n");        WriteOneOrTwoInterval();        Write("public " + className + "()\n");        WriteOneOrTwoInterval();        Write("{\n");        for (int i = 0; i < name.Count; i++)        {            WriteTwoOrThreeInterval();            Write(name[i] + " = " + readMethod[i] + "();\n");        }        WriteOneOrTwoInterval();        Write("}\n\n");    }    public static void WriteConstructionCopy(List<string> name, List<string> readMethod)    {        Write("\n");        WriteOneOrTwoInterval();        Write("public " + className + "(" + className + " a" + ")\n");        WriteOneOrTwoInterval();        Write("{\n");        for (int i = 0; i < name.Count; i++)        {            if (readMethod[i].Contains("List"))            {                string type = readMethod[i].Substring(4, readMethod[i].Length - 8).ToLower();                //Debug.Log(type);                WriteTwoOrThreeInterval();                Write(name[i] + " = new " + type + "[a." + name[i] + ".Length];\n");                WriteTwoOrThreeInterval();                Write("Array.Copy(a." + name[i] + ", " + name[i] + ", " + "a." + name[i] + ".Length);\n");            }            else if (readMethod[i].Contains("Dict"))            {                string type = readMethod[i].Substring(4, readMethod[i].Length - 8).ToLower();                //Debug.Log(type);                WriteTwoOrThreeInterval();                Write(name[i] + " = " + "new Dictionary<string, " + type + ">(a." + name[i] + ");\n");            }            else            {                WriteTwoOrThreeInterval();                Write(name[i] + " = " + "a." + name[i] + ";\n");            }        }        WriteOneOrTwoInterval();        Write("}\n\n");    }    public static string GetClassName()    {        return className;    }    public static void Write(string s)    {        builder.Append(s);    }    private static void WriteZeroOrOneInterval()    {        if (useNameSpace) Write(fourSpace);    }    private static void WriteOneOrTwoInterval()    {        if (useNameSpace) Write(fourSpace + fourSpace);        else Write(fourSpace);    }    private static void WriteTwoOrThreeInterval()    {        if (useNameSpace) Write(fourSpace + fourSpace + fourSpace);        else Write(fourSpace + fourSpace);    }}

那么对于下图:


生成的配置文件如下:

public class PoolInfo {    public const string Cube = "Character/Enemy/Cube";    public const string Sphere = "Character/Hero/Sphere";    public const string Capsule = "Effect/Capsule";}



2.对象池

using UnityEngine;using System.Collections;using System.Collections.Generic;public class PoolManager : CSharpSingletion<PoolManager> {    //path -- go    public Dictionary<string, List<GameObject>> dic = new Dictionary<string, List<GameObject>>();    //把对象放到对象池中    public void SetPoolObject(string path, GameObject go)    {        if (!dic.ContainsKey(path))        {            List<GameObject> list = new List<GameObject>();            list.Add(go);            dic.Add(path, list);        }        else        {            dic[path].Add(go);        }        go.SetActive(false);    }    //从对象池中取出对象    //isNewGo为true,表示返回新的go,否则表示返回缓存池中的go    public GameObject GetPoolObject(string path, bool isNewGo = false)    {        //Resources.Load: 重复Load同样的资源只会指向同一段内存,不会增加开销        if (isNewGo)        {            GameObject go = MonoBehaviour.Instantiate(Resources.Load<GameObject>(path));            return go;        }        if (!dic.ContainsKey(path))        {            GameObject go = MonoBehaviour.Instantiate(Resources.Load<GameObject>(path));            return go;        }        else        {            if (dic[path].Count > 0)//还未取完            {                GameObject go = dic[path][0];                go.SetActive(true);                dic[path].Remove(go);                return go;            }            else//已经取完            {                GameObject go = MonoBehaviour.Instantiate(Resources.Load<GameObject>(path));                return go;            }        }    }    public void Cache(string path, int amount = 1, bool isNewGo = true)    {        for (int i = 0; i < amount; i++)        {            GameObject go = GetPoolObject(path, isNewGo);            SetPoolObject(path, go);        }    }}

3.测试

using UnityEngine;using System.Collections;public class PoolTest : MonoBehaviour {    void Start ()     {        //1        //PoolManager.Instance.Cache(PoolInfo.Cube, 5000, true);        //Profiler.BeginSample("PoolTest");        //for (int i = 0; i < 5000; i++)        //{        //    PoolManager.Instance.GetPoolObject(PoolInfo.Cube);        //}        //Profiler.EndSample();        //2        Profiler.BeginSample("PoolTest");        for (int i = 0; i < 5000; i++)        {            Instantiate(Resources.Load<GameObject>(PoolInfo.Cube));        }        Profiler.EndSample();    }}

原创粉丝点击