原创

题外话:今天遇到一个坑爹的事,新来了一个WIN10的电脑,但是Unity装完,任何IDE工具打开都无法识别命名空间,原来WIN10本来不带NET2.0,需要去控制面板--程序和功能---添加.net3.5

单例模式

初学者很容易搞晕,为啥有2种写法,这里顺带着写一下,不是本章的要点。

首先,是继承自MonoBehaviour的单例,需要使用U3D组件和功能可以用这种单例。理解U3D本身单例写法的机制就知道为啥要这么写了,第一个挂载脚本的对象,就是该单例,后面再怎么重复挂载是无效的。因为挂载的时候就实例化该类了。

需要说明的是,不要写在构造函数里,继承自MonoBehaviour的脚本,构造函数也会执行,但是它的执行时间无法确定,有可能再Awake之前,有可能在Start之后,容易出现BUG。

public static ObjectPool instance;   //单例

    //U3D的单例机制,是第一个挂载脚本的对象,就是该单例,后面再怎么重复挂载是无效的。因为挂载的时候就实例化instance了。
    void Awake()
    {
        instance = this;
    }

其次,不继承MonoBehaviour的单例,全局单例吧,什么场景都能用,不能挂载到U3D物体上。

private static ObjectPool instance;   //单例

    public ObjectPool GetInstance()
    {
        if (instance == null) 
        {
            instance = new ObjectPool();
        }

        return instance;
    }

对象池

思路:重复创建大量物理和销毁物体,会大量消耗资源,比如:子弹,金币等等,对象池的作用就是创建完了不销毁,只能把它隐藏存入对象池,用一个列表保存数据,需要用的时候再取出来,同时激活它,并且移除列表,这样列表中剩下的就是隐藏可以使用的对象。因为可能有很多物体需要用对象池,所以把个物体的LIST列表存入一个字典。如果对象池中有100个对象,创建90个都是在对象池中激活,只有创建110,才会再新生成10个。

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



//U3D单例对象池
public  class ObjectPool : MonoBehaviour
{
    public static ObjectPool instance;   //单例

    public GameObject[] prefabObjects;   //prefab数组

    private Dictionary<string, List<GameObject>> pool = new Dictionary<string, List<GameObject>>();  //对象池字典


    //U3D的单例机制,是第一个挂载脚本的对象,就是该单例,后面再怎么重复挂载是无效的。因为挂载的时候就实例化instance了。
    void Awake()
    {
        instance = this; 
    }


    //从池中获取      //正式项目最好用一个静态类来保存名字,防止出错
    public GameObject GetOut(string GameObjectName, Vector3 vector3)
    {
        GameObject gameObject;   //返回的gameObject

        //如果池中有
        if (pool.ContainsKey(GameObjectName) && pool[GameObjectName].Count > 0)
        {
            //取池里的用
            gameObject = pool[GameObjectName][0];
            gameObject.SetActive(true);
            gameObject.transform.position = vector3;

            //取完移除
            pool[GameObjectName].RemoveAt(0);
        }
       //如果没有
        else
        {
            GameObject prefabObject = null;

            //要生成的prefabObject   prefab数组中的物体名字要和传入的字符串一致  
            for (int i = 0; i < prefabObjects.Length; i++)
            {
                if (prefabObjects[i].name == GameObjectName)
                {
                    prefabObject = prefabObjects[i];
                }
            }

            //直接创建
            gameObject = (GameObject)GameObject.Instantiate(prefabObject, vector3, Quaternion.identity);
        }
       
        return gameObject;
    }

    //存入对象池
    public void SetIn(string GameObjectName,GameObject gameObject) 
    {
      //池中没有
      if (!pool.ContainsKey(GameObjectName))
      {   //新建池List
          pool.Add(GameObjectName, new List<GameObject>());
      }
      
      //存入池
      gameObject.SetActive(false);
      pool[GameObjectName].Add(gameObject);

      Debug.Log(pool[GameObjectName].Count);

    }

    //销毁对象池
    public void DestroyPool(string GameObjectName)
    {
        if (pool.ContainsKey(GameObjectName))
        {   //删除对象
            for (int i = 0; i< pool[GameObjectName].Count; i++) 
            {
                Destroy(pool[GameObjectName][i]);
            }

            //移除列表
            pool.Remove(GameObjectName);
        }
    }
   
}

注意:使用的时候, 从对象池获取,什么地方都可以用,存入对象池这个方法最好在物体本身上,比如子弹上挂着一个,自己就把自身存入对象池。实际使用就用PoolManager  插件好了,据说很好用。