- Home /
Are static events bad in this case?
I have a GameManager
class which handles the start of the level, pausing, end of the level, etc.. I also have gameobjects and any of them can trigger the level to end. I don't want them to have a reference to the GameManager
object beacuse I want to be able to test them out of the "level context". So basically just for example drag them to an empty scene and test their movement or anything.
So my instinct is that I create a static event in this class. Why static? Well, because this way the GameManager
doesn't need to know each instance of those objects when subscribing to the event. That object just fires the event not worrying about wheter the game manager is existing or not and the game manager can listen to it. It does not matter who fired the event.
I think I like the idea but most answers and forum posts about Unity shout that "static events are bad!" though they never made the reason clear to me. Is this true in this case? Is there a "better" approach?
Do the game objects triggering the end of the level have a component in common?
Do they get instantiated dynamically, are they already present in the scene or is it a mix of both?
They do, the event would be created in that common component.
It is a mix of both.
Answer by Bodrp · Apr 30, 2017 at 09:24 PM
Someone gave what I think is a good answer to why static events are bad.
I believe your reflex to make you game objects independant of your GameManager
is a good thing. Be it a monster, a coin or a player, it should not need a GameLevel to exist. As you said, it should be able to exist on its own.
I had a problem much alike your own once. What I did was this:
In my
GameManager
equivalent (`GameController`), I calledGameObject.FindObjectsOfType<ThatComponent>()
to first register on every existingThatComponent
'sOnDeath
event.The
GameController
was (not directly) in charge of the instantiation of allThatComponent
s. Every time it would instantiate one, it would register on itOnDeath
event.
In the end, it worked fine. I could instantiate multiple ThatComponents
a second without lag and none of them knew anything about the GameController
, which made them usable in other games / subgames without any adjustment or unexpected behaviour. And yes, I happen to take stuff from one game to the next, because I made it easy.
My opinion: I like to build software architecture as a military chain of commands. The GameController
gives orders and reacts how he pleases to events. No one tells the GameController
what to do, because that would mean he has lost control.
Regarding the concerns on the link, it is easier to handle subscribing/unsubscribing events in Unity as using Awake() and OnDestroy() is a pro$$anonymous$$ent part of Unity workflow.
Answer by Ruri-Dev · Apr 30, 2017 at 06:30 PM
It's not that they're bad, there are a lot of classes in Unity that have very convenient static properties and methods. Problem comes when we programmers, sometimes try approaches like using singletons or statics in a way such that scalability and and code flow become compromised.
That being said, there are a lot of approaches for instances to communicate without knowing each other. Here are my two recommendations:
A good messenger event system, here is the CSharpMessenger_Extended from the Unify community, you can download it and use it for your project, there are instructions of how to use it on the same page. After becoming used to it you can have a good read at the code, you'll learn a lot of delegates and become able to program a robust system yourself.
Use the GameObject.FindObjectOfType<GameManager> () method from within your game objects. It is know as a heavy method but if you use it only for a few tests, I think it'll be fine.
Answer by itchyOwl · Feb 05, 2018 at 12:22 PM
Static events are not bad, but the trick with them is they won't get garbage collected. They are always there. This may cause issues for example when the scene is reload/changed and subscribers fail to unsubscribe from the static event. When you use static events, you should make sure to reset the event when it needs to be reset (just reassign it).
You can also use patterns like singleton or event manager, but these are not good solutions for every case. Also be aware of the side effects: If you use singleton, you need one and only one instance of GameManager at a time. If you use an event manager, you lose some of the encapsulation and create overhead for your coding (and you may lose the type-safety, if you rely on strings).
Answer by guneyozsan · Aug 14, 2018 at 11:15 AM
The most important concern when choosing between a static or non-static event is that you cannot selectively address subscribers when you have multiple event source instances with static events.
So static events are better when you have a singleton-like global event sources (like GameManager
in your case).
public class GameManager
{
// I'm a singleton.
public static event Action GameStarted;
public static event Action GamePaused;
}
Or, it also works backwards from multiple sources to singleton-like listeners. If you want your GameManager
to learn about what happens to all instances of a class without referencing each of them (like death of any enemy), you can make it easier implementing static events to that class with multiple enemies.
public class GameManager
{
private bodyCount = 0;
private void Awake()
{
Enemy.Die += IncreaseBodyCount;
}
private void OnDestroy()
{
Enemy.Die -= IncreaseBodyCount;
}
private void IncreaseBodyCount(GameObject deadEnemy)
{
bodyCount++;
}
}
public abstract class Enemy : MonoBehavior
{
public static event Action Die;
protected void OnDie()
{
if (Die != null) Die(this);
}
}
public class Minion : Enemy {
void Die
{
base.OnDie();
}
}
public class Boss : Enemy
{
void Die
{
base.OnDie();
}
}
Another point is, you don't even need an instance to raise a static event, which makes them useful when you need such functionality with static methods.
One other concern is it is harder to shut down, or find the source of a static event source. You may have difficulties debugging an unexpected behavior.
Your answer
![](https://koobas.hobune.stream/wayback/20220612121009im_/https://answers.unity.com/themes/thub/images/avi.jpg)