#Circular dependencies with instantiating “manager” prefabs

1 messages · Page 1 of 1 (latest)

warped tusk
#

I have a bunch of “manager” objects. They have dependencies on each other. This poses a problem when I instantiate each object as a prefab as one object or another will inevitably not exist and so references can’t be set/initiation code can’t be run etc in awake or start for at least some such object. Is there an idiomatic solution to this issue? Should I put the “awake” and “start” stuff into non Unity functions and then just call them in my scene startup code? For example maybe every object has a “set refs” function and then an “init” function and the scene spawn code just instantiates each object, calls set refs on each object, and then init on each? Or am I making it too complicated and should I just make the scene have all these objects already in it so I don’t have to deal?

dense pasture
warped tusk
#

Doesn’t that not work if you instantiate prefabs because each instantiate calls both awake and start, so you still get start being called on one object before the next is even created - right?

dense pasture
#

Start isn't called right away iirc

warped tusk
#

Oh…

#

I see…. Alright…. I’ll mess around with it…

#

Thanks

dense pasture
#

Basically, everything goes in Start unless you're certain it exists. And these certain items would likely only be component instances on this object. For example, you'd assign the player's rigid body component in Awake (if not done so from the inspector, for whatever reasons) but would assign a reference to the manager in Start.

tawdry minnow
#

do all your managers derive from MonoBehaviour? if so, do they need to do that?

#

Managers generally shouldnt need all the lifecycle stuff that comes with MonoBehaviour. but it obviously depends on the specifics of that manager itself

warped tusk
#

I’ll have to see how much work it is to modify all this stuff and then how much of a payoff it would be to refactor…

#

Probably would pay to clean things up in the long run

tawdry minnow
#

depending what is in the managers, making some stuff static may make referencing easier

public class MyClass {

    public static MyClass CreateInstance() {
        return new MyClass();
    }
}```
Like in this class, I dont actually need to first locate a specific instance of MyClass to get the static method, I can access it like
```cs
public class SomeComponent : MonoBehaviour {
    void Start() {
        MyClass foo = MyClass.CreateInstance();
    }
}```
#

there are some caveats to using static, but it typically makes life easier when you just want to do something in a class when you dont really care much about the specific instance of that class

dense pasture
#

Managers in regards to Unity, often refer to Singleton instances of a Unity Object.

tawdry minnow
#

that is true, Singletons are good when its important you interact with a specific instance of the class, which can be helpful but it really depends on what the manager is or what its used for

#

but you have to actually construct the instance of the class before you can use them

#

whereas if the whole class was static, like this one, its accessible globally purely by writing InstanceHelper., it doesnt need to be constructed beforehand

public static class InstanceHelper {
    public static T LoadAndInstancePrefab<T>(string path) where T : UnityEngine.Object {
        T prefab = Resources.Load<T>(path);
        return Object.Instantiate(prefab) as T;
    }
}```
warped tusk
#

I kind of avoid static stuff for this purpose just bc it feels very brittle

#

They end up using a bunch of Unity things so I just make one GO per manager

dense pasture
#

I don't believe he's attempting to make a helper/utility tool but rather some manager that simply distributes easy to access referencing amongst several objects.

warped tusk
#

I had them just sitting in a scene but I want to make it more controllable so I’m moving to programmatic scene loading

#

But then I ran into the circular refs problem where it was sort of worked out before

#

And the cleanest solution seemed to just be avoid awake and start and have some special bootstrapper gameobject load all the managers, set refs, and call Init()

#

I was just wondering what other people do

dense pasture
#

There may be other purposes though but generally in game development with Unity, folks use managers to consolidate tedious referencing - anti pattern in normal programming (more room for error with dependency on a single object etc)

warped tusk
#

That’s kind of how I’m using them

#

One type of monobehqvior just references its own manager if anything

#

And then the managers can talk to each other if needed

#

So that everything isn’t maximally spaghetti

#

But it seems no matter what I do it’s just a game of hide the spaghetti

#

And the managers also control spawning and killing and other stuff like that

tawdry minnow
#

In general id say those look good, but perhaps if the problem youve got is that making sure theyre actually constructed correctly with the right references (this is also an issue ive faced before), a solution I have found to help is like this

void MakeInstance() {
    
    MyClass foo = InstanceHelper.LoadAndInstancePrefab<MyClass>(pathToResource);
    // foo.Awake() will be called immediately upon the prefab being loaded

    // data can be set in foo, this is called before foo.Start(), that will be called after MakeInstance() is finished
    foo.someNumber = 1f;
}```In that method, you could go and create 20 different managers, in any order you want, and make sure they all actually have the correct references
#

ive had trouble before where I created two classes and then its pain when their Start() almost have to be called at the same time

dense pasture
#

I'm guessing they've got several managers already in the scene and that they're discovering issues with race conditions.

tawdry minnow
#

yeah, it seems like it, its a tricky thing to fix

warped tusk
#

That’s basically it. I added more and more stuff and each thing I added was added in a way that made it work. But now that I’m trying to change that whole structure it seems it’s a bit brittle.

dense pasture
#

Just don't access anything not attached to this object in Awake. Meaning you can assign references to its components (including this instance for managers) and would configure your other members that rely on instances not attached to this object in Start etc

warped tusk
#

Alright I’ll try and do that

tawdry minnow
#

the biggest help would be to ensure that you know X class will need Y, design your code to guarantee Y has to exist first, make sure that certainty is there before you are allowed to construct X

#

for that id just do a condition like this, by default it will never be allowed to construct the manager

bool canCreate = false;
// determine the conditions needed
// before canCreate can be true
if(canCreate) {
    // safe to construct the manager now
}```