Can I use an interface to subscribe a script to a multicast delegate? Or, what would be a good alternative?

One of the many “golden rules” of programming is that if you’re copying code, you’re probably doing something wrong.

I have a singleton (gasp) that manages game ticks, and on every game tick it invokes the OnGameTick delegate.

I have many scripts that do their own things when OnGameTick is invoked, but they all do it through the DoGameTick() method. So, right now, I have all of these scripts inherit from abstract class TickUpdatingMonoBehavior, which is where the OnEnable() and OnDisable() methods subscribe and unsubscribe abstract void DoGameTick() to the OnGameTick delegate. That way, I don’t need to type it out for every script, and as a bonus the compiler tells me when I haven’t implemented DoGameTick().

However, this means that I cannot have these methods inherit from anything else (except other children). I want to use an interface called like IUpdateOnTick or something, but interfaces don’t support default implementation and can’t even call OnEnable() and OnDisable(). The interface could still define DoGameTick() but that doesn’t accomplish much on its own.

When inheritance causes problems, composition often helps.

public interface ITickable
{
     void DoGameTick();
}

// Will automatically add TickExecutor component when this component is added
[RequireComponent(typeof(TickExecutor))]
public class MyMonoBehaviour : MyBaseClass, ITickable
{
     public void DoGameTick()
     {
          Debug.Log("Tick");
     }
}

public class TickExecutor : MonoBehaviour
{
     private ITickable tickable;
     void OnEnable()
     {
          tickable = GetComponent<ITickable>();
          if(tickable != null)
              GameManager.OnGameTick += tickable.DoGameTick;
     }

     void OnDisable()
     {
          if(tickable != null)
              GameManager.OnGameTick += tickable.DoGameTick;
     }
}

IDK exactly what you want to achieve but there is couple tricks that can be useful :slight_smile:

public interface ITickable 
{ 
    protected internal void Bla() { Debug.Log(""); }
    internal void Init() { Debug.Log("Some initialization things?"); }
    
}

public class A : ITickable
{
    public A()
    {
        ((ITickable)this).Init();
    }
}

public class B : MonoBehaviour
{
    ITickable tickable;
    A Aclass;

    private void Awake()
    {
       
        ((ITickable)Aclass).Init();
        tickable.Init();
    }
    void Call()
    {
        ((ITickable)Aclass).Bla();
        tickable.Bla();
    }
}

public class C: MonoBehaviour, ITickable
{

    private void Awake()
    {
        ((ITickable)this).Init();
        A AclassInit = new();
    }
}

or maybe events?

public class TickUpdater : MonoBehaviour
{
    public static event System.Action OnTick;
    public static event System.Action<String> OnTickWithParams;

    private void Start()
    {
        OnTick();
        OnTickWithParams("some text");
    }
}

public interface ITickReceiver
{
    public void RegisterEvent() { InternalRegisterEvent(); }
    private void InternalRegisterEvent() { TickUpdater.OnTick += DoTickFromInterface; }

    void DoTickFromInterface();
}

public class TickReceiver : MonoBehaviour, ITickReceiver
{

    private void Awake()
    {
        TickUpdater.OnTick += DoTick;
        TickUpdater.OnTickWithParams += DoTickWithParams;
        (this as ITickReceiver).RegisterEvent();
    }

    private void DoTick() { }

    public void DoTickFromInterface() { }

    private void DoTickWithParams(string obj) { }

}

Can’t you just make abstract void DoGameTick() virtual, and then override it as needed?