0
\$\begingroup\$

I'm looking for the best way to handle events for a tactic game in Unity. Every unit may need to react to different events (turn start, end, on damage to self, on damage to other, on kill, etc...).

At the moment I'm just cycling all units for any event from a central manager class, but I'm looking for a more elegant and easy-to-extend solution. I'm not worried about performance since the involved number of units will be low.

Any advice?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Have you researched UnityEvents? If not, that's where you should start. \$\endgroup\$
    – Kevin
    May 25, 2021 at 22:24

1 Answer 1

1
\$\begingroup\$

One of the best ways to handle events in Unity is... using UnityEvents!

In this example, we have a singleton called TurnManager with functions we can call when a turn starts or ends. Units subscribe to the relevant event so they are notified when a turn starts or ends.

public class TurnManager : MonoBehavior {
    //singleton pattern for convenience
    private static TurnManager instance;
    public static TurnManager Instance => instance;

    [SerializeField] private UnityEvent onTurnStart;
    public UnityEvent OnTurnStart => onTurnStart;

    [SerializeField] private UnityEvent onTurnEnd;
    public UnityEvent OnTurnEnd => onTurnEnd;

    void Awake() {
        Assert.IsNull(instance);
        instance = this;
    }
    void OnDestroy() {
        instance = null;
    }

    public void StartTurn() {
        onTurnStart.Invoke();
    }
    public void EndTurn() {
        onTurnEnd.Invoke();
    }
}

public class SelfHealingUnit : Unit {
    [SerializeField] private int hpPerTurn = 10;    

    void OnEnable() {
        TurnManager.Instance.OnTurnStart.AddListener(TurnStartHandler);
    }
    void OnDisable() {
        TurnManager.Instance.OnTurnStart.RemoveListener(TurnStartHandler);
    }
    void TurnStartHandler() {
        HP += hpPerTurn;
    }
}

public class SuicideUnit : Unit {
    [SerializeField] private int lifespan = 3;
    [SerializeField] private UnityEvent onExplode;
    public UnityEvent OnExplode => onExplode;

    int turnsAlive = 0;

    void OnEnable() {
        TurnManager.Instance.OnTurnEnd.AddListener(TurnEndHandler);
    }
    void OnDisable() {
        TurnManager.Instance.OnTurnEnd.RemoveListener(TurnEndHandler);
    }
    void TurnEndHandler() {
        turnsAlive++;
        if (turnsAlive >= lifespan) {
            Explode();
        }
    }
    public void Explode() {
       //do stuff here
       //...
       onExplode.Invoke();
    }
}

This way we don't have to notify every single unit every time the turn starts or ends; we only notify the units that care when the turn starts or ends. You can easily extend this example with other types of events.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .