How do you manage without nested prefabs ?

Hi guys,

I was wondering how do you manage without nested prefabs when you want to reuse components inside another components ? This is something I often struggle against and I can’t figure out what would be the best way to do. Do you have methods or techniques or whatever ?

Thanks

I assume “components” means “child objects”?

I simply make one prefab for each kind of object I need. That includes child objects. I helped one project that used prefab evolution, which adds support for nested prefabs, but in the end it was not really worth it. It is one of the things you think you need, but in the end they turn out to be less useful than you thought. With nested prefabs you’ll end up thinking “at which level of hierarchy should I introduce the change? Should it be within child prefab? Or within this object’s prefab?”, which ends up wasting your time. For differences in configuration, you could use scriptable objects, links to other prefabs, etc.

2 Likes

So you want to instantiate a GameObject (A) which is a child of a prefabed GameObject (B) ?

You could for example have that child GameObject (A) as a separate prefab, which you can use on it’s own, and have a component on the original GameObject (B) that wold instantiate GameObject (A) as it’s child.

You could use an instancing script that on Awake() creates and sets the nested prefab elements of base/root prefabs.

But you would probably need it to run in the Editor as well, so if you build a level with nested prefabs it will dynamically change all prefab elements.

I’m surprised there should be some simple scripts on the wiki/forum to help with this, there are probably asset store solutions to the problem.

Ideally Unity would introduce a prefab library/database system that works across projects and handles nesting as it’s just linking to another data entry.

I use prefabs at the lowest level. Everything else I build via code at runtime.

1 Like

The challenge is that while it does indeed sound simple, the implementation gets pretty complex pretty fast. Particularly when it comes to local variants. I’ve built a couple of solutions to this for different projects, and both times the edge cases got almost overwhelming. It’s not too difficult if you keep it to a single level or work in a narrow band (like just UI), but multiple levels can get ugly fast. Not to mention the dependencies it creates, which can lead unexpected results on large or multiple developer projects.

I’m with @Kiwasi , using base or core prefabs and dealing with rest programmatically.

1 Like

hey @zombiegorilla , what sort of general approach or design patterns, if any, do you take with dependencies? I often get caught with which gameobjects/scripts get instantiated before or after others, and how best to handle Awake/Enable/Start (and Disable/Destroy) events in the right order so code can make connections between objects. I have used different script ordering for various components so they’re awake and ready to go, and have used other rigs with custom events here and there for setup and teardown. I know there’s some dependency injection libraries around on GitHub but they mostly deal with gameobjects in the scene at startup and don’t deal much or at all with runtime instantiations.

Managers being destroyed before the things they manage can get messy during various destroys as well (ie. destroying normally during runtime vs destroying due to end of scene or stopping the player). I always end up with what feels like a bandaid on a few scripts, having to check what the app state is via an app singleton or do self-checks for OnApplicationQuit etc. to avoid a few null reference exceptions on the way out the door at quit time.

Some projects start with one technique and fall into using others as things get more complex, more or less connected or observed, or managed by managers.

Do you generally prefer runtime code-based connections, or inspector-based references between scripts on gameobjects/prefabs, or a mixture?

Just wondering if I’m missing some general setup and teardown magic somewhere to make things easier… :slight_smile:

Could you provide an example as I just don’t get how data links or prefabs can get so complex, or why Unity is taking so long to solve the nested prefab problem, so maybe I don’t understand the problem?

Technically, it isn’t overly difficult, it is more about design and expected behaviour and implementation. Once you start nesting you create nested dependencies that can conditionally change. Take UI. Say you have a “blue_panel” ,“shop_window”, “small_button” and a “standard_title” as nested prefabs.

So you create a layout that has a that has a shop (for example). You start with the shop_window, in it you place blue_panel, in that you place a standard_title, and a blue_panel with a table layout. In that table you use the blue_panel 50 times. In that panel you use the standard_title and two more blue_panel, one of which has 2-3 instances of the small_button with local changes (text probably). Now you have several categories, so you dupe store panel several times and put in tab section, which is the blue_panel with some tabs sitting on top, made of small_buttons.

Ok, so now several questions arise. Say on the third panel, the fourth pane, you want to make one of buttons green.
So you change the background to green. So what are you changing?

Our layout looks something like this:

shop_window (swords)
    blue_panel (main)
        standard_title
        small_button (tab 1)
        small_button (tab 2)
        <...>
        small_button (tab 10)
        blue_panel (for tabbed content - fire swords)
            blue_panel (content holder)
                blue_panel (base item 1)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                blue_panel (base item 2)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                <...>
                blue_panel (base item 20)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                      
        blue_panel (for tabbed content - frost swords)
            blue_panel (content holder)
                blue_panel (base item 1)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                blue_panel (base item 2)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                <...>
                blue_panel (base item 20)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                <...>
            blue_panel (for tabbed content - holy swords)
                blue_panel (content holder)
                    blue_panel (base item 1)
                        standard_title
                        blue_panel (item image)
                        blue_panel (item stats)
                        blue_panel (buttons)
                            small_button (buy)
                            small_button (sell)
                            small_button (info)
                    blue_panel (base item 2)
                        standard_title
                        blue_panel (item image)
                        blue_panel (item stats)
                        blue_panel (buttons)
                            small_button (buy)
                            small_button (sell)   <---- lets change this one
                            small_button (info)
                    <...>
                    blue_panel (base item 20)
                        standard_title
                        blue_panel (item image)
                        blue_panel (item stats)
                        blue_panel (buttons)
                            small_button (buy)
                            small_button (sell)
                            small_button (info)
                    <...>
shop_window (swords)
    blue_panel (main)
        standard_title
        small_button (tab 1)
        small_button (tab 2)
        <...>
        small_button (tab 10)
        blue_panel (for tabbed content - fire swords)
            blue_panel (content holder)
                blue_panel (base item 1)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                blue_panel (base item 2)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                <...>
                blue_panel (base item 20)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                  
        blue_panel (for tabbed content - frost swords)
            blue_panel (content holder)
                blue_panel (base item 1)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                blue_panel (base item 2)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                <...>
                blue_panel (base item 20)
                    standard_title
                    blue_panel (item image)
                    blue_panel (item stats)
                    blue_panel (buttons)
                        small_button (buy)
                        small_button (sell)
                        small_button (info)
                <...>
            blue_panel (for tabbed content - holy swords)
                blue_panel (content holder)
                    blue_panel (base item 1)
                        standard_title
                        blue_panel (item image)
                        blue_panel (item stats)
                        blue_panel (buttons)
                            small_button (buy)
                            small_button (sell)
                            small_button (info)
                    blue_panel (base item 2)
                        standard_title
                        blue_panel (item image)
                        blue_panel (item stats)
                        blue_panel (buttons)
                            small_button (buy)
                            small_button (sell)
                            small_button (info)
                    <...>
                    blue_panel (base item 20)
                        standard_title
                        blue_panel (item image)
                        blue_panel (item stats)
                        blue_panel (buttons)
                            small_button (buy)
                            small_button (sell)
                            small_button (info)
                    <...>

So we want to make that one button be a trade instead of a sell (or whatever). So we go in and change that text. What did we change locally? was it that button? Or was it the panel containing the buttons. or the panel containing the item? The panel above that (content)? Or the item panel? Or the panel containing the items? Or the panel that is the tabbed content? Or top level panel? Or the shop_window? What if I go midway in at the tabbed content panel and hit revert? Is that affected or not? More importantly, what is the expectation? What is a local change when have a nested stack? If I hit revert does it wipe all its content, because the prefab itself has no content. Who actually “owns” that local change?

In fact, I would bet that if anyone here answered that question… “what would you expect to happen if you revert something in the middle?”… you would probably get several different answers.

The concepts are hard to manage as well as expectations. Any solution presents a unexpected result for some group of folks. Which boils down to giving users the ability to do massive (hidden) destruction to their work with button click. Most new users don’t use vcs, most seem to jump in and do the most insane things. From a UI/UX standpoint, making this functionally useful, it comes with a heavy educational overhead. Despite that fact that most people believe that it would be simple solution and usage. It is safe bet that any design that unity implements (if ever) will endlessly confuse and anger many users. Mostly because no one ever reads the docs, and tend to “expect” things to work the way they have in their head regardless of the docs. Either that or they would have to severely limit the scope and maybe the depth, which again would freak people out.

For me, that wasn’t a problem. I knew exactly how my users were going to use it, and told them up front what the pain points were, and could tailor it to fit their needs, and quite simply, they were extremely advanced users to start with. Plus, I was within yelling (throwing) distance if things went wrong. Unity would be unleashing it on millions of users many with virtually no skills, and never read the docs.

On top of all that, it would really encourage bad design with deeply nested dependencies. Nesting obviously isn’t a blocker. It is clear that people often request things be “easier”, but often that comes at a cost, And many times the solution is to look at the bigger picture (design) and just plan a logical workflow that balances flexibility with dependencies and spf. Sure it is nice to be able to change everything at the drop of a hat (yes, sometimes it is necessary), but planning and prototyping are the quickest ways to avoid over complicating and unnecessary pivoting. The more you plan, the less escape hatches you have to build.

3 Likes

Generally I just keep dependencies to a bare minimum. I almost never have more than a one script on an object (other than standard components). I typically instantiate everything in the scene. Usually for that stuff I have an Init() class that I call for setup and injection (rarely). For managers I usually have a Game controller and it will initialize other controllers as required. I try to keep cross talk to a minimum, and rely on delegates rather than directly accessing other classes.

@zombiegorilla Thanks for the quick overview :slight_smile: What sort of pattern do you use for the delegates?