美文网首页unity
对象池模拟子弹弹夹

对象池模拟子弹弹夹

作者: S_H_C | 来源:发表于2017-03-18 00:09 被阅读0次

为了优化项目资源,我们在场景中最好使用对象池来储存子弹这种需要不断实例出来的对象;因为像子弹这种对象,如果实例出来,用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

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

相关文章

  • 对象池模拟子弹弹夹

    为了优化项目资源,我们在场景中最好使用对象池来储存子弹这种需要不断实例出来的对象;因为像子弹这种对象,如果实例出来...

  • SCUM狙击枪故障图解

    M1 坏弹 射击时子弹卡在了枪管中,此故障由子弹耐久低引起 卡壳 弹夹没有正确弹出,卡在弹出器中,此故障由弹夹耐久...

  • python应用:老王开枪

    人类 属性姓名 血量 持有的枪 方法安子弹 安弹夹 拿枪(持有抢) 开枪 子弹类 属性杀伤力 方法伤害敌人(让敌人...

  • burpsuite中intruder标签内attack type

    首先假设我们有一挺机枪一杆步枪,子弹通用。前两种只涉及弹夹,后两种机枪用弹鼓,步枪用弹夹,表示多个payload ...

  • 简单的一个小游戏

    老王开枪 1. 人类 属性 姓名 血量 持有的枪 方法 安子弹 安弹夹 拿枪(持有抢) 2. 子弹类 属性 杀伤力...

  • 反恐精英

    目录 基本信息 参考代码 1. 基本信息 人类 属性姓名血量持有的枪 方法安子弹安弹夹拿枪(持有抢)开枪 子弹类 ...

  • 腹肌很难练么?那是你没练过子弹肌!

    子弹肌是下胸两侧 在肋骨的部位 因为视觉上看着像弹夹 故得名为子弹肌 子弹肌学名为前锯肌 又名鲨鱼线 在健身圈 对...

  • 利用对象池发射子弹(自创)

    利用对象池发射子弹(自创) 一:创建一个新的场景,随便创建一个物体,在这个物体上添加控制代码:控制这个物体前后左右...

  • SCUM手枪故障图解

    卡壳 弹壳卡在出弹口中,此故障由枪械耐久低引起 卡弹 子弹卡在弹夹与击发装置之间,此故障由子弹耐久低引起 哑弹 无...

  • 子弹

    压进枪膛,扣动扳机,被顶出枪口飞速击中物体的瞬间子弹才叫子弹。其余的时间在仓库里沉睡,弹夹上待命车载船运,被携带着...

网友评论

    本文标题:对象池模拟子弹弹夹

    本文链接:https://www.haomeiwen.com/subject/zevynttx.html