多语言展示
当前在线:1753今日阅读:195今日分享:14

Unity 实用技巧 之 超实用对象池模板的使用

Unity 实用技巧 之 超实用对象池模板的使用。在游戏中合理的使用对象池,能有效的节约性能的开销,是游戏开发中常用的一种资源使用方式,本节介绍如何通过使用主池子管理子池子的方式,实现对象池的管理,具体如下
工具/原料
1

Unity

2

对象池ObjectPoolController

3

单例Singleton

一、基本概念
1

对象池:对象池意义是将游戏中反复创建销毁的对象进行多次利用,从而避免大量对象的销毁与创建而造成CPU的负担

2

单例模式:是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例

二、实用技巧 之 超实用对象池模板的使用
1

打开Unity,新建一个空工程,然后Unity界面如下图

2

在工程中新建两个文件夹“Resources”、“Scripts”、在“Scripts”下添加两个脚本,然后打开编辑器编辑脚本代码,具体如下图

3

在打开的“MonoSingleton”脚本上进行代码编辑,具体的脚本知识点可参见下面的经验连接学习,这是不是讲解重点,具体代码及代码说明如下图

4

“MonoSingleton”具体脚本内容如下:using UnityEngine;public class MonoSingleton : MonoBehaviour where T : MonoSingleton{    private static T instance;    public static T Instance {        get {            if (instance == null) {                GameObject obj = new GameObject(typeof(T).Name);                instance = obj.AddComponent();            }            return instance;        }    }    protected virtual void Awake() {        instance = this as T;    }}

5

在打开的“IReusable”脚本上进行代码编辑,写一个接口,并且写两个接口函数Spawn、UnSpawn,具体代码及代码说明如下图

6

“IReusable”具体脚本内容如下:public interface IReusable{    void Spawn();    void UnSpawn();}

7

在打开的“ReusableObject ”脚本上进行代码编辑,继承接口,并且抽象化两个接口函数Spawn、UnSpawn,目的让可重用对象继承去实现,具体代码及代码说明如下图

8

“ReusableObject ”具体脚本内容如下:using UnityEngine;public abstract class ReusableObject : MonoBehaviour, IReusable{    public abstract void Spawn();    public abstract void UnSpawn();}

9

在打开的“SubPool ”脚本上进行代码编辑,首先设置子池子列表,然后实现子池子对象的Spawn。UnSpawn,以及UnSpawnAllObject和判断对象是否在子池子列表的函数,具体代码及代码说明如下图

10

“SubPool ”具体脚本内容如下:using System.Collections.Generic;using UnityEngine;public class SubPool {    List subPool = new List();    GameObject m_Pref;    public string Name {        get {            return m_Pref.name;        }    }    public SubPool(GameObject pref) {        m_Pref = pref;    }    public GameObject Spawn() {        GameObject obj = null;        foreach (GameObject o in subPool) {            if (o.activeSelf == false) {                obj = o;            }        }        if (obj == null) {  //第一次和池子中没有的时候            obj = GameObject.Instantiate(m_Pref);            subPool.Add(obj);        }        obj.SetActive(true);        IReusable ir = obj.GetComponent();        if (ir != null) {            ir.Spawn();        }        return obj;    }    public void UnSpawn(GameObject obj) {        if (subPool.Contains(obj)) {            IReusable ir = obj.GetComponent();            if (ir != null) {                ir.UnSpawn();            }            obj.SetActive(false);        }    }    public void UnSpawnAllObject() {        foreach (GameObject o in subPool) {            if (o.activeSelf == true) {                UnSpawn(o);            }        }    }    public bool ContainObjectInSubPool(GameObject obj) {        return subPool.Contains(obj);    }}

11

在打开的“ObjectPoolController ”(也是所谓的主池子)脚本上进行代码编辑,首先设置主池子字典管理子池子,然后实现主池子的Spawn。UnSpawn,以及UnSpawnAllObject和把子池子注册添加进主池子的函数,具体代码及代码说明如下图

12

“ObjectPoolController ”具体脚本内容如下:using System.Collections.Generic;using UnityEngine;public class ObjectPoolController : MonoSingleton {    private Dictionary Pools = new Dictionary();    public GameObject Spawn(string objName) {        if (Pools.ContainsKey(objName) == false) {            RegisterSubPool(objName);        }        SubPool subPool = Pools[objName];        return subPool.Spawn();    }    private void RegisterSubPool(string objName) {        GameObject obj = Resources.Load(objName);        SubPool subPool = new SubPool(obj);        Pools.Add(objName, subPool);    }    public void UnSpawn(GameObject obj) {        foreach (SubPool subPool in Pools.Values) {            if (subPool.ContainObjectInSubPool(obj)) {                subPool.UnSpawn(obj);                break;            }        }    }    public void UnSpawnAllObject() {        foreach (SubPool subPool in Pools.Values) {            subPool.UnSpawnAllObject();        }    }}

13

在打开的“BulletReusable ”脚本上进行代码编辑,首先继承Reusableobject,来表明子弹是可重用的,接下来实现继承的Spawn和UNSpawn函数,以及一个眼石销毁函数,具体代码及代码说明如下图

14

“BulletReusable ”具体脚本内容如下:using System.Collections;using System.Collections.Generic;using UnityEngine;public class BulletReusable : ReusableObject {    public override void Spawn()    {        print("生成Bullet");        Invoke("DelayDestroy", 3.0f);    }    public override void UnSpawn()    {        print("销毁Bullet");    }    private void DelayDestroy()    {        ObjectPoolController.Instance.UnSpawn(gameObject);    }}

15

在打开的“Test ”脚本上进行代码编辑,通过在Update函数中按下“B”键,生成或调用释放对象池中的Bullet对象,来检验对象池的使用,具体代码及代码说明如下图

16

“Test ”具体脚本内容如下:using System.Collections;using System.Collections.Generic;using UnityEngine;public class Test : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () {        if (Input.GetKeyDown(KeyCode.B)) {            ObjectPoolController.Instance.Spawn("Bullet");        } }}

17

脚本编译正确后,回到Unity界面,工程中的脚本目录如图,在场景中新建一个“Sphere”,并命名为“Bullet”,然后把脚本“BulletReusable”赋给“Bullet”,最后拖拽到Resources目录下作为预制体,删除场景中的“Bullet”,具体如下图

18

在场景中新建一个“GameObject”,然后把脚本“Test”赋给“GameObject”,具体如下图

19

运行场景,分别按下“B”键,即可看到场景中生成了Bullet(Clone),几秒后隐藏,控制台console上打印也与预期相符,具体如下图

20

到此,《Unity 实用技巧 之 超实用对象池模板的使用》讲解结束,谢谢

注意事项
1

对象池模板与ResourcesTool工具结合使用,效果更好

2

若帮到您,还请帮忙投票以帮助到更多的人;若有疑问,请留言

推荐信息