分享

【关于unity对象池的用法(话痨版)(c#)】

 阿修罗之狮猿授 2016-06-13
这个是我的学习笔记,是我感觉挺重要的东西,记得我自己都能看懂了,耐住话痨你们肯定能看懂,主要在于理解,减耗是一种信仰。。。。。。。。
对于这个也只是学个思想,代码不要学我,新手,不专业,太啰嗦,我以后会努力规范代码的;

题外:我的微博 “ 黑石铸造厂厂长 ”,想要个大 v粉丝不够啊 ,大家互粉一下呗。。。。。。。。。

当游戏中需要发射子弹(gameobject)等操作的时候,不停的Instantiate和destroy就会很耗性能,如果又是多人游戏,那多人同时Instantiate和destroy子弹,配置不高的设备可能会炸,同时这种大量的创建和销毁时不必要的。
这里可以用到类似于ios编程中uitableview中对cell的类似于循环利用的机制,这里面叫对象池,就是说建立子弹对象并使用完后不进行销毁,而是用SetActive方法来改变其激活状态,等再次需要使用时再进行激活


图中红圈部分就是创建进对象池的对象,当足够多后就能实现循环利用而不是无限增加。


我们要创建一个字典,字典中与key值对应的是数组(arraylist)(例:key为手枪子弹  对应arraylist[手枪子弹,手枪子弹,手枪子弹。。。。。。 ])。
arraylist就是用来装重复利用的子弹gameobjet的。

对象池个人感觉就是一种对gameobject的利用机制,可能还可以用很多方法实现。

下面就直接上代码,写了三个脚本:
1.pool脚本,注释已经详细到话痨了:
[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//对象池
//节省性能的方法,important,
public class pool : MonoBehaviour {
    //实例化自己
    public static pool instance;
    //创建一个字典dic 键为子弹或敌人种类 值为数组 存放多个同样的子弹或敌人
    public static Dictionary<string, ArrayList> dic = new Dictionary<string, ArrayList>();
// Use this for initialization
void Start () {
     //使自身可被调用
        instance = this;
}
    //方法(函数):调用后会返回一个属于需要的种类(dic的key值(实际为key + "(Clone)"))的 敌人或子弹(即一个gameobject)。
    //key是子弹或敌人预设体的名字,预设体放在Resources中
    //方法名get(可以自定义) 返回值为 参数为(obj名(子弹 敌人种类 dic的key),激活位置,激活角度)
    public static GameObject Get(string key, Vector3 position, Quaternion rotation) {
        //输出预设体名(这个没用 就是输出来看看 就是NSLog)
        Debug.Log(key);
        //创建返回值对象
        GameObject go;
        //拼接制作dic的key名,因为instantiate出的gameobject都会自动命名为gameobject(Clone),这里是为了通下面return方法里给key的命名匹配
        string GameObjectName = key + "(Clone)";
        //如果字典里有gameobjectname这个key 并且key对应的数组不为空(有该种类子弹,且该种类子弹中有《已经创建过的》(未激活)的子弹gameobject)
        if (dic.ContainsKey(GameObjectName) && dic[GameObjectName].Count > 0)
        {
            //从gameobjectname这个key位置取出数组
            ArrayList list = dic[GameObjectName];
            //取出一号位的子弹
            go = (GameObject)list[0];
            //从列表中去除这个子弹(拿出来用)
            list.RemoveAt(0);
            //将子弹gameobject激活
            go.SetActive(true);//使用时激活
            //参数赋值于子弹
            go.transform.position = position;
            //参数赋值于子弹
            go.transform.rotation = rotation;
        }
            //如果没有
        else {
            //
            Debug.Log("chi"+key);
            //在给定位置创建一个resources中名为给定key的预设体的gameobject
            go = Instantiate(Resources.Load(key), position, rotation) as GameObject;
        }
        //返回创建的东西
        return go;
         
    }
    //函数(方法) 名return(可自定义) 参数是需要取消激活的对象g
    //将需要取消激活的对象取消激活
    public static GameObject Return(GameObject g) {
        //获取gameobject的名字,会是一个在上面get方法里创建的(预设体的)gameobject,名字会是gameobject(Clone);
        string key = g.name;
        //如果字典里有这个key
        if (dic.ContainsKey(key))
        {   //就在这个key所对应的数组中加入这个g  (这个g就是已经用完的子弹,放到这个数组里的gameobjet都是不销毁只是取消激活等待再次利用的gameobject)
            dic[key].Add(g);
        }
            //如果没有这个key
        else {
            //建立一个这个key的arraylist 并把g加进去
            dic[key] = new ArrayList() { g };
        }
        //不销毁而是取消激活
        g.SetActive(false);
        //返回g
        return g;
    }
// Update is called once per frame
void Update () {
    
}
}


====================================================================

2.子弹创建(子弹创建方法其实在pool中(是创建或激活) 就是这里调用一下 给参数 然后给子弹一个动力)脚本



[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using System.Collections;
//这个脚本挂到任意一个geamobject上 我挂在camera上
public class creatzidan : MonoBehaviour {
    //拖入子弹预设体
    public GameObject zidan;
    //拖入子弹开始位置,给一个空物体位置,然后拖个空物体进来
    public Transform startPlace;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
        //获取空格键输入 (发射键)
        if (Input.GetKeyDown(KeyCode.Space)) {
            //调用pool的get方法创建一个子弹
            GameObject AZiDan = pool.Get(zidan.name, startPlace.position, Quaternion.identity);
            //给子弹刚体一个力(发射)
            AZiDan.GetComponent<Rigidbody>().AddForce(Vector3.forward * 30, ForceMode.Impulse);
        }
}
}



====================================================================
3.子弹自动“销毁”脚本 (同样是调用了pool中的方法 (其实并不是销毁 是取消激活) )

[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using System.Collections;
public class desttoryy : MonoBehaviour {
// Use this for initialization
void Start () {
}
    //这个脚本挂到子弹上,让子弹在激活后n秒自动“销毁”(进入不激活状态)
    //创建延时操作destoryy()
    IEnumerator destoryy() {
        //延时n秒
        yield return new WaitForSeconds(3f);
       //调用取消激活方法取消激活自身
        pool.Return(this.transform.gameObject);
    }
// Update is called once per frame
void Update () {
   //执行延时操作
        StartCoroutine(destoryy());
}
}



====================================================================

最后啰嗦一句:根本原理就是:打一颗 “5mm子弹” 就创建一个gameobject,这 “5mm颗子 弹” 需要销毁的时候不销毁它,把它的激活状态变为false,然后把它存入 “5mm子弹” 数组中,当你再打出一颗“5mm子弹”的时候,不需要创建一颗新的“5mm子弹”,只需要把刚才那颗未激活“5mm子弹”从ArrayList里拿出来激活一下,然后删除掉ArrayList里关于这个gameobje的数据就行了,然后这颗子弹再销毁。。。。如此往复,子弹多了也同理。






    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多