The Most Important Thing I Learned This Game Jam

Event Handlers are VERY useful!

Background Flavor...

I've been programming my own games for the past ~5 years. I have six games published on my itch.io page, and countless projects I've sunk hours of development into that never saw the light of day. None of these projects I had worked on make use of custom event handlers - nor was I aware at the time what event handlers even are. Yet, looking back, I can find tons of places where they would have make my code cleaner and my life easier.

How I Used To Do Things...

Here's a rough example of how I would have managed character functionality in the past.

``` public class Character { bool movingForward; CharacterAudio audio; CharacterMovement movement;

void ManageCharacter()
{
    if(movingForward)
    {
        audio.Play(...);
        movement.MoveForward(...);
    }
}

// ...

} ```

Why Do I Not Like This?

In software development, one of the best practices you can ever learn is to keep your systems decoupled. IE: We want our systems to not be unnecesarily dependent on eachother to perform their functionality.

In the example above, I outline an example Character class to handles working with CharacterAudio and CharacterMovement components. Now I'm gonna ask rhetorical questions... - What happens if I make a NPC using the Character class - but I don't want them to make noise when they walk? Can I remove the CharacterAudio component? - In the example above, we will error out if we remove the component. Our Character class is TIGHTLY COUPLED to its respective Character... components. - What if we add logic for checking if a component is null before using it? - We can go that route, but now we have to do that for EVERY component referenced in Character.

Why is our Character even referencing its components to begin with? Every time we create and add a new Character... component - we would need to add a new reference within the Character class and plug in the respective component function calls within ManageCharacter(). Inevitably, this class becomes bloated with a thousand references and the code becomes harder to work with and read...

Now this is where Event Handlers come in.

What are Event Handlers and Why Should I Use Them

Below is an example of how I would use event handlers to improve our code (I used Unity Actions here, but you can use your preferred method of event handlers).

Essentially, the code below shows each Character... component gets a reference to the respective main Character component - and subscribes its functionality to the respective OnMoveForwardAction event.

``` using UnityEngine.Events;

public class Character { public UnityAction OnMoveForwardAction;

public void MoveForward()
{
    OnMoveForwardAction.Invoke();
}

}

[RequireComponent(typeof(Character))] // Ensures CharacterAudio's GameObject has a Character component public class CharacterAudio { public void OnEnable() { Character c = GetComponent(); c.OnMoveForwardAction += PlayWalkingAudio; }

public void OnDisable()
{
    Character c = GetComponent<Character>();
    c.OnMoveForwardAction -= PlayWalkingAudio;
}

public void PlayWalkingAudio()
{
    ...
}

}

[RequireComponent(typeof(Character))] // Ensures CharacterMovement's GameObject has a Character component public class CharacterMovement { public void OnEnable() { Character c = GetComponent(); c.OnMoveForwardAction += MoveForward; }

public void OnDisable()
{
    Character c = GetComponent<Character>();
    c.OnMoveForwardAction -= MoveForward;
}

public void MoveForward()
{
    ...
}

} ```

The Character class is unaware of who is subscribed, and simply alerts all subscribers for when the MoveForward event occurs. This successfully decouples the Character class from all subcomponents and cleanly resolves the issues discussed above. It is fine for the subcomponents to be coupled to the Character class - as this assumption has to be made for defining subcomponent functionality.

The best part of this paradigm is shown when we want to create a new subcomponent. For example, if we want a CharacterHealthOnMove component (like some special in-game buff), then we can accomplish this with the following steps 1. Create the CharacterHealthOnMove class. 2. Define the functionality for gaining health within the class in a function. 3. Subscribe the above function to the OnMoveForwardAction event.

Conclusion

Check out event handlers if you haven't used them before. It'll make it easier to organize, write, and extend your code going forward. I heavily utilized events when coding my submission BIG BLOCK MODE for this jam.

Near the end of the jam, I had events for stuff like blocks falling, game loss, row cleared, etc - and it took literal seconds for me to subscribe audio functionality to these respective events and have it all working within the game. EZ PZ.

Note

This is my first time writing an informative blog post like this. Sorry if it sucked. I'm open to any feedback: positive or negative. Also feel free to check out our submission if you're interested.

THANKS!