unity对象池系统

当游戏场景中出现大量的可重复利用的物体时,通过Destory来销毁再创建会触发不必要的GC回收机制,浪费性能,我们可以利用unity自带的对象池系统,从而节约性能来得到同样的效果。

为了使用这个对象池系统,我写了一个瞬间产生多枚子弹的测试脚本如下:

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

public class UnlimitedSwordSystem : MonoBehaviour
{
     public GameObject projiectilePrefab;

     public Rigidbody2D rigidbody2d;

     private int projectileNum=20;

     private Vector2 CreatPosition;

     GameObject projectile;
   
    private Coroutine launch3times;

    
    public void CreatProjectiles()
    {
        if(transform.GetComponent<SkillTrigger>().available==false)return;
        if(launch3times!=null)
        {
            StopCoroutine(launch3times);
        }
        launch3times=StartCoroutine("CreatProjectile");   
    }

    private IEnumerator CreatProjectile()
    {
        int k=2;
        while(k>=0)
        {
            k--;
            for(int i=0;i<projectileNum;i++)
        {
            CreatPosition=Random.insideUnitCircle*1.5f;

            projectile = Instantiate(projiectilePrefab, 
            CreatPosition+rigidbody2d.position,
            Quaternion.identity);
        
            launch(CreatPosition);
        }     
            yield return new WaitForSeconds(0.3f);
        }
    }

    
    void launch(Vector2 p)
    {
        projectile.GetComponent<Projectile>().Launch(p.normalized,500);
    }
}

这个脚本可以在瞬间分三次产生共60枚子弹,运行游戏,打开Profiler,可以看到GC Allocated In Frame有明显波动

 接下来使用对象池来优化

创建一个脚本pool,使用unity的对象池需引入UnityEngine.Pool;

从对象池中取出和放入对应着Get和Release这两个函数:

 

为了实现对象池,必须修改一下子弹的脚本,让子弹停留2秒后回收入对象池而非摧毁

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

public class Projectile : MonoBehaviour
{
    System.Action<Projectile>dea;
    public void SetDea(System.Action<Projectile> dea)
    {
        this.dea=dea;
    }
    private Rigidbody2D rigidbody2d;
    public int DamageValue=1;

    void Awake()    //在Start之前调用
    {
        rigidbody2d = GetComponent<Rigidbody2D>();
    }

    public void Launch(Vector2 direction,float force)
    {
        rigidbody2d.AddForce(direction*force);
    }


    float lifeTime=2;
    bool IsActive=true;
    private void Update()
    {
        // if (transform.position.magnitude > 250f)
        // {
        //     Destroy(gameObject);
        // }
        if(!IsActive)return;
        
        lifeTime-=Time.deltaTime;
        if(lifeTime<=0)
        {
            lifeTime=2;
            dea.Invoke(this);

        }
    }

创建对象池所需的参数:

 createFunc:

创建一个对象,值得注意的是当Get不能得到一个对像时,会调用这个方法创建对象。

actionOnGet:

调出对象池对象时要执行的功能

actionOnRelease:

回收对象到对象池时要执行的功能

actionOnDestroy:

摧毁对象池中对象要执行的操作

collectionCheck:

是否开启回收检测功能

defaultCapacity:

对象池的默认容量,和链表或队列类似,当容量不足时会自动扩容。

maxSize:

限制对象池的最大容量,防止对象池的无限扩张,如果maxSize已满,当调用Release函数时,这个Release函数将会忽略。

对象池:

public class Pool : MonoBehaviour
{
    [SerializeField] Projectile prefab;
    [SerializeField] int defaultSize=100;
    [SerializeField] int maxSize=500;
    ObjectPool<Projectile>pool;

    [SerializeField] Rigidbody2D rigidbody2d;
    private void Awake() {
        pool=new ObjectPool<Projectile>(OnCreatPoolItem,OnGetPoolItem,OnReleasePoolItem,
        OnDestoryPoolItem,true,defaultSize,maxSize);
    }

    private void Update() {
        var p=pool.Get();
        p.transform.position=rigidbody2d.position+ Random.insideUnitCircle*2.5f;
    }

    private void OnDestoryPoolItem(Projectile projectile)
    {
        Destroy(projectile.gameObject);
    }

    private void OnReleasePoolItem(Projectile projectile)
    {
        projectile.gameObject.SetActive(false);
    }

    private void OnGetPoolItem(Projectile projectile)
    {
        projectile.gameObject.SetActive(true);
    }

    private Projectile OnCreatPoolItem()
    {
        var projectile=Instantiate(prefab,transform);
        projectile.SetDea(delegate{pool.Release(projectile);});

        return projectile;
    }
}

运行游戏可以看到,GC Allocated In Frame在对象池稳定运行后为0

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值