Why make a "Resource folder"

Hello,

I recently discovered the Resources.Load() function to load “things” from any Resources folder in your unity workspace. And although I get the appeal, there is something I can’t wrap my head around. Why Resources.Load() can ONLY load resources inside a folder named resources ?
It seems so weird to me. From my point of view, anything in a game is a resource; textures, scripts, sounds, etc
Just different types of resources. So why should I mess around with my whole file hierarchy and add resources folder everywhere ? Why can’t we just load ressources from the root of our unity project folder ?
Perhaps I just got it all wrong, I’m thinking with a bad mindset. But this “resources folder” prerequisite is a drawback to me.

Could someone please explain me why they made this choice ? And if you know elegant ways to load resources without dragging them on the UI or using resources folder, please be my guest.

my assumption has always been that it has to do with what is, and is not included in the final build. Not everything in your project will get put into the final build, only that which is used in a scene somewhere. I assume that the items in the resources folders are included regardless of whether they are used in a scene so that anything added at run time via script has the resource available. Be interesting to find out if that assumption is anywhere near the mark :smile:

2 Likes

That is what I would say aswell. Each scene gets its own arcive that include all the assets in the scene at build time. Since no dynamically loaded assets are present there some other archive was needed for these. You now have the ability to put things in assetbundles yourself wich sort of work like a variable amount of resource folders. But that puts more management in your hands.

Yup - that’s exactly what it does.

Wort pointing out aswell I suppose is that none of your original texture or model files are included in a build (with some exceptions) The unity runtime only loads specialized/optimized versions of your assets created during import.

OK thanks for answering guys.

I should definetly look for some documentation around how unity compile its packages for release build.

That said, I still don’t understand why do Unity impose us to create resources folder. Might as well look around for the assets loaded with Resource.load() during the 1st pass compilation (I assume C# has some multi pass “compilation” like C++ and any other evolved languages) instead of coming up with yet another naming convention :confused: (sorry if it sounds rude,i that’s not my intention).
Also there is no other way at all, to load (for example) a prefab from a script? We have to go for Ressource.load() or drag the prefab throught the UI (which I can’t do because my prefab variable is static and so it doesnt show up in the explorer). Not at all ? :confused:

You’d rather have the overhead of Unity finding all your Resource.* calls and then searching your entire project for those assets every time you compile your code just to avoid having to name a folder in a particular manner? Why? What if you’re passing a string to Load() that it can’t determine the value of at compile time?

And no - there’s no other way to dynamically load prefabs in your project from code.

1 Like

If your code can possibly be analyzed this way, odds are you are not really taking advantages of Resources. That concept might work for this code:

GameObject foo = Resources.Load<GameObject>("foo");

But why would you do that rather than linking the prefab directly via a public reference?

A more realistic use case might be:

string[] someObjectNames = new string[]{"foo1", "foo2"};
for (int n=0;n<someObjectNames.Length;n++) {
GameObject thisFoo = Resources.Load<GameObject>(someObjectNames[n]);
}

This is already virtually impossible to optimize at build time for. And we’ve barely begun!

Say you have a bunch of item images, identically named but sorted into folders by color.

Sprite LoadIcon(string itemName, string itemColor) {
return Resources.Load<Sprite>(itemColor+"/"+itemName);
}

At this point, if you want your compiler to intelligently include every item that could be found by this code, it needs to be smart enough to find every instance of LoadIcon, and every possible parameter that could be getting fed into the function.

We’re just getting started.

A (simplified) use case we rely on heavily at my current job:

public TextAsset listOfObjectNames; // text file, linked via the inspector
void Awake() {
string[] lines = listOfObjectNames.text.Split('\n');
for (int l=0;l<lines.Length;l++) {
Instantiate(Resources.Load<GameObject>(lines[l]) );
}
}

In our case, we have more data in the text file than just that to customize the objects that get spawned, effectively making that file markup to spawn customizable objects on the fly from text files.

And the main reason we do that, is so that we can do the exact same thing, but loading the text file from the web.

Do you see how what you want it to do is fundamentally impossible?

2 Likes

I don’t know how works the overhead of unity, but I always assumed it doesn’t recompile a file if it has not been modified since the last compilation. You’re implying it doesn"t work that way
And yeah I may be a little stubborn. But it’s not because I think “I have better ideas, and senior devs should tottally listen to me”. It’s just that I wanted to understand what lead them to make this choix. IMO, A better understanding of unity design choices can help you adopt the unity devs paradigmn and so avoid unelegant coding habits.

And I’m being reluctent to change my file hierarchy because as it is now, it really suits my logic / thinking of a Unity project. And adding a special folder just in order to get a specific function to work, still sounds weird to me. It’s like when you range your socks in the drawer. You just put them in a “the sock drawer”. You don’t have a drawer for “regular socks” and one for the “might be used by Resources.load() socks”.

But hey, I’m still learning, obviously I’m missing something here. i have to take a step back, look at the big picture and understand the whole resources concept.

EDIT: Haven’t seen StarManta message when I was writing this. So,
yeah the web exemple brings some new light on the problem. Resources.Load() is definetly designed to be a, insecure (in the way that we have to do verifiy the stuff that’s pointed by the string) on run-time only function

And to the question why don’t I use a public reference and drag the prefab on it. There’s two problems with that; 1/ it’s a static variable so it doesn’t show up in the inspector 2/ I like to keep my inspector as clear as possible. If I’m making a character GameObject there’s gonna be a lot of things on it, different sub models, script, different link between each part of the character, etc etc. But lot of that will be set on the creation of the GameObject and I will never tinker with them again… So might as well hide them. I like to keep only stuff useful (for debug purposes) on my inspector (like the speed of the character for instance)

But it looks like you and the unity devs are telling me that i’m using unity in a wrong way and should always go for public references.

…what? I have no idea what you’re getting at here. Unity can compile files as often or as rarely as it likes, that has no bearing on this question.

If you really want to avoid Resources, you could make a singleton in this case:

public class ObjectReferenceHolder : MonoBehaviour {
public static ObjectReferenceHolder instance;
void Awake() {
instance = this;
}

public GameObject thing1;
public GameObject thing2;
}

So instead of having a static variable, you have a static reference to an in-scene object with the references you need (via ObjectReferenceHolder.thing1)

OK, this might be getting confusing due to the backwards leaning of it.

When building, you have to build everything. There’s some preprocessing that can be done at a previous time. But the actual build still needs to do a full build.

When doing that build the build processor needs to be told every little thing that must be included in the build. Everything.

Who ever engineers the build process decides how the build process determines what everything is. Usually for resources in the game, there’s a resource resource file, or a resource directory, or heck even a resource project. And the build process for each resource needs to be defined as well (textures get processed this way, models that way, a specific model might be processed differently from another… so on, so forth). And of course, if a resource is not used in the project, you don’t want to include it in the build.

This is called the ‘build pipeline’.

It’s a pipeline because there are several steps to it, that must occur in a specific order.

Note, lets look at some old games, like Super Mario, Zelda, and the sort. Hackers have torn apart the code and pulled resources for sprites out of it for things that don’t exist in the games. These resources ended up in their because their build pipeline was including resources that should have not been included in the final build. Thing is… this was back when games were meant to fit on expensive ROM chips that were very small in storage space. These unnecessary resources ended up increasing the size of the ROM for no reason. This may be because someone forgot to remove it from what ever system they use to determine necessary resources.

In unities case, they wanted to make it as easy as possible for the user. So instead of requiring all resources to placed in some resource directory, or resource project. They instead decided they’d just infer what resources are needed by searching through the scenes and seeing what scripts/prefabs/models/etc were included in the scene (either by reference, or by direct instantiation in scene). Now we have a list that ONLY consists of the resources needed, making for the most compact build possible to make the game run.

Remember, compactness is important… you may be deploying to platforms like iOS or Android where there is limited storage. Or printing to CD/DVD which has a finite size limit.

Thing is… this means that EVERYTHING you use needs to be in a scene. It doesn’t allow for ‘dynamic’ loading. What if the scene gets populated with characters based on a choice the user made, and the choice could be from a list of 100 characters. Why load all 100 characters into memory just to be in that scene???

So Unity included a way to allow you to define the resources you want to include in the game. They reintroduced the ‘Resources’ folder. What otherwise would have been required, unity only uses for when unity otherwise can’t figure out what resources are needed (see @StarManta 's previous post).

The only other option would be to include the ENTIRE project. Which is ridiculous. Then we’d end up creating the fattest/least efficient build of the game since every unused asset gets included.

Note… when working on large projects tons of assets may exist that aren’t actually critical to the game. It may be assets used for editor stuff. Or old versions of assets laying around because some designer wanted to be able to look at it easily. How do we include these assets in our project, while not including them in the build???

Well, that’s what the Resources folder does.

Basically… if it’s not in a Resources folder, but is used in a scene, it gets included, otherwise it doesn’t. If it’s in the Resources folder it always gets included.

3 Likes

And no, unity can not figure out what resources are needed by searching through your code. Code allows for infinite possibilities of strings to be passed into ‘Resources.Load’.

Say you had a method that generates a random string, of random length. This means that all possible words up to max length can exist. All asset paths that are shorter than that max length fall under that umbrella. So… if a program can call Resources.Load, for unity to include all possible assets that can be loaded by Resources.Load… it’d have to include ALL ASSETS. Completely subverting the entire point of compacting the build process and not including unnecessary assets.

To be able to query source code to tally assets, unity would have to force only constant strings be passed into Resources.Load (which can’t be syntactically enforced, it’d just be a build error). And that would sort of defeat the entire ‘dynamic’ need for Resources.Load. Constants aren’t dynamic!

2 Likes

Minor niggle with this point. Those ROM cartridges were only available at specific sizes, usually powers of 2 (256kb, 512kb, etc). If your game ended up being 468kb, those extra 20kb of assets were making no difference at all, and if your game ended up at 515 kb, you bet your ass the devs would look through and find those. If they were left in, they were almost certainly costing them nothing.

Not really relevant to the discussion at hand, because on the modern Web or mobile build, every kb DOES have an impact.

Very true.

My point was just that resource management is important. Because increasing the ROM size passed any of the chip sizes, meant increasing the prices. I was already getting long winded so I wasn’t going into hard specifics, since the topic was about resource management, not the actual considerations old developers had to make down to the kilobyte.

In my case, I use Resources because I don’t want everything loaded into RAM when the game loads. For example, my game Horde Rush has costumes and helmets that you can customize your character with. Supposing I had thousands of costumes and helmets. Why would I want to eat up precious RAM by loading all of those? Instead, having them available to load when I need them is what Resources.Load() provides. It gives you a way to load only the things that you want to load in memory.

1 Like

Indeed, let’s just say that until @StarManta post I had the wrong idea about Ressources.Load(). To cut it short, I thought it was simply a method to load assets from your unity workspace. Kinda like a GameObject.Find() but looking inside unity project folder instead of the scene and using a file path instead of a name. (Admit it, a method like that which could treat everything imported as a resource would be helpful.) But hey I got it all figured out by now (I hope), as I wrote in this message

Thanks for everything again guys. I think we’re done here, you covered all the grounds here.

No, I can’t admit that… because then unity would have to include all assets in the project folder into the final build.

This would make the final build larger than it would have to be.

If it did that, and I had assets I didn’t want included in the final build. Every time I built I’d have to remove all assets I don’t want from the project folder.

Naaaah the imaginary function I had in mind when writing this description would only take const string as parameter and check the presence of the asset to load at compilation (NOT at runtime), so it would load only the useful file. But hey it’s all fiction and fantasies.

A function that has this really limited use case, and no IDE can track it’s syntactical oddity, leading to weird errors that aren’t apparent off the bat.

OR

You could just have a Resources folder.