After completing the lecture and testing firing the gun, I’m getting the error below and some bullets are destroyed shortly after firing.
MissingReferenceException: The object of type ‘Bullet’ has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
Gun+<>c.b__15_1 (Bullet bullet) (at Assets/Scripts/Gun/Gun.cs:63)
UnityEngine.Pool.ObjectPool`1[T].Get () (at <10871f9e312b442cb78b9b97db88fdcb>:0)
Gun.ShootProjectile () (at Assets/Scripts/Gun/Gun.cs:83)
Gun.Shoot () (at Assets/Scripts/Gun/Gun.cs:75)
Gun.Update () (at Assets/Scripts/Gun/Gun.cs:30)
I am able to recreate this consistently by just shooting the far away walls and then shooting the ground tiles nearby. I found another post by DustyDomino (2D game feel course object pooling bullet error) with the same issue. Tried changing the pools ActionOnDestroy from “Destroy(bullet)” to “Destroy(bullet.gameObject)”. This reduced the error frequency but it still can be consistently recreated.
I’ve tried setting the Pool collectionCheck to true, this gives a different set of errors about releasing objects that has already been released. I also tried changing the Pool’s actionOnDestroy to be a method checking if bullet != null. This seemed to reduce the errors but still didnt prevent them entirely. I’ve reverted both of these changes.
Any assistance would be appreciated to help understand what is happening. Please see gif/screenshot and code below.
Gif
Pic of holding down mouse button but showing a bunch of empty spots where bullets should be:
Gun Code
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Pool;
public class Gun : MonoBehaviour
{
public static Action OnShoot;
//public Transform BulletSpawnPoint => _bulletSpawnPoint;
[SerializeField] private Transform _bulletSpawnPoint;
[SerializeField] private Bullet _bulletPrefab;
[SerializeField] private float _gunFireCD = .5f;
private ObjectPool<Bullet> _bulletPool;
private static readonly int FIRE_HASH = Animator.StringToHash("Fire");
private Vector2 _mousePos;
private float _lastFireTime = 0f;
private Animator _animator;
private void Awake() {
_animator = GetComponent<Animator>();
}
private void Update()
{
Shoot();
RotateGun();
}
private void Start() {
CreateBulletPool();
}
private void OnEnable() {
OnShoot += ShootProjectile;
OnShoot += ResetLastFireTime;
OnShoot += FireAnimation;
}
private void OnDisable() {
OnShoot -= ShootProjectile;
OnShoot -= ResetLastFireTime;
OnShoot -= FireAnimation;
}
public void ReleaseBulletFromPool(Bullet bullet){
_bulletPool.Release(bullet);
}
private void CreateBulletPool()
{
_bulletPool = new ObjectPool<Bullet>
(
() => {return Instantiate(_bulletPrefab); },
bullet => { bullet.gameObject.SetActive(true); },
bullet => { bullet.gameObject.SetActive(false); },
bullet => { Destroy(bullet.gameObject); },
false,
20, 40
);
}
private void Shoot()
{
if (Input.GetMouseButton(0) && Time.time >= _lastFireTime) {
OnShoot?.Invoke();
}
}
private void ShootProjectile()
{
//Bullet newBullet = Instantiate(_bulletPrefab, _bulletSpawnPoint.position, Quaternion.identity);
Bullet newBullet = _bulletPool.Get();
newBullet.Init(this, _bulletSpawnPoint.position, _mousePos);
}
private void FireAnimation()
{
_animator.Play(FIRE_HASH, 0, 0f);
}
private void ResetLastFireTime()
{
_lastFireTime = Time.time + _gunFireCD;
}
private void RotateGun()
{
_mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//OLD, doesnt flip gun - Vector2 direction = _mousePos - (Vector2)PlayerController.Instance.transform.position;
Vector2 direction = PlayerController.Instance.transform.InverseTransformPoint(_mousePos);
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
transform.localRotation = Quaternion.Euler(0, 0, angle);
}
}
Bullet Code
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
[SerializeField] private float _moveSpeed = 10f;
[SerializeField] private int _damageAmount = 1;
private Vector2 _fireDirection;
private Rigidbody2D _rigidBody;
private Gun _gun;
private void Awake()
{
_rigidBody = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
_rigidBody.velocity = _fireDirection * _moveSpeed;
}
public void Init(Gun gun, Vector2 bulletSpawnPos, Vector2 mousePos) {
_gun = gun;
transform.position = bulletSpawnPos;
_fireDirection = (mousePos - bulletSpawnPos).normalized;
}
private void OnTriggerEnter2D(Collider2D other) {
Health health = other.gameObject.GetComponent<Health>();
health?.TakeDamage(_damageAmount);
_gun.ReleaseBulletFromPool(this);
}
}