- Home /
Using static c# events
I have different scripts on whcih I have to check all the time if escape button then bla bla. It's not that bad but I think it could be handled much more easily with events. I am thinking of creating, I already have InputHandler class, full of static methods so I thought I could make a static or non static event(if non static, to use singleton) and eventually attach all the methods from all the different scripts that depend on the escape button to this event.(note if you ask why just not check in every script for escape button, simply because most of them don't have update functions, nor coroutines to wait for smth to happen)
My question is is there a better, easier alternative I can use to achieve same thing with unity?
P.S If my approach is the best, should I use singleton or just static event?
Answer by _foa · Mar 02, 2015 at 12:35 PM
Personally I would avoid static events and static things as much as possible, static is useful sometimes but if it is not handled correctly can cause many problems and hidden dependencies that can be hard to spot, also they make Unit Testing hard, very hard.
(You can find many resources on why static and Singletons are bad).
I would create an empty GameObject with a script that checks for the Escape key to be pressed and if it is pressed it will fire an Event.
Then in other scripts retrieve that empty GameObject, get the script by using GetComponent from the empty object reference and subscribe to its event handler for the Escape key.
Or you can do the other way around: you can Tag the GameObjects that should receive the Escape Key event, get them from the script that checks for the Escape key (attached to an empty GameObject) with FindGameObjectsWithTag.
Once you have found them, with GetComponent for each of the event receiver found, get the script with the correct method that should handle the event and invoke it when the escape key is pressed. (extra points if you make each script implement an interface with the method that should be executed).
Rember to do this components search at script startup and cache the results to increase performance.
Hope I've been clear enough, let me know !
@_foa So I read a little bit about the static topics and singeton and I see people say avoid them when possible. Since I can hardly come up with few examples when I can't avoid static or singleton, does this mean I should remove them everywhere I'm using them currently? Should I always search for a workaround when possible not to use them even if sometimes the code seems much more to write?
Anyway I understood everything very clearly, just since I haven't put into practice intefaces, I know how to use them and genrally when they are used but still I'm unable to put them into practice. So could you just write a simple example how is it going to be made with interfaces? I'd really like to try it out!
People who say avoid them at all costs are idiots. But it's fair to say they should only be used when they're the right tool for the job. They quite often are, but I agree that it doesn't sound like your situation is one of those.
Here is a small example with interfaces, keep in $$anonymous$$d that I don't have Unity on the computer I am working with right now so there might be some small issues, as soon as I get back to my computer I will update the comment to fix eventual errors.
Let's declare your interface:
public interface IHandleEscape$$anonymous$$ey
{
void HandleEscape$$anonymous$$ey();
}
Now let's see an hypotetical Escape$$anonymous$$eyListener script (a script that will invoke, for every GameObject, the HandleEscape$$anonymous$$ey()) Start method:
//Contains every registered listener interested in the Escape$$anonymous$$ey press.
private readonly List<IHandleEscape$$anonymous$$ey> registredListeners = new List<IHandleEscape$$anonymous$$ey>();
void Start()
{
GameObject[] listeners = GameObject.FindGameObjectsWithTag("Escape$$anonymous$$eyListener");
foreach(GameObject listener in listeners)
{
IHandleEscape$$anonymous$$ey handlerScript = listener.GetComponent<IHandleEscape$$anonymous$$ey>();
if (handlerScript != null)
{
registeredListeners.Add(handlerScript);
}
}
}
Now let's have a look at the Update method of the same script:
void Update()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Escape$$anonymous$$ey))
{
foreach(IHandleEscape$$anonymous$$ey listener in registeredListeners)
{
listener.HandleEscape$$anonymous$$ey();
}
}
}
Now the anatomy of an handler script for the Escape$$anonymous$$ey press event:
//Note the IHandleEscape$$anonymous$$ey next to the $$anonymous$$onoBehaviour
public class SampleScript : $$anonymous$$onoBehaviour, IHandleEscape$$anonymous$$ey {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void HandleEscape$$anonymous$$ey()
{
//Here goes thecode to run when the Escape$$anonymous$$ey is pressed.
}
}
Hope it helps, let me know of any errors.
When you want something to exist once and not per instance.
If you have a static event for example, this event is a static event and applies to all that use it. If the event is an instance event, meaning it exists after instantiating an object it belongs or is a member of, then each instance of an object have their own event handler and do not share.
You may ask why. I guess you could add custom code in the add/remove of the event subscription, that would depend on implementation.
Static generally is used sometimes in Unity for holding a single score that is accessible on the class, not the instance. A lot of people do this because it's easy, but it's generally because they don't understand how to gain access to an instance of an object and retain the reference through out the lifetime of a scene or game. Static has it's places, but it can be over used. It doesn't make you a bad person, it generally can make things obfuscated in terms of how you mean to implement something, but i suppose that's up to the observer.
I personally like the interface one.
Now let's talk about why:
It is more Object Oriented
The key listener is reponsible to invoke each event handler and not the other way around, which makes more sense (to me is the listener that should notify its subscribers about updates and this is also how many UI frameworks work, notably Windows Forms and Windows Presentation Foundation)
It is easly reusable: from Unity you just have to attach a script with the interface implementation and a tag without forcing you to add for each script that needs the escape key the code to search for the Game Component and the subscription to the event (this is not the script responsibility after all)
By using the interface oriented implementation you can couple less tightly your code.
Of course there are a few drawbacks with this method: for example you have to take care if any of your handler can be destroyed, because they are stored in the Escape$$anonymous$$eyListener script so you might get a NullReferenceException if they are destroyed.
But it is easly fixed by checking for null pointers and removing them before invoking each HandleEscape$$anonymous$$ey$$anonymous$$ethod.
But I can find more pros in the Interface oriented approach than the other one, hope I gave you enough information about my choice.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How to unsubscribe from InputSystem event properly 0 Answers
How to unsubscribe from InputSystem event properly 1 Answer
Getting the text from UIInput 1 Answer