Search Unity

A question about delegates in if statements

Discussion in 'Scripting' started by Korno, Mar 1, 2015.

  1. Korno

    Korno

    Joined:
    Oct 26, 2014
    Posts:
    518
    I am away from my dev box at the moment so I cant test this, but to c# gurus out therem I have a question:

    In my game I have a class that handles taking damage. It looks like this:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public delegate void DamageReceivedEvent(Damageable src, float Health, float damage);
    5. public delegate void DeathEvent(Damageable src);
    6. public delegate bool ShouldApplyDamageEvent(Damageable src);
    7.  
    8. public class Damageable : MonoBehaviour {
    9.    
    10.     public float Health;
    11.     public bool IsInvincible;
    12.     public bool IsDead=false;
    13.     public float StartHealth;
    14.  
    15.     public event DamageReceivedEvent OnDamaged;
    16.     public event DeathEvent OnDeath;
    17.     public event ShoudlAppyDamageEvent OnPreApplyDamage;
    18.  
    19.     public virtual void OnEnable()
    20.     {
    21.         Health = StartHealth;
    22.     }
    23.    
    24.     public void TakeDamage(Damager d)
    25.     {
    26.         if(IsDead==false)
    27.         {
    28.             if(d.enabled == true)
    29.             {
    30.                 if(!OnPreApplyDamage(d))
    31.                 {
    32.                     Health -= d.Damage;
    33.                     if(OnDamaged != null) OnDamaged(this, Health, d.Damage);
    34.                     checkForDeath();
    35.                 }
    36.                
    37.             }
    38.         }
    39.     }
    40.  
    41.     public void ResetHealth()
    42.     {
    43.         Health = StartHealth;
    44.         IsDead =false;
    45.     }
    46.    
    47.     void checkForDeath()
    48.     {
    49.         if(Health <= 0)
    50.         {
    51.             IsDead = true;
    52.             if(OnDeath != null)OnDeath(this);
    53.         }
    54.     }
    55.    
    56. }
    As you can see I making heavy use of delegates to allow other game objects to receive damage notifications, for AI death animations etc. As this is a magic based game and some spells can remove or reduce damage, I am providing an event that is fired before the damage is applied

    Code (CSharp):
    1. public delegate bool ShouldApplyDamageEvent(Damageable src);
    2.  
    If a handler returns false then the damage is not applied (this could be a shield script for example)

    Now, I have this piece of code:

    Code (CSharp):
    1. public void TakeDamage(Damager d)
    2.     {
    3.         if(IsDead==false)
    4.         {
    5.             if(d.enabled == true)
    6.             {
    7.                 if(!OnPreApplyDamage(d))
    8.                 {
    9.                     Health -= d.Damage;
    10.                     if(OnDamaged != null) OnDamaged(this, Health, d.Damage);
    11.                     checkForDeath();
    12.                 }
    13.                
    14.             }
    15.         }
    16.     }
    The question
    If two objects subscribed to the OnPreApplyDamage event and one returned true and one returned false, How would the if statement resolve?
     
  2. Yemachu

    Yemachu

    Joined:
    Feb 1, 2015
    Posts:
    13
    The return value of an event matches that of the function which is executed last on the invocation list. That is most likely the one which subscribed last... not something we get much wiser from. You could try to execute all functions yourself by retrieving the invocation list; this way you get all results. And her is how you would do that:
    Code (CSharp):
    1. public delegate bool ShouldApplyDamageEvent(Damageable src);
    2.         public event ShouldApplyDamageEvent OnPreApplyDamage;
    3.  
    4.         public void SomeFunction()
    5.         {
    6.             if (OnPreApplyDamage!=null)
    7.             {
    8.                 ShouldApplyDamageEvent[] handlers = (ShouldApplyDamageEvent[])OnPreApplyDamage.GetInvocationList();
    9.                 foreach (ShouldApplyDamageEvent handler in handlers)
    10.                 {
    11.                     handler(this);
    12.                 }
    13.             }
    14.         }
    Another option is to do it the way the .NET Framework does it: passing down an object with values which can be changed by the reciever. That way you can basically have multiple return values. The class EventArgs is typically used for this purpose. You could combine this with the above, so you might stop the invocation earlier if you have found what you were looking for. Here is an example how you would go around that:
    Code (CSharp):
    1. public class DamageEventArgs : System.EventArgs
    2. {
    3.     private Damageable _damageable;
    4.     public Damageable damageable
    5.     {
    6.         get {return _damageable;}
    7.     }
    8.  
    9.     private bool _shouldApplyDamage = false;
    10.     public bool shouldApplyDamage
    11.     {
    12.         get {return _shouldApplyDamage;}
    13.         set {_shouldApplyDamage = value;}
    14.     }
    15.  
    16.     public DamageEventArgs(Damageable damageable)
    17.     {
    18.         _damageable = damageable;
    19.     }
    20. }
    21.  
    22. public event System.EventHandler<DamageEventArgs> ShouldApplyDamage;
    23.  
    24.  
    25. public void SomeFunction()
    26. {
    27.     if (ShouldApplyDamage != null)
    28.     {
    29.         DamageEventArgs eventArgs = new DamageEventArgs(null);
    30.         ShouldApplyDamage(this, eventArgs);
    31.         if (eventArgs.shouldApplyDamage)
    32.         {
    33.             //Apply damage... or whatever you want to do.
    34.         }
    35.     }
    36. }
    37.  
    38.  
    39. public void SubscribedFunction(object sender, DamageEventArgs e)
    40. {
    41.     if (e.damageable != null)
    42.     {
    43.         e.shouldApplyDamage = true;
    44.     }
    45. }
     
    Korno likes this.
  3. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
  4. Korno

    Korno

    Joined:
    Oct 26, 2014
    Posts:
    518
    Thanks guys, that was some great information. To be honest this is the first time I have even considered events with return types, I usually just used them for notifications.