In Unity, how can I send an event to a single game object? Or, how else can I solve this problem?
Scenario: Let's say there are six players in a scene. And a bunch of coins for them to collect.
Each coin has a CoinCollectable
script. When it detects a collision with a player, it invokes its OnCollected
event.
public class CoinCollectable : MonoBehaviour
{
// The action to invoke when this coin is collected by a player
public static event Action<GameObject, int> OnCollected;
// When a coin is touched
private void OnTriggerEnter2D(Collider2D other) {
// If not a player, abort
if (!other.gameObject.CompareTag("Player")) return;
// Invoke the coin collected event
OnCollected?.Invoke(other.gameObject, coinValue);
}
}
All players listen to this event in their PlayerCoinCounter
script.
public class PlayerCoinCounter : MonoBehaviour
{
private void OnEnable()
{
// Subscribe to events
CoinCollectable.OnCollected += IncreaseCoins;
}
private void OnDisable()
{
// Un-subscribe from events
CoinCollectable.OnCollected -= IncreaseCoins;
}
private void IncreaseCoins(GameObject player, int coinsToAdd)
{
// If this is not the player who collected the coin, abort
if(player != this.gameObject) return;
// (Increase the current coin counter value)
}
}
The problem is that with this setup, every single player has to check "Was I the one who collected the coin?" in their event handler method. This feels cumbersome and not very elegant.
How would you approach this problem? I wonder:
- Is there a way to send the event just to the one player who actually collected the coin? (To avoid each player having to check if they collected it)
- If not, then in
OnTriggerEnter2D
, should I instead doother.GameObject.GetComponent<PlayerCoinCounter>().IncreaseCoins(...)
? This does not feel ideal, because I would be assuming that the player has such a component. So I would lose the decoupling that the event approach provides.
PS: I am using events to minimise coupling.