Simple broadcasting system

Hey,

Thought I’d share a simple script I’ve been using a for a while to handle communication better between objects.

This allows you to send events to objects and any scripts that are registered to the event can respond. It also allows for sending out blind events and anything registered to listen for it will get called.

Helpful use cases:

  • Communication between objects without worrying about what components it has
  • Scripts can deal with a broadcast in their own way, a player can lose health on damage event and a plant could just play a ruffle anim
  • No need to have a static GetInstance manager, you can have a broadcast to fetch the in scene manager

Registered broadcasts can persist between scenes, so a persistant object can register for paused events and receieve them on any scene it gets moved into.

Broadcasts can be used in 3 key ways:

  • Simple broadcasts are dataless and come with a static “SendBroadcast”
  • Dynamic broadcasts are used for events that several objects may need to send in a frame, these can hold data and shouldnt use a static “SendBroadcast” E.g. Damage events
  • Static broadcasts are the data version of simple broadcasts, you have to write your own “SendBroadcast” function for these

Heres an example of each:


//Simple broadcast
public class StartGameBroadcast : SimpleBroadcast<GameOverBroadcast> { }

//Dynamic broadcast
public class FindPlayers : Broadcast
{
    public List<Player> PlayerList;
}

//Static data broadcast
public class LevelLoadedBroadcast : Broadcast
{
    public Level LoadedLevel;

    public static void SendBroadcast(Level InLevel)
    {
        LevelLoadedBroadcast Instance = GetInstance<LevelLoadedBroadcast>();
        Instance.LoadedLevel = InLevel;

        Broadcaster.SendBroadcast(null, Instance);
    }
}

Heres a usage of example each:

-Simple broadcast

//Declare the broadcast
public class GameOverBroadcast : SimpleBroadcast<GameOverBroadcast> { }

//IBroadcastListener lets us register for broadcasts
public class GameSystem : MonoBehaviour, IBroadcastListener
{
    void Awake()
    {
        //Register to respond to the game over broadcast
        Broadcaster.RegisterDelegate<GameOverBroadcast>(this);
    }

    void OnDestroy()
    {
        //UnRegister once we no longer need to care about it
        Broadcaster.UnRegisterDelegate<GameOverBroadcast>(this);
    }

    //Required for IBroadcastListener, any registered broadcasts will come through here
    public void ReceiveBroadcast(object InSender, Broadcast InBroadcast)
    {
        //Check its the Broadcast we want
        if (InBroadcast.IsBroadcast<GameOverBroadcast>())
        {
            //Do stuff
        }
    }
}

public class Player : MonoBehaviour
{
    void OnDeath()
    {
        //Send a global broadcasts of "GameOverBroadcast", any registered listener will respond
        GameOverBroadcast.SendBroadcast();
    }
}

Dynamic broadcast


public class DamageBroadcast : Broadcast
{
    public int Damage;
}

public class Projectile : MonoBehaviour
{
    DamageBroadcast DamageBC = new DamageBroadcast();

    private void OnTriggerEnter(Collider other)
    {
        //Sets the damage in the broadcast
        DamageBC.Damage = 10;
        //Only sends the broadcast to who we overlapped with
        Broadcaster.SendBroadcast(this, other.gameObject, DamageBC);
    }
}

//Broadcasts sent to a gameobject can be handled by any of the monobehaviours on it
public class Player : MonoBehaviour, IBroadcastListener
{
    int Health;

    void Awake()
    {
        Broadcaster.RegisterDelegate<DamageBroadcast>(this);
    }

    void OnDestroy()
    {
        Broadcaster.UnRegisterDelegate<DamageBroadcast>(this);
    }

    public void ReceiveBroadcast(object InSender, Broadcast InBroadcast)
    {
        //When we receive a damage broadcast, apply the damage
        if (InBroadcast.IsBroadcast<DamageBroadcast>())
        {
            DamageBroadcast Data = InBroadcast as DamageBroadcast;

            Health -= Data.Damage;
        }
    }
}

Static data broadcast

public class LevelLoadedBroadcast : Broadcast
{
    public Level LoadedLevel;

    //Since this broadcast will be called once in a while we can use a static instance
    public static void SendBroadcast(Level InLevel)
    {
        //Get or create a static instance of this type
        LevelLoadedBroadcast Instance = GetInstance<LevelLoadedBroadcast>();
        //Set the data to pass along
        Instance.LoadedLevel = InLevel;

        //Sending globally, could provide a caller & target if relevant
        Broadcaster.SendBroadcast(null, Instance);

       //Clear the data up (If needed)
      Instance.LoadedLevel = null;
    }
}

public class GameSystem : MonoBehaviour
{
    void LeveLoad()
    {
        Level LoadedLevel;
        //Sending out the event with the data
        LevelLoadedBroadcast.SendBroadcast(LoadedLevel);
    }
}

public class OtherSystem : MonoBehaviour, IBroadcastListener
{
    void Awake()
    {
        Broadcaster.RegisterDelegate<LevelLoadedBroadcast>(this);
    }

    void OnDestroy()
    {
        Broadcaster.UnRegisterDelegate<LevelLoadedBroadcast>(this);
    }

    public void ReceiveBroadcast(object InSender, Broadcast InBroadcast)
    {
        if(InBroadcast.IsBroadcast<LevelLoadedBroadcast>())
        {
            LevelLoadedBroadcast Data = InBroadcast as LevelLoadedBroadcast;

            //Do what we want with the data
            Data.LoadedLevel;
        }
    }
}

I’ve personally used this in all my projects so hopefully other people find this useful!
Any questions feel free to ask.