How to listen for an event launched from an instantiated object?

I’m trying to create a clone of the Bomberman game. The player will have the ability to drop bombs, but the amount will be limited according to skill level. To implement the logic, my idea was as follows: When the player presses J, he instantiates a bomb. At this time, it is checked if the player has already exceeded the limit amount of his skill. If it doesn’t go over the limit, the bombsDropped variable is incremented.

The problem is to decrement this variable. I tried to create an event that is launched at the moment the bomb explodes, but since the bomb is instantiated, the reference is always null.

Thanks to everyone who tries to help!

Examples of problems:

Repository in GitHub:
https://github.com/MuriloCSeidenstucker/GIT_BombermanClone

Codes:

PlayerController.cs:

public class PlayerController : MonoBehaviour
{
    [SerializeField] GameObject bombPrefab;

    ...
    PlayerSkills playerSkills;
    PlayerInput playerInput;

    Bomb bombScript;

    int bombsDropped;

    void Start()
    {
        ...
        playerSkills = GetComponent<PlayerSkills>();
        playerInput = GetComponent<PlayerInput>();

        bombScript = FindObjectOfType(typeof(Bomb)) as Bomb;
        if (bombScript != null)
        {
            bombScript.OnExplode += BombExploded;
        }
    }

    private void OnDestroy()
    {
        if (bombScript != null)
        {
            bombScript.OnExplode -= BombExploded;
        }
    }

    void Update()
    {
        if (playerInput.GetActionInput())
        {
            if (!IsSkillLimitExceeded())
            {
                DropBomb();
            }
        }
    }

    void FixedUpdate()...

    void MovePlayer()...

    void DropBomb()
    {
        Instantiate(bombPrefab, transform.position, transform.rotation);
        bombsDropped++;
    }

    void BombExploded()
    {
        bombsDropped--;
    }

    bool IsSkillLimitExceeded()
    {
        if (bombsDropped == playerSkills.AmountBombs)
            return true;

        return false;
    }
}

Bomb.cs:

public class Bomb : MonoBehaviour
{
    public event Action OnExplode;

    float timeToExplode = 2.0f;

    void Start()
    {
        StartCoroutine(BombSettings());
    }

    IEnumerator BombSettings()
    {
        yield return new WaitForSeconds(timeToExplode);
        if (OnExplode != null)
        {
            OnExplode.Invoke();
        }
        Destroy(gameObject);
    }
}

You need to subscribe separately to each individual bomb as it is dropped. Instantiate() returns a reference to the thing you just created.

public Bomb bombTemplate;

void DropBomb()
{
    Bomb newBomb = Instantiate<Bomb>(bombTemplate, transform.position, transform.rotation);
    newBomb.OnExplode += BombExploded;
    ++bombsDropped;
}

(If you want your prefab variable to be of type GameObject instead of type Bomb for some reason, then you will need to get a reference to the Bomb component on the newly-instantiated GameObject via GetComponent() or some variant thereof.)

I do feel like I should note that this whole approach is a little bit dangerous, in the sense that if a bomb were ever somehow removed from the game without invoking its OnExplode event, your bomb counter would be permanently wrong.

Assuming the number of bombs per player is not very large (say, less than a hundred), I would probably keep around references to all the bombs in a collection like List or HashSet, and iterate through them to check if they still exist (removing the references to any that don’t). That makes the decision state-dependent instead of path-dependent, thereby eliminating an entire class of potential bugs.

Thanks so much for the help, this solved the problem!