I’m writing a new plugin/Unity Package, with the intention being that other developers use it.
As part of my package’s logic I want to instantiate a prefab. I’m trying to understand what would be the best-practice way for me to do this?
Ideally I would use something like the addressable system, but this seems problematic because:
I can’t assume that devs using my package will have addressables in their project (or want to download it as a dependency of my package)
Since my asset will need to be marked as addressable and placed into a certain addressable group, it certainly won’t work “out of the box”.
I’m afraid what this leaves me with is loading the prefab from the Resources folder, which is considered bad practice. However, it’s the only viable option I see.
Would love for you guys to share your insight with me. Thank you.
But why do you a) need a prefab and b) why do you need to instantiate it?
You could as well create a new GameObject, add the required components to it, and initialize them with the necessary data. Done. This is the script-only solution.
Perhaps you don’t even need to instantiate a prefab. Consider an editor script or a static class, perhaps there’s no need to use a GameObject in the scene in the first place?
Though for either you can always provide the option for the user to provide their own implementation for reaching the desired objects that suits their project specifics. I did this in a recent internal tool and it ended up being the secret sauce to make it as flexible as I needed.
To answer your question - My package includes a comprehensive wrapper for an in-app-purchasing flow, including the bells and whistles of showing different overlays on purchase success/failure.
Of course, these overlays are prefabs with textures, etc. They’re not a simple GameObject running a MonoBehavior.
I know that I could technically have my package’s users supply the GameObjects via dependency injection, but I kind of want to make the integration experience as seamless as possible for them which is why I’m trying to avoid that.
Allowing devs to provide their own implementation would certainly work (In my mind they would pass the GameObject / a class that loads the GameObject via dependency injection), but I fear that this would complicate the integration process of the developers. I want to try and keep things as plug-and-play as possible for them, which is why I’m checking options for us loading assets directly, without the devs’ intervention.
A thought: A Build Pre-Process that adds the prefab to the boot scene (the first scene in the list) with an option to override which scene the prefab is embedded in (to allow people to optimize if they don’t want the textures as part of the initial boot flow). No integration required. You could also allow users to customize the prefab (allowing them to specify a prefab variant) if you wanted.
Addressables is a wrapper for AssetBundles.
Even without using Addressables, you can create AssetBundles during the build pre-process and load them at any desired timing.
GarethFalkingham, Arithmetica - these are wonderful suggestions.
Indeed, it seems plausible that storing my prefab(s) as asset bundle(s) during the prebuild step and fetching them in runtime would make a performant, out-of-the-box solution for my users.
Of course, it will take some time to develop as ideally I won’t want to bundle everything into one bundle, so I’ll have to make some system to divide them logically, but the idea is sound.
I would try to stick to basic Unity concepts as much as possible and create a config Scriptable Object that holds all the references you need. You then bundle a default asset of it in your package and let users copy it to set their own configuration and references.
The user then needs to reference the config asset somehow. You can provide an API where the asset is just a user-supplied argument, to be most flexible, but you can also make it easier for users by bundling prefabs or demo scenes that already reference the default asset. They can then just swap out the config asset to customize the plugin.
This avoids using any custom setup that the user would have to learn and adapt to their build process. This allows all assets to be built-in, loaded through Addressables or loaded through any custom asset bundle process the user might have.