- Home /
[Unity5] Performance and functions
Hi all,
I've got a question about a thing, I try to explain it:
I implemented an ingame time mechanic so that every "x" seconds I count a day change and every "y" days I change the season. As example: every 24 seconds pass a day and every 50 days I change the season; (24*50 = 1200 seconds from the season-change to the next one)
In the scene I've got 1000+ objects that every season-change has to do a function (as example "DoSomething") and atm this is doing in the Update() of each object: in the Update() I check the season change and if this happen I call the function DoSomething.
This mean that every Update() 1000+ objects do an "if" that will be true only every 1200 seconds.
I think that I can do a better thing. like when the season change I can call the DoSomething function of each object: is it true? It means that every 1200 seconds I've to cycle all the childs of my scene, check if the child is a particular child and then call the function.
What do you think about this?
Answer by Cryptomane · Sep 06, 2015 at 05:39 PM
Why don't you just have the season-dependent code become a bunch of event handlers?
In their Start() you just register the handlers on the class that keeps the season info, so that every season change you can send the event and every object will be notified at once with no season check at all.
Wow: thanks for the information, the event handling is really good!
I've a question: - I added this code on the InGameDateTime script: public static event onSeasonChangeHandler onSeasonChange; public delegate void onSeasonChangeHandler(float season); - in the Element script I added: IngameDateTime.onSeasonChange += new IngameDateTime.onSeasonChangeHandler(onSeasonUpdate); - in the Element script I added: void onSeasonUpdate(float season) { do something }
And all works very well. Now I've got a question about static and non static declaration (this event handling thing make me a little mad :P): In the example I put the inGameDateTime.cs as a component in a single object. Cause the static declaration every class/variable in the InGameDateTime class are accessible by the "InGameDateTime.variableORclass". If I want to declare multiple instance of InGameDateTime I've to change the changeseason from static to dynamic and register a class with this: GameObject.Find("NameOfTheObjectThatContainInGameDateTime").getComponent().onSeasonChange += new GameObject.Find("NameOfTheObjectThatContainInGameDateTime").getComponent().onSeasonChangeHandler(onSeasonUpdate);
I'm right?
Sorry for the bad english or example but it's not a good day for me to think and write :P
Answer by wibble82 · Sep 06, 2015 at 01:16 PM
Certainly iterating over all the objects every 1200 seconds is going to be substantially more efficient. If you can record the list of objects in advance (rather than search the scene) it'll be mildy faster.
Ultimately though if you have 1000 objects that need to change, in some way you have to do some work per object. You could start messing with coroutines that update once every 1200 seconds, but you'd still eventually hit the problem that a load of work happened.
So short answer - yes, you're right. Use 'FindObjectsOfType' to find all objects with your component on, then iterate over them and call your function on each one.
Answer by Pharan · Sep 06, 2015 at 07:26 PM
Yes. Your later idea is better.
When the object is created, have it register itself with a manager-type object in the scene which adds it to a list/collection. That manager object should also be the one that determines the season, or should be accessible to the script that manages the season. And when the season changes, it should "inform" all the registered objects by calling a method on them.
This pattern and recommendation is mentioned in a Unity video: https://www.youtube.com/watch?v=Ozc_hXzp_KU
It's simpler but slower to use FindObjectsOfType. It's slow because it uses reflection, and on 1000 objects too. But if you're just prototyping and testing a mechanic quick and dirty, that way might serve you well enough until it's time to improve performance.
@Cryptomane's recommendation also works. Instead of the script being added to a list, the "season manager" can have a public "SeasonChanged" event that each of those 1000 objects can subscribe to. And when the season changes, the "season manager" can call SeasonChanged(whateverdata you want to pass). In this case, the child will know information about itself (and you can pass information to it about the season), and it can react accordingly.
Learn about the syntax of C# events and event handlers here: https://unity3d.com/learn/tutorials/modules/intermediate/scripting/events
Which solution you choose depends on how you want to think about the objects. Is it easier to think about them when they're passive and just managed centrally? Or do they manage and mutate themselves and are just informed? Which script is better equipped/has the data to cleanly perform the needed operations without the code turning into a mess?