You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity对象池问题:Get()函数持续实例化新对象求助

Unity对象池Get()持续实例化新对象问题排查

问题现象

使用Unity内置ObjectPool实现对象池时,调用Get()函数会持续实例化新对象,无报错,但对象池未复用已有对象。

相关代码

生成器类(OPool)

public class OPool : MonoBehaviour
{
    public Bullet bulletPrefab;
    public UnityEngine.Pool.ObjectPool<Bullet> _bulletPool;
    public static OPool _OPool;
    public void Start()
    {
        _bulletPool = new UnityEngine.Pool.ObjectPool<Bullet>(createFunc: InstantiatePoolBullet, actionOnGet: GetBulletFromPool,
            actionOnRelease: ReturnBulletToPool,DestroyBullet, true, 15,20);
    }

    public void Update()
    {   
        transform.position = transform.parent.position + new Vector3(0f, 3.5f, 2.5f);
    }

    public Bullet InstantiatePoolBullet()
    {
        Bullet bullet = Instantiate(bulletPrefab, transform);
        bullet.SetPool(_bulletPool);
        return bullet;
    }

    public void GetBulletFromPool(Bullet bullet)
    {
             bullet.transform.position = transform.position;
             bullet.transform.rotation = transform.rotation;             
             bullet.gameObject.SetActive(true);      
    }

    public void ReturnBulletToPool(Bullet bullet)
    {
        bullet.gameObject.SetActive(false);
    }
    public void DestroyBullet(Bullet bullet)
    {
        Destroy(bullet.gameObject);
    }
 
}

子弹类(Bullet)

public class Bullet : MonoBehaviour
{
    public float speed;
    private ObjectPool<Bullet> _pool;
    public float _deadtime = 0.7f;
    private float _currentTime;
    private Rigidbody rb;
    public int damage;
    public static Bullet bullet;
    private void Awake()
    {
        rb = GetComponent<Rigidbody>();
        _currentTime = _deadtime;
    }

    private void Start()
    {
        bullet = this;
        ApplyVelocity();
    }

    private void Update()
    {
        if (_currentTime > 0)
        {
            _currentTime -= Time.deltaTime;
        }
        else
        {
            DestroyBullet();
        }
    }

    public void SetPool(ObjectPool<Bullet> pool)
    {
        _pool = pool;
    }

    private void OnEnable()
    {
        ApplyVelocity();
        _currentTime = _deadtime;
    }
    
    private void ApplyVelocity()
    {
        rb.velocity = speed * transform.forward;
    }

    private void DestroyBullet()
    {
        if (_pool != null)
        {
            _pool.Release(this);
        }
        else
        {
            Destroy(gameObject);
        }
    }

}

Player脚本调用Get()的代码

void Update()
{
    if (transform.IsChildOf(RunPlayer.Instance.transform) && RunPlayer.Instance._state == NumState.Running)
    {
        _State = State.Free;

    }
    if (_State == State.Free)
    {
        canShoot = true;
        charAnim.SetBool(Starting, true);
        StartCoroutine(ShootR());
    }
}
public enum State
{
    Idle,
    Free
}
public IEnumerator ShootR()
{
    while (canShoot)
    {
        if (downShootRate)
        {
            yield return new WaitForSeconds(.150f);
        }
        yield return new WaitForSeconds(.145f);
        bulletPool._bulletPool.Get();
    }
}

排查方向

  1. 协程重复启动问题:Player的Update方法中,每次_State == State.Free都会调用StartCoroutine(ShootR()),导致同时运行多个射击协程,疯狂调用Get()。当调用频率远高于子弹回收速度时,对象池空闲对象被耗尽,只能持续实例化新对象。
  2. 子弹回收逻辑失效:
    • 在DestroyBullet中添加日志,确认是否执行了_pool.Release(this);
    • 检查_pool是否为null,避免子弹被直接销毁而非放回池;
    • 打印_currentTime值,验证倒计时是否正常触发回收。
  3. 对象池参数限制:当前对象池最大空闲对象数为20,如果同时存在的子弹数量超过20,回收的子弹会被销毁(空闲池已满),导致后续Get()只能创建新对象。
  4. 子弹运动异常:检查Rigidbody设置(如是否勾选Kinematic),若rb.velocity不生效,虽不影响倒计时回收,但如果子弹被其他逻辑误销毁,也会导致池中空闲对象不足。

开发建议

  • 修复协程重复启动:添加标志位控制协程仅启动一次:
    private bool _isShooting;
    void Update()
    {
        // 原有状态判断逻辑
        if (_State == State.Free && !_isShooting)
        {
            canShoot = true;
            charAnim.SetBool(Starting, true);
            _isShooting = true;
            StartCoroutine(ShootR());
        }
    }
    public IEnumerator ShootR()
    {
        while (canShoot)
        {
            // 原有等待逻辑
            bulletPool._bulletPool.Get();
        }
        _isShooting = false;
    }
    
  • 移除静态Bullet实例:public static Bullet bullet;会被所有子弹覆盖,可能引发未知错误,建议直接删除。
  • 增加调试日志:在对象池的InstantiatePoolBullet、ReturnBulletToPool、DestroyBullet中添加日志,跟踪对象创建、回收、销毁流程。
  • 调整参数匹配需求:根据射击频率和子弹生命周期,调整对象池的defaultCapacity和maxSize,或延长射击间隔,降低Get()调用频率。

内容的提问来源于stack exchange,提问作者user21596799

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:45:11