Skip to content

Add pause button as C# events reference #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 2, 2023

Conversation

nucleartide
Copy link
Owner

@nucleartide nucleartide commented Mar 1, 2023

JIRA Ticket

Sorry folks, this is internal to my Notion workspace!

https://www.notion.so/nucleartide/Mechanics-Learning-Best-Practices-93c15ca344744f33a767236172efd035?pvs=4

Changelog

Provide a bulleted list of changes that were made in this pull request.

  • Add controls for toggling the Pause menu
  • Expose an OnPauseAction in our GameInput so that other GameObjects can listen on pause events
  • Add a PauseManager for managing the pause state. Currently, all it will do is log the current state.

How it works

Explain what you did, how you did it, and why you did it. Also any lessons that might be useful to others.

(Note to self: it's easiest to do a stream-of-consciousness writeup of what you did.)

Sooner rather than later, any game project will require communication between different GameObjects, MonoBehaviours, and ScriptableObjects.

And if you don’t manage this complexity correctly, it’ll come back and bite you in the behind in the form of long nights of debugging and self-hatred.

A popular pattern I’ve seen to facilitate communication is through C# delegates and events.

But what are they exactly?

Delegates

After reading the conceptual guide in the Microsoft documentation, here are a few notable points:

  • It’s a function that you can assign to a variable. That’s all it is. Seriously. Put all the verbiage aside for a moment. In an oversimplified way, it’s like a const namedFunction = function () { /* … */ } in JavaScript.
  • Use the Action, Func, and Predicate types to avoid declaring new types for delegates. The C# language has you covered. You can then define type aliases, such as using MyAlias = Action<int> for example.
  • Invoke delegates with ? and Invoke. Delegates may be null, so unless you can guarantee the presence of a delegate, you should invoke delegates with SomeDelegate?.Invoke(…).
  • You can assign multiple functions to the same delegate. A contrived example to demonstrate the syntax:
    public Action<int> IncrementHealthAction = PickUpItem + IncrementHealth;
    
    private void PickUpItem(int health) { /* ... */ }
    
    private void IncrementHealth(int health) { /* ... */ }

The difference between delegates and events

However, you may be confused about the difference between delegate and event — some examples:

public event EventHandler Progress;

Progress?.Invoke(this, new FileListArgs(file));

EventHandler onProgress = (sender, eventArgs) =>Console.WriteLine(eventArgs.FoundFile);

fileLister.Progress += onProgress;

fileLister.Progress -= onProgress;

What gives? It seems like they both do the same thing, and the docs even mention that event is implemented using delegate.

The docs explain that the event keyword is like how C# properties encapsulate underlying C# fields:

public event EventHandler DirectoryChanged
{
    add { _directoryChanged += value; }
    remove { _directoryChanged -= value; }
}

private EventHandler _directoryChanged;

That is, while you can add/remove delegates from DirectoryChanged, you can’t reassign DirectoryChanged entirely. You can’t write DirectoryChanged = someNewHandler and overwrite things, the C# compiler won’t allow it.

The event keyword, when thrown atop the standard EventHandler delegate, provides a form of encapsulation that you don’t get with the delegates alone.

That’s nice. So what can I do with this?

You can use this as a decoupling mechanism between different GameObjects and MonoBehaviours, of course!

Instead of hard-coding behavior in a PauseManager for when the Pause button is pressed, have other parts of your game listen for a Pause event, and handle within their respective classes.

You can see the Files changed tab that is part of this pull request for code examples, and also see the visual result of what I created below.

Quality Assurance

Take some screenshots as confirmation of quality assurance.

It's a simple P to Pause, and P to Unpause control:

Screenshot 2023-03-02 at 8 38 44 AM

@nucleartide nucleartide marked this pull request as ready for review March 2, 2023 14:41
@nucleartide nucleartide merged commit 86598f6 into master Mar 2, 2023
@nucleartide nucleartide deleted the jason/add-csharp-events-example branch March 2, 2023 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant