Adding callbacks/events to an instantiated prefab
Asked Answered
W

2

0

I am having a heck of a time with this one. I am using a Spawner which is not a Prefab to Instantiate a bunch of prefab bombs in my scene. When each bomb is diffused I need it to contact the spawner to let it know, Destroy it, and tell the player “You have one more left”. Anyway, I was hoping this post would help (Can one add events to an instantiated object? - Questions & Answers - Unity Discussions) but I receive the error

"Operator += cannot be applied to operand of type `UnityEngine.Events.UnityAction` and `void`" 

Spawner.cs

void Spawn()
{
    ...
    aBomb = Instantiate (bomb, b[point].transform.position, b[point].transform.rotation);
    aBomb.GetComponent<Disarm> ().BombDisarmed += this.BombDisarmed ();
    ...
}
void BombDisarmed()
{
    // Do Disarm Stuff
}

Attached to my bomb Prefab I have the Disarm.cs script.

Disarm.cs

public class Disarm : MonoBehaviour
{
    public event Action BombDisarmed;
    
    public void DisarmBomb()
    {
        if (BombDisarmed != null)
            BombDisarmed ();
    }
}

Obviously it’s been trimmed but the basics are there. The gist is the same. Disarm.DisarmBomb() is getting called because the Audio and Particles are playing but now I just need it to call Spawner.BombDisarmed().

I’ve tried delegate’s, UnityEvent’s, and SendMessage, no luck. At this point I’m convinced I have no idea what I’m doing :slight_smile:

I have NO IDEA why I can’t get this working!! PLZ. HELP.

Western answered 22/8, 2023 at 22:14 Comment(1)

Worked great, thanks!

Gingergingerbread
S
0

I would stick with UnityEvent’s with this. I’m not sure how you were using them before resorting to Actions, but I set up a small scene with a “spawner” that spawns one bomb and adds a listener to the UnityEvent that the Bomb controller has. The bomb controller will destroy itself after 3 seconds, then its OnDestroy() will trigger, invoking the BombDisarmed UnityEvent.

The was UnityEvents work is that you need to add listeners (which are your methods you want triggered), and then invoke the UnityEvent when you want it to.

In the spawner, i add my listener once I instantiate the bomb. Then in the bomb’s OnDestroy, I invoke the UnityEvent, which the triggers HandleBombDisarmed() from the spawner.

If you want to go one step further, you can include the BombController in the listener by implementing your own UnityEvent class. Then you can access information about each bomb when they are disarmed. Here is the documentation on UnityEvent Unity - Scripting API: UnityEvent<T0>

Basically, you create a class that extends UnityEvent, and you do nothing else with it! You can see at the bottom of BombController that I created one (I added System.Serializable on it so that it shows up in the inspector, check it out!).

Then to use this new UnityEvent type, use it just like a normal UnityEvent, the only catch is, the listener you give it must have the same parameter type at , and when you call Invoke(), it needs an argument with the same type as well.

I implemented both types of UnityEvents in the code. "BombDisarmed" is the normal way you asked for. And "CoolBombDisarmed" is the the going a step further and letting you pass the bomb object to the method.

(Sorry for the novel, I don’t answer these much!)

SpawnerController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
  
public class SpawnerController : MonoBehaviour
{  
    public GameObject BombPrefab;
  
    void Start ()
    {
        GameObject bomb = Instantiate(BombPrefab);
        BombController bombController = bomb.GetComponent<BombController>();
  
        bombController.BombDisarmed.AddListener(HandleBombDisarmed);
        bombController.CoolBombDisarmed.AddListener(HandleCoolBombDisarmed);
    }
	
    public void HandleBombDisarmed()
    {
        Debug.Log("Bomb disarmed");
    }
  
    public void HandleCoolBombDisarmed(BombController bomb)
    {
        Debug.Log("Bomb disarmed. Its name was " + bomb.gameObject.name);
    }

}

BombController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
  
public class BombController : MonoBehaviour
{    
    public UnityEvent BombDisarmed;
    public BombDisarmedEvent CoolBombDisarmed;
  
    // Use this for initialization
    void Start ()
    {
        StartCoroutine(BlowUp());
    }
  
    private void OnDestroy()
    {
        BombDisarmed.Invoke();
        CoolBombDisarmed.Invoke(this);
    }
  
    IEnumerator BlowUp()
    {
        yield return new WaitForSeconds(3.0f);
        Destroy(this.gameObject);
    }

}
  
[System.Serializable]
public class BombDisarmedEvent : UnityEvent<BombController>
{
  
}
Shoreline answered 26/12, 2023 at 15:35 Comment(1)

SWEEET! Thanks for taking the time. I like putting it in the OnDestroy() also.

Western
E
0

usually you don’t need parentheses"()" when assigning delegates

aBomb.GetComponent ().BombDisarmed += this.BombDisarmed; // and not += this.BombDisarmed()
Ellord answered 22/8, 2023 at 21:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.