- Home /
Loading resources into a ScriptableObject instead of Resources.Load?
Greetings,
so the way you usually load resources dynamically from code is via putting them in a Resources folder and using Resources.Load
Another approach I used for a while in my personal project (as an experiment) that I'm now thinking (but not sure) of implementing at work, is the idea of using a ScriptableObject as a runtime asset/resource database and pre-loading assets into it at edit-time.
So it might look something like:
public class ResourceManager : ScriptableObject
{
public AudioClip[] Clips;
#if UNITY_EDITOR
void LoadAudioClips()
{
// use AssetDatabase.LoadAssetAtPath to load all clips from e.g. Assets/Audio into Clips'
}
#endif
}
Of course there'd be a custom editor for ResourceManager that exposes a button to load the necessary resources/assets (clips, prefabs, materials, etc)
And then the game code ask the ResourceManager to give it a certain clip to play (either by name, by an enum, by an int id etc). Which saves Resource.Load calls.
I'm just a bit hesitant to go full on-board and use this approach at work because I'm not a 100% sure that it offers vs just Resources.Load besides saving a couple Resources.Load calls. I mean, when you use Resources and accidentally put stuff there that you don't need they'll be included in the build, but same thing would happen if you put stuff you don't need in 'Audio' or 'Art' folder which gets loaded into ResourceManager at edit-time so the unused asset is included anyways, point being this approach doesn't guard against accidental inclusion of unused assets.
I'm just not sure if the value of this is worth it to invest time switching our pipeline into.
So my question is:
Do you think this is a good idea? yes/no, why?
Are there any other caveats or benefits using this approach vs Resources.Load that I'm not seeing/missing?
Do you have other cool ideas of
handling resources? if so, please
share if you could!I assume that the cost of calling Resource.Load on something that's already loaded is less than the cost of calling it the first time? (I assume the first time it loads it into memory, the second time it's just there so it grabs it - please correct me if I'm wrong)
Thanks
Answer by JoshuaMcKenzie · Feb 18, 2016 at 06:02 PM
I use this setup (at least one thats very similar to what you're describing) for data I either want to persist across levels or data I don't want to be specifically tied to a scene (cause that's one of the cool things about ScriptableObjects)
In my current game I use it to define different game modes, specifically difficulty modes. Each of our designers have their own game mode that they can create and mess with via an editor tool that I wrote (so if one designer is responsible for hard mode then he can build his own mode and playtest it while another designer focuses their normal mode). Even better, this sort of setup makes it really easy to to prepare a demo build and present.
My GameMode scriptableobject handles the overall progression of the game (what order the levels are played, what songs play on them, what techs are unlocked by which levels, and what and how many enemies spawn in each level). then when a player selects a difficulty on the main menu, and the save file just remembers the path to the specific GameMode and makes one Resources.Load call. My controller prefab also has a reference to a specific GameMode as a default in case one isn't already loaded which designers can set up for their own testing.
Overall, the serialization (of a single string for the path plus some data storing player prefs and a couple arrays of bools/int for player progression) is pretty simple, as I'm not saving any heavy data like an uncompressed audio file.
pros:
Flexibility. using a single GameMode asset one designer can easily manage how a game should progress while a separate designer can run away with their GameMode asset full of their ideas and tests. they can change the outcome of an entire level without even opening the scene.
Overhead Saving data is a lot more lightweight since you're usually only saving value-types and just one Resources.load call per player load.
Version Control most of the my controllers basically grab their progression data from the currently loaded GameMode class. and each designer can simply make their own GameMode asset to play with so even though two designers can be play testing the same scene they are loading and editing different GameMode assets which avoids most of the nasty business of merge conflicts with other teams.
cons:
Think Ahead! When I first made the editor, my designers quickly got to playing with it. they would make elaborate setups and then find a bug or ask for a new feature in the editor. thing is you need to be careful about changing variable names and datatypes because since the class is serialized and already had these elaborate setups a single bugfix or added feature could invalidate the entire serialization process and the all that data would be lost (annoyingly forcing the designers to start from scratch). granted this is the same gotcha you can get when changing monobehaviours, but with something that likely stores the entire progression of the game thats alot of data to start from scratch.
its very important that you study ways of keeping the scriptableObject's serialized data consistent from day one to avoid this (so getting all the class's requirements from the designers is very important). Using composition helps a ton in preserving most of the data through changes. If you take the time and prepare for the gotchas, the workflow is pretty efficient at helping designers develop the game. I can't see myself going back to how I've done it before after doing it this way.
Thanks for sharing. In my case, it's trivial to rebuild/reassign everything if the asset gets corrupt, press a single button to have the resource database repopulated. We avoid having to deal with Unity serialization like the plague. Our data lives in data files with custom in-house format. We can still expose things for tweaking using Vexe Framework [Show] attribute (so even if something wasn't serializable you could still view it)
Question is, if you added X number of assets under the Resources folder, and the size of the build increased by Y. Compare this to referencing those same X number of assets via the Resource$$anonymous$$anager ScriptableObject, would the size still increase by Y? That's what I'm trying to figure out..
Your answer
Follow this Question
Related Questions
Loading a ScriptableObject at Runtime. 1 Answer
How can I overcome the 2GB Resource File Limit and load more than 2GB of assets into the scene? 1 Answer
What is the cost of using Resources.Load? 2 Answers
www faster than Resources.Load? 0 Answers
ridiculous load time using Resources.Load() on android build 0 Answers