Advertisement

Unity - Observer pattern or conditional logic in Update method for controlling UX visibility

Started by March 22, 2020 05:15 PM
2 comments, last by lougv22 4 years, 8 months ago

So i have a bit of a conundrum at the moment. I have a piece of UX (in a Canvas panel) that needs to be shown or hidden, depending on some condition in gameplay logic. Up until now I've been doing this with conditional logic in the Update method of a MonoBehaviour, i.e. something like this:

public GameObject uxPanel;
 
void Update()
{
    if (uxShowCondition)
    {
        uxPanel.gameObject.SetActive(true);
    }
    else
    {
        uxPanel.gameObject.SetActive(false);
    }
}

Simple and it works. The problem is that this conditional logic gets called every single frame. I know Unity is optimized for running these Update methods every frame and all that, but still, it seems like an overhead.

An alternative to the above, that I discovered recently, is to trigger an event in the gameplay logic and then show/hide the UX in question in a class that handles said event, using the Observer pattern. That would look like this:

An abstract subject class, i.e. a template for something that is being observed:

public abstract class Subject
{
    public event Action OnGameplayEvent;
 
    public virtual void Trigger()
    {
        OnGameplayEvent?.Invoke();
    }
}

A concrete implementation of the abstract class above:

public class MySubject : Subject
{
    public override void Trigger()
    {
        base.Trigger();
    }
}

An observer class that listens for events from a subject class:

public class MyObserver : MonoBehaviour
{
    private Subject mySubject;
 
    void Start()
    {
        mySubject.OnGameplayEvent += Subject_OnGameplayEvent;
    }
 
    private void Subject_OnGameplayEvent()
    {
        // Do something here to show or hide the UX panel
    }
}

And this is the gameplay class that triggers the event. I am skipping constructors and initializers for the sake of brevity:

public class MyGameplayClass
{
    Subject mySubject;
 
    void GameplayLogic()
    {
        ...............
        ...............
 
        mySubject.Trigger();
    }
}

So my question is, which of the two methods above is better for showing and hiding a piece of UX in a Canvas panel? The first one is definitely simpler, but it runs every frame, which may or may not be a problem. I am not sure about that. The second is more complex, but it only runs one time, i.e. when the gameplay logic triggers the event.

If you simply need to do something if something different happens, then using events might be the way to go. They are fired once and if doing things right, stored until a consumer uses them so you don't have to worry about initialization order.

Keeping a check up and running might be no problem for single objects but if you have more UI and objects checking conditions, this may become a performance impact over time.

If you have complex conditions, maybe reactive programming is something for you. This is events 2.0 where you have the chance to chain different events into a single condition to display your UI, in the style of a state mashine. Don't use the Microsoft one, it is quite too heavy for games but you can for sure have your own implementation that is a little more lightweight.

I wrote my own one in less than 10 files and 2000 lines of code to be used in my non-game UI framework to replace the MVVM pattern

Advertisement

Thank you! I am leaning towards using events as well. This is a check for a single UX element now, but it has the potential to grow and have a significant performance impact, if I do the check every frame in an Update method.

This topic is closed to new replies.

Advertisement