Adding and removing methodes to event with an event...?

I’m training myself to use more events.
my test is with a day/night cycle… ie animals go to sleep/wakeup/searchForFood, predators goHunt/hide, humans startAFire/extinguishAFire/searchForFood.

for most function i use an Interface IBehaviour (sleep/wakeup/searchFood/hunt/hide…)
I have a Being base class that implements the IBehaviour interface…

and an EventHandler that fires the events OnChangeToDay and OnChangeToNight.

now I’m looking for a good way to add and remove the necessary function for each inherited class from Being (animal, predator, human).

Can i use an other event for the adding and removing to the Day/Night events? how would that look and where would i best put it?

current scripts… with the error:
Assets/Scripts/Cursus/Animal.cs(8,63): error CS0070: The event EventPublisher.OnChangeToDay' can only appear on the left hand side of += or -= when used outside of the type EventPublisher’

from the line: EventPublisher.OnChanged == EventPublisher.OnChangeToDay
also tried: EventPublisher.OnChanged is EventPublisher.OnChangeToDay (desperate attempt :slight_smile: )

EventPublisher:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EventPublisher : MonoBehaviour
{
    public delegate void DayNightCycle();
    public static event DayNightCycle OnChangeToDay;
    public static event DayNightCycle OnChangeToNight;

    public List<Being> beings;
    //public Being[] allBeings;

    void Start()
    {
        Human h = new Human();
        beings.Add(h);
        Animal a = new Animal();
        beings.Add(a);
        //allBeings = FindObjectsOfType<Being>();
    }

    public static DayNightCycle OnChanged(DayNightCycle newEvent)
    {
        DayNightCycle currentEvent;
        if(currentEvent != newEvent)
        {
            currentEvent = newEvent;
        }
        return currentEvent;
    }

    void OnGUI()
    {
        if(GUILayout.Button("Day"))
        {
            OnChanged(OnChangeToDay);
        }
        if(GUILayout.Button("Night"))
        {
            OnChanged(OnChangeToNight);
        }
    }
}

IBehaviour interface:

public interface IBehaviour
{
    void Sleep();
    void WakeUp();
    void SearchFood();
    void Hide();
}

Being base class:

using UnityEngine;
using System.Collections;

public class Being : IBehaviour
{
    public virtual void EventUpdate()
    {
        Debug.Log("Update event");
    }
    public void Sleep()
    {
        Debug.Log("sleeping");
    }
    public void WakeUp()
    {
        Debug.Log("waking up");
    }
    public void SearchFood()
    {
        Debug.Log("searching food");
    }
    public void Hide()
    {
        Debug.Log("hiding");
    }
}

child classes:

using UnityEngine;
using System.Collections;

public class Human : Being
{
    public override void EventUpdate()
    {
        if(EventPublisher.OnChanged == EventPublisher.OnChangeToDay)
        {
            EventPublisher.OnChangeToDay += WakeUp;
            EventPublisher.OnChangeToDay += SearchFood;
            EventPublisher.OnChangeToDay += ExtinguishFire;
            EventPublisher.OnChangeToDay -= StartFire;
            EventPublisher.OnChangeToDay -= Sleep;
        }
        if(EventPublisher.OnChanged == EventPublisher.OnChangeToNight)
        {
            EventPublisher.OnChangeToDay += Sleep;
            EventPublisher.OnChangeToDay += StartFire;
            EventPublisher.OnChangeToDay -= ExtinguishFire;
            EventPublisher.OnChangeToDay -= WakeUp;
            EventPublisher.OnChangeToDay -= SearchFood;
        }
    }

    public void StartFire()
    {
        Debug.Log("starting a fire");
    }
    public void ExtinguishFire()
    {
        Debug.Log("extinguishing a fire");
    }
}
using UnityEngine;
using System.Collections;

public class Animal : Being
{
    public override void EventUpdate()
    {
        if(EventPublisher.OnChanged == EventPublisher.OnChangeToDay)
        {
            EventPublisher.OnChangeToDay += WakeUp;
            EventPublisher.OnChangeToDay += SearchFood;
            EventPublisher.OnChangeToDay -= Sleep;
        }
        if(EventPublisher.OnChanged is EventPublisher.OnChangeToNight)
        {
            EventPublisher.OnChangeToDay += Sleep;
            EventPublisher.OnChangeToDay -= WakeUp;
            EventPublisher.OnChangeToDay -= SearchFood;
        }
    }
}

Why not just subscribe the events once instead of subscribing / unsubscribing all the time?
Also then you wouldn’t need all those if statements which would make things simpler.

the if statements didn’t work…
if i don’t unsubscribe, wouldn’t the wrong methods fire if the event gets set?

i ended up with this, but don’t know if i like it… feels sloppy…

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EventPublisher : MonoBehaviour
{
    public delegate void DayNightCycle();
    public static event DayNightCycle OnChanged;
    public static bool day;

    public List<Being> beings =  new List<Being>();
    //public Being[] allBeings;

    void Start()
    {
        Human h = new Human();
        beings.Add(h);
        Animal a = new Animal();
        beings.Add(a);
        //allBeings = FindObjectsOfType<Being>();
    }

    void OnGUI()
    {
        if(GUILayout.Button("Day"))
        {
            day = true;
            foreach(Being b in beings)
                b.EventUpdate();
            OnChanged();
        }
        if(GUILayout.Button("Night"))
        {
            day = false;
            foreach(Being b in beings)
                b.EventUpdate();
            OnChanged();
        }
    }
}
using UnityEngine;
using System.Collections;

public class Animal : Being
{
    public override void EventUpdate()
    {
        if(EventPublisher.day)
        {
            EventPublisher.OnChanged += WakeUp;
            EventPublisher.OnChanged += SearchFood;
            EventPublisher.OnChanged -= Sleep;
        }
        else if(!EventPublisher.day)
        {
            EventPublisher.OnChanged += Sleep;
            EventPublisher.OnChanged -= WakeUp;
            EventPublisher.OnChanged -= SearchFood;
        }
    }
}
using UnityEngine;
using System.Collections;

public class Human : Being
{
    public override void EventUpdate()
    {
        if(EventPublisher.day)
        {
            EventPublisher.OnChanged += WakeUp;
            EventPublisher.OnChanged += SearchFood;
            EventPublisher.OnChanged += ExtinguishFire;
            EventPublisher.OnChanged -= StartFire;
            EventPublisher.OnChanged -= Sleep;
        }
        else if(!EventPublisher.day)
        {
            EventPublisher.OnChanged += Sleep;
            EventPublisher.OnChanged += StartFire;
            EventPublisher.OnChanged -= ExtinguishFire;
            EventPublisher.OnChanged -= WakeUp;
            EventPublisher.OnChanged -= SearchFood;
        }
    }

    public void StartFire()
    {
        Debug.Log("starting a fire");
    }
    public void ExtinguishFire()
    {
        Debug.Log("extinguishing a fire");
    }
}

ok, supremegrandruler I get what you meant with just subscribing. with the 2 events like pervious it makes sense.

this feels better… although it seems harsh to subscribe to events in the constructor. it sure drops the if’s and bool’s…
still will try to make it more generic.
is this a good way to go at it?
and one more question: is there an “auto” unsubscribing happening if an instance gets destroyed or collected by the garbage collector?

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EventPublisher : MonoBehaviour
{
    public delegate void DayNightCycle();

    public static event DayNightCycle OnChangedToDay;
    public static event DayNightCycle OnChangedToNight;

    public List<Being> beings =  new List<Being>();
    //public Being[] allBeings;

    void Start()
    {
        Human h = new Human();
        beings.Add(h);
        Animal a = new Animal();
        beings.Add(a);
        //allBeings = FindObjectsOfType<Being>();
    }

    void OnGUI()
    {
        if(GUILayout.Button("Day"))
        {
            OnChangedToDay();
        }
        if(GUILayout.Button("Night"))
        {
            OnChangedToNight();
        }
    }
}
using UnityEngine;
using System.Collections;

public class Animal : Being
{
    public Animal()
    {
        EventPublisher.OnChangedToDay += WakeUp;
        EventPublisher.OnChangedToDay += SearchFood;
        EventPublisher.OnChangedToNight += Sleep;
    }
}
using UnityEngine;
using System.Collections;

public class Human : Being
{
    public Human()
    {
        EventPublisher.OnChangedToDay += WakeUp;
        EventPublisher.OnChangedToDay += SearchFood;
        EventPublisher.OnChangedToDay += ExtinguishFire;
        EventPublisher.OnChangedToNight += Sleep;
        EventPublisher.OnChangedToNight += StartFire;
    }

    public void StartFire()
    {
        Debug.Log(this.ToString()+" starting a fire");
    }
    public void ExtinguishFire()
    {
        Debug.Log(this.ToString()+" extinguishing a fire");
    }
}

Looks a lot better! Maybe the way I’d do it is subscribe to events on the “OnEnable” function and unsubscribe on the “OnDisable”.

but the Being class doesn’t inherit from monoBehaviour it only implements the IBehaviour interface so I thought the derived classes Animal and Human don’t have access to the OnEnable/OnDisable methods…

Yes, if it doesn’t inherit from MonoBehaviour, it won’t have access to those functions. You do know you can implement from an interface while also inheriting from a class, right?

If you don’t want to inherit from MonoBehaviour, maybe just create your own unsubscribe function.

yes but I prefer handling objects in code as to components on gameObjects.
I’ll try making a kind of generic function to subscribe with some kind of callback delegate.