Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegates and Events triggering on particular instance

I have the following class which defines an event and delegate. I then have a method which fires the event like this:

public class HealthManager : MonoBehaviour {
    // Create the delegate
    public delegate void ObjectDeath(GameObject go);
    // Create the event
    public static event ObjectDeath OnObjectDeath;

    public static void GiveDamage(GameObject dealer, GameObject receiver, float amount){
        /* 
            Subtract health here
            ... Code Snipped ...
        */
        if(objectHealth.health <= objectHealth.deathHealth){
            // Trigger the delegate/event
            OnObjectDeath(receiver);
        }
    }
}

I then have this class which listens for the event to get fired like this:

public class DeathListener : MonoBehaviour {

    // Add event listeners when object gets enabled
    void OnEnable () {
        HealthManager.OnObjectDeath += Died;
    }

    // Remove event listeners when object gets disabled
    void OnDisable () {
        HealthManager.OnObjectDeath -= Died;
    }

    void Died(GameObject go){
        if(gameObject == go){
            Destroy(gameObject);
        }
    }

}

The question I have is, is it possible to fire the event on just particular objects?

So, instead of doing this:

// Trigger
OnObjectDeath(receiver);
// ---------------------------- //
void Died(GameObject go){
    if(gameObject == go){
        Destroy(gameObject);
    }
}

I can do something like this:

receiver.OnObjectDeath();
// ---------------------------- //
void Died(){
    Destroy(gameObject);
}

I would like to have a way where in the event Died I don't have to check which object to apply it on. Currently if I remove the if statement, then it will apply that to all gameObjects not just the instance I am working with.

like image 527
Get Off My Lawn Avatar asked Nov 16 '25 08:11

Get Off My Lawn


1 Answers

You seem to misuse the event pattern in your case. The point of event/listener is that the sender sends the info regardless of who is listening.

But in your case, the sender is aiming at one specific instance and you actually have a reference to it already. Then you might as well get the component of that object and call a method on it.

public static void GiveDamage(GameObject dealer, GameObject receiver, float amount){
   /* 
       Subtract health here
       ... Code Snipped ...
   */
   if(objectHealth.health <= objectHealth.deathHealth){
       // Trigger the delegate/event
       receiver.GetComponent< DeathListener >().Died(); // no need for parameter
    }
}

EDIT: Based on your comment, a more appropriate way (in my opinion) would be to have a IDamageable interface with Damage method. Then all items that should be damaged should implement the method so they get damaged properly. Then you can simply calls the Damage method with the amount of damage and it will take care of the death if needed.

Let's consider a bullet system:

public void Bullet:MonoBehaviour{
    public int damage = 10;
    // it is hitting either from raycast or collision or else
    void OnHit(GameObject collidedObject){
        IDamageable dam = collidedObject.GetComponent<IDamageable>();
        // if you hit a wall or no damageable item, it will be false
        if(dam != null) {
            dam.Damage(damage);
        }
    }
}

The bullet is oblivious to what it is hitting and should not care. Only matters how much it should damage.

public class Player : MonoBehaviour , IDamageable{
     int health = 20;
     public EventHandler <EventArgs> RaiseDeathEvent;
     protected void OnDeath(EventArgs arg){
          if(RaiseDeathEvent != null) RaiseDeathEvent(this, arg);
     }
     public void Damage(int damage){
         this.health -= damage;
         if(this.health < 0){
             Died();
             OnDeath(null);
         }
     }
}

There you go. If you need other items, like UI or scene manager to be informed of death so that they can perform an action, then you would get those to find the event and register to it. The player would not even know about them.

like image 69
Everts Avatar answered Nov 19 '25 00:11

Everts



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!