Have you ever been afraid of a monster in the dark? Elusive, hiding under your bed or inside the closet, skulking out of view whenever your parents shine a light. But you know it's there, lurking in the shadows, just barely out of sight. What if that monster is real?
That monster is very real for 8 year old Elias. It is waiting, in the darkness, in it's stronghold. Waiting, and plotting and biding it's time, slowly exerting it's influence all throughout his bedroom. Of course his parents don't believe him, so there's only one option left: Call in the Orb Warriors!
Take control of Alpha, Beta, Gamma or Omega and become part of the justice loving, evil fighting group of hero robots known as the Orb Warriors!
Master the Orb, the titular weapon of the Orb Warriors, and it's unique form of combat. Modify your Orbs abilities further through the use of Boost Capsules and collect rare Power Chips to unlock your full potential and customize your Orb Warrior to fit your playstyle.
A very neat feature of the Unity game engine is the concept of Resources. For the uninitiated, I will try to give a quick overview of how Resources work.
Every asset placed inside a folder named "Resources" can be accessed in the editor and in your game build via its path. You can create multiple folder called "Resources" in your assets and you can create subfolders within. However, the path via which you can load your asset is always relative to its nearest Resources parent folder.
Let's look at an example.
A pretty common way of structuring a Unity project is creating a central Resources folder directly in the Assets folder (which is the root of your project as far as Unity's Project window is concerned). If we take this approach, we may want to create subfolders within to organize our Resources.
For our example, let's say we have created a prefab for an enemy named Orc. Your asset database may see its path like this: "Assets/Resources/Enemies/Orc.prefab".
To load the GameObject using our Resources class, we may use:
GameObject orcPrefab = Resources.Load("Enemies/Orc");
Please note that the path expected by the Resources.Load function does not include its filename extension, in this case ".prefab". For this reason, it is not safe to have multiple assets with the same filename at the same relative resource path.
It is also worth noting, that we are using the generic variant of the Resource.Load function. Similar to the Instantiate function, this can also be used to get direct access to the Components of a GameObject. In our case, let's say the Orc has a MonoBehaviour component called EnemyLogic. To get said component immediately when loading our Orc prefab, we could modify our example like this:
EnemyLogic orcPrefab = Resources.Load("Enemies/Orc");
Keep in mind that we are still only referring to the asset, in this case our prefab. To create Orcs in our game scene, we would still have to instantiate them.
Enough about Orcs (for now). In a real world game project there are all kinds of assets you may want to access from your scripts: ScriptableObjects, Materials, Textures, AudioClips and so on. Anything that inherits from UnityEngine.Object is fair game.
The neat thing about the Resources approach is that it requires zero setup in your code. You don't need to create any serialized fields to drag your assets into. If an asset is in your Resources, you can basically get it from anywhere in your code base, even in editor code.
Sometimes, this can be a memory safer. Say you have a GameObject that will randomly spawn an item, 1 from a variety of 20 or so options. Sadly, we only know the item we actually need at runtime. Using Resources, instead of referencing 20 different prefabs that we may instantiate, we can decide which item to spawn first and then proceeed to load exactly the prefab we need.
For loading large assets without slowdown, there is even the option of using Resources.LoadAsync.
Right here: Accessing assets via their path is not very safe. One little typo and you're in for a NullReferenceException. Not from Resources.Load itself mind you, which will simply return null in case an asset cannot be found. But your code will probably expect the asset to exist, otherwise you wouldn't try to load it, right?
It is not uncommon for assets to get moved or renamed once in a while to keep the project structure tidy. If you do this to any of your Resources, you better remember to update all the scripts that depend on their path. Try explaining that to your designers.
We can't fully eliminate the problem, our paths have to be stored somewhere. However, we can do quite a lot to minimize the room for errors and reduce our workload.
A straightforward approach to manage our Resources would be to centralise the way we store our paths.
Back to our Orc example, let's take a look at what our helper class could look like:
Now everytime we want to get our Orc prefab, we can simply write:
EnemyLogic orcPrefab = Resources.Load(ResourcePaths.Orc)
What if we remove or rename our assets now? No biggy! If we are consistent in using our little helper class, it is the only place where we ever have to make any changes. That is a lot less work than going through all scripts that use Orcs.
Why stop there? We can easily take this one step further by using some cute Getter Properties and moving the Resources.Load calls into our helper class. Let's also assume our class will grow a little and we want to keep things nice and tidy. We can improve our structure by using Nested Types.
Here is what the result looks like:
This makes accessing our Resources a breeze without introducing any additional overhead or maintenance work (compared to our previous approach). Once again, to get our now infamous Orc, we would now write:
EnemyLogic orcPrefab = ResourceLoader.Enemies.Orc;
So this is a pretty great setup already. We can take this and run with it.
However, if we want to reduce the amount of code we have to write and manage by hand, we could entertain the idea of creating a GUI based solution...
For Orb Wars we have created an EditorWindow into which we can drag and drop our assets and which will write our helper class for us. For prefabs, we can even select the component type we want to use (or use GameObject).
Our ResourceMapperGenerator will also prevent duplicate assets, automatically update the paths of assets that were moved or renamed and warn us about assets or types that no longer exist in our project.
Here is a short example of the ResourceMapperGenerator in action:
Those are a lot of Menu prefabs!
The generated C# code is pretty simple and identical in structure to the ResourceLoader class we created for our example.
Let's take a look at what the beginning of the generated class looks like:
And that is all for today.
Tune in for part 2 of our Resource shenanigans to find out about other ways in which you can use Resources and how we use them to keep our network traffic low.
Take a look at the thought process and iterative workflow that went into creating our cast of main characters, the Orb Warriors, from concept to finished...
A quick overview of the Stats system in our game, how we designed it and what we learned along the way.
Ever wondered how all those fancy visual effects in your favourite games are made? Well, today we're breaking down some of the VFX from OrbWars! Well...
No articles were found matching the criteria specified. We suggest you try the article list with no filter applied, to browse all available. Post article and help us achieve our mission of showcasing the best content from all developers. Join now to share your own content, we welcome creators and consumers alike and look forward to your comments.