对象池模拟子弹弹夹

为了优化项目资源,我们在场景中最好使用对象池来储存子弹这种需要不断实例出来的对象;因为像子弹这种对象,如果实例出来,用Destroy来销毁后它其实还是占用内存资源的,这些被占用的内存在下下个场景加载完成后才会清空,所以我们要把这些能够重复利用的对象放到对象池中,当使用时把它的SetActive设为true,不使用时设为false,这样就避免不断地重复实例和销毁对象。

对象池的特点:

1.节省对象重复创建和初始化所耗费的时间
2.简化对象获取和使用的过程
3.优化内存资源,提高系统性能
下面就来用一个模拟子弹弹夹来简单介绍对象池的使用。
先创建一个新场景,里面创建一个地面Plane和一个方块Cube,用Cube来模拟枪(虽然很low,就将就着用,这不是重点= =),如图:

Paste_Image.png

然后再创建一个子弹(其实就是一个Sphere)预设体,如图:

Paste_Image.png

(记得改一下Sphere的Scale值为0.2)
这个时候我们就可以先写一个对象池的脚本:

public class GameObjectPool : MonoBehaviour
{
    const int number = 10;//子弹弹夹的容量
    bool isin = true;//用来判断是否实例子弹对象
    int n;//用来记录实例出子弹对象的个数

    //集合里面的元素,相当于对象池里面的对象,这里的集合可看作为对象池。
    static List<GameObject> pools = new List<GameObject>();
    //再声明一个集合,用来回收发射出去的子弹对象
    List<GameObject> pb = new List<GameObject>();  

    //首先创建一个单例
    private  GameObjectPool() { }
    private static GameObjectPool instance;    
    public static GameObjectPool GetInstance(GameObject name)//此处的Gameobject name就是需要放入对象池的对象--子弹
    {
        if (instance == null)
        {
            print("实例池子");
            //动态的生成一个名为“GameObjectPool”的对象并将单例脚本附加上去
            instance = new GameObject("GameObjectPool").AddComponent<GameObjectPool>();
            for (int i = 0; i < number; i++)//先往对象池中放入十发子弹
            {
                name.SetActive(false);
                pools.Add(name);
            }
        }
        return instance;
    }
    //从对象池中取对象
    public GameObject MyInstantiate()
    {
        if (pools.Count == 0)//如果十发子弹打完
        {
            print("没子弹了:" + pools.Count);
            return null;
        }
        else
        {
           // print(pools[0].name);
            //取出对象池里面的第一个元素
            GameObject obj= pools[0];
            if (isin)//判断是否已经实例了十发子弹
            {
                //obj = pools[0];
                Instantiate(obj);//实例出子弹
                n++;//计数加加
                if (n == number)
                {
                    isin = false;
                }
            }
            //将对象设置为激活状态
            obj.SetActive(true);
            //将被取出的元素,从对象池中移除
            pools.Remove(obj);
            return obj;
        }       
        }
   //回收子弹的方法
    public void MyDisable(GameObject name)
    {
        //将传进来的对象隐藏(处于非激活状态)
        name.SetActive(false);
        //回收子弹添加到pb集合中
        pb.Add(name);
    }
    public void ResetBullet()//换弹夹的方法
    {
        if (pb.Count != 0)//判断回收子弹的集合是否是空
        {
            print("pb不是空");
            for (int i = 0; i < pb.Count; i++)
            {
                pools.Add(pb[i]);      //把回收的子弹重新加到弹夹中去         
            }            
            pb.Clear();
        }
    }
}

这个脚本不需要挂到任何物体上;
然后我们需要给预设体子弹写一个脚本:

public class Bullet : MonoBehaviour {   
    void OnEnable()
    {                      
        //开启协程
        StartCoroutine(DelayDisable(1f));
    }


    void Update()
    {
        //子弹自动向前运动
        transform.Translate(Vector3.forward * Time.deltaTime * 50);
    }
    void OnDisable()
    {
        Debug.Log("I'm over");
    }
    //子弹消失的方法
    IEnumerator DelayDisable(float time)
    {
        //等待一秒
        yield return new WaitForSeconds(time);
        //调用单例中向集合pb里面回收子弹对象的方法
        GameObjectPool.GetInstance(gameObject).MyDisable(gameObject);
    }
}

如图

Paste_Image.png

最后我们给Cube加一个脚本,用来控制它发射子弹

public class GameManerge : MonoBehaviour {
    //创建子弹的预设体
    public GameObject mBulletPrefab;
    void Update()
    {
        //如果按下鼠标左键,发射子弹
        if (Input.GetMouseButtonDown(0))
        {
            //调用单例脚本里面的从对象池中取对象的方法
            GameObject go = GameObjectPool.GetInstance(mBulletPrefab).MyInstantiate();
            if(go!=null)
            {
                go.transform.position = transform.position;    //设置子弹生成的位置是Cube的位置           
            }            
        }
        //按下鼠标右键,换弹夹
        if (Input.GetMouseButtonDown(1))
        {
            print("换子弹:");
            GameObjectPool.GetInstance(mBulletPrefab).ResetBullet();
        }
    }  
}

如图,


Paste_Image.png

这样就运用对象池做好了一个弹夹效果,场景有点丑但达到的效果还是不错的^_

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容