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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With