Does your game or application in Unity use a lot of update loops that slow down performance? No need to install plug-ins or special packages, greatly increase performance for free with an update publisher in Unity. It makes you wonder why this isn’t a standard feature anyway (but that goes for a lot of things in Unity).
We’re basically going to make a SINGLE type of update loop for your entire project! As you can imagine, this will lead to a massive performance boost for your game, especially if you use a lot of scripts that implement any kind of update loop.
Understanding the issue:
What's the problem? Let’s address the issue of update loops in the first place (like Update
, FixedUpdate
, or LateUpdate
) in Unity, because it's more complex than you may think.
When you put code in an update loop to move a game object, like transform.position += new Vector3(0, 0, 1) * Time.deltaTime;
, under the hood a lot of different checks are being performed before the update loop is even validated and started. First, Unity checks if the object hasn’t been destroyed yet, then there's checks if the requirements have been met to be active at all. Even when it passes all these checks, Unity still needs to confirm that its own update method is functioning properly.
So basically, even BEFORE Unity runs the actual update loop, it’s doing all these involved computations, behavior iterations, call validations, preparing to invoke the method, verifying all the arguments and then finally running the little piece of code you wrote (which hardly is a performance issue compared to the aforementioned. Yes, this even happens with empty update methods accidentally left behind in scripts!
This slows down your project tremendously, and gets worse the more update loops you have!
When you have lots of objects that implement any update loop in Unity, you can see the problem if it needs to perform these under the hood checks constantly.
Come on!
But what can we do about it? This is yet another case where the Observer Design Pattern comes in!
The Solution:
First, we’re going to make an UpdatePublisher
that lives in the scene on its own GameObject. It holds the ONLY Update
method in the game, and it’ll notify all the other listeners when it’s called.
The observer itself is an interface, we’ll call it IUpdateObserver
:
public interface IUpdateObserver
{
void ObservedUpdate();
}
Now we’re going to create the UpdatePublisher
. This script is responsible for routing the loops, and since has a static method, it can be implemented globally in your project.
using System.Collections.Generic;
using UnityEngine;
public class UpdatePublisher : MonoBehaviour
{
private static List<IUpdateObserver> _observers = new List<IUpdateObserver>();
private static List<IUpdateObserver> _pendingObservers = new List<IUpdateObserver>();
private static int _currentIndex;
private void Update()
{
for (_currentIndex = _observers.Count - 1; _currentIndex >= 0; _currentIndex--)
{
_observers[_currentIndex].ObservedUpdate();
}
_observers.AddRange(_pendingObservers);
_pendingObservers.Clear();
}
public static void SubscribeObserver(IUpdateObserver observer)
{
if (!_pendingObservers.Contains(observer))
_pendingObservers.Add(observer);
}
public static void UnsubscribeObserver(IUpdateObserver observer)
{
_observers.Remove(observer);
}
}
We need to add the _pendingObservers check for protection in case something else (accidentally) modifies the observers list.
Alright, now we can use this on any object in our scene! For example:
using UnityEngine;
public class MoveObject : MonoBehaviour, IUpdateObserver
{
private void OnEnable()
{
UpdatePublisher.SubscribeObserver(this);
}
private void OnDisable()
{
UpdatePublisher.UnsubscribeObserver(this);
}
public void ObservedUpdate()
{
transform.position += new Vector3(0, 0, 1) * Time.deltaTime;
}
}
And that’s it! Whether we use it on one, two or a thousand game objects, it only needs 1(!) update loop! This is how we greatly increase performance for free with an update publisher in Unity! How cool is that?!
Performance benefits aren't the only positive thing here, even non-monobehavior classes can register for update calls as well! It's also a single entry point system as from now on all of the logic goes through one point, making it easier to debug.
This UpdatePublisher system for Unity can easily be extended by creating a system for FixedUpdate or LateUpdate for instance.
Want to know more ways to optimize your Unity game or application?
I wrote another article about 11 more ways to optimize performance in Unity.
~Happy coding!
No comments:
Post a Comment