0
\$\begingroup\$

Let's say a game engine had a central game class as well as multiple systems (as objects) that are stored within it. These systems (such as input, rendering, sound, etc) would also be updated by this main game class. What if the input manager detects that the close button on the window if pressed. It would cause the game to shutdown by, say, calling a quit method inside the game class. This would be an example of a closely coupled system which is typically not good for future expansion of these systems. How would a closely coupled system like this be dealt with in order to make it more loosely coupled?

\$\endgroup\$
1
\$\begingroup\$

Events would help for this.

Take your InputManager example in the method where you detect the close button has been pressed instead of referencing the game class and calling the quit method you would fire an event lets say "OnWindowClosed" and then have your game class subscribe to that event.

That way you could theoretically have any class that needs to know the game is shutting down subscribe to the event and do whatever it needs to do when OnWindowClosed is triggered.

This way the subscriber (Game class) doesn't need to know anything about the publisher(Input Manager) other than it did something it may want to "respond" to.

Here is an example from my project, the ActorManager needs to listen for the OnMapLoad Event Triggering from MapManager in order to spawn the Actors into the scene after its been generated.

public class EventManager
{
    //define a delegate signature, the variables need to match up the event trigger
    public delegate void OnMapLoad(Vector3 mapSize, Dictionary<Vector3, Tile> currentMap);
    //define the event generally prefixed with "On"
    public static event OnMapLoad OnMapLoadCallBack;

    //and here's the event trigger itself
    public static void TriggerOnMapLoad(Vector3 mapSize, Dictionary<Vector3, Tile> currentMap)
    {
        //check to see if OnMapCallBack has subscribers
        if (OnMapLoadCallBack != null)
        {
            //if it does trigger the event with params (or without if you dont define any above)
            OnMapLoadCallBack(mapSize, currentMap);
        }
    }


}

public class ActorManager : MonoBehaviour
{

    public int teams = 2;
    public int teamMembers = 1;
    public GameObject toonPrefab;
    public GameObject aiPrefab;
    public List<Team> teamsList = new List<Team>();
    public Vector3 teamOneSpawn = new Vector3(0, 0, 0);
    public Vector3 teamTwoSpawn = new Vector3(0, 0, 0);
    //I'm using unity and you always want to be sure to subscribe and unsubscribe from events otherwise they will cause memory leaks, I'm simply doing it when the gameobject is instantiated and when it's disabled/removed
    void OnEnable()
    {
        //here I'm subscribing to the event and assigning the function Init to fire when the event is triggered, notice again the parameters must match the delegate you define
        EventManager.OnMapLoadCallBack += Init;
    }

    void OnDisable()
    {
        //unsubscribing here
        EventManager.OnMapLoadCallBack -= Init;
    }

    void Init(Vector3 mapSize, Dictionary<Vector3, Tile> currentMap)
    {
        CreateTeams(mapSize);
    }

public class MapManager : MonoBehaviour
{
    public void GenerateMap(BiomeData biome)
    {
        CreateFloor(biome);
        AddDecorations(biome);
        AddTrapTiles(biome);
        AddEnviroment(biome);

        //this is where I call the event from the Map Manager to let the Actor Manager know the map has finished loading
        EventManager.TriggerOnMapLoad(mapSize, currentMap);
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.