This article shares resource management in Unity - a set of simple resource management solutions (1)
After a series of articles, we finally come to the last part of this topic.
In the next few articles, the author will provide a set of simple resource management solutions for everyone to learn and refer to. I believe that they can be directly used in projects with simple modifications.
The whole program will basically cover all the content mentioned in our previous article.
In this article, we first briefly introduce the core structure and layout, and fill and enrich it in subsequent articles.
Well, enough nonsense, let's start today's content immediately.
demand analysis
Ab
First of all, we need to use or under Runtime , or Resources
under Editor .AssetDatabase
Resources
Then, we need to use the resource according to the file name + extension, which requires that the resource cannot have the same name , and requires a resource-path mapping relationship management.
Finally, we need to manage resources that need to be instantiated and resources that do not need to be instantiated. This is achieved through object pools and reference counting.
Resource directory structure design
We use the common plus system and then classify the schemes separately, namely:
- Resource classification:
Textures
: textureSprites
: spritePrefabs
: PrefabricatedShaders
: shaderMaterials
: materialAnimationClips
: animation clipAnimators
: animation controllerSpines
: bonesFont
: fontAudioClip
: sound clipConfig
: configuration fileBehaviorTree
: behavior treeModels
: ModelScenes
: Scenes
Config
: Save some resource configuration informationCommon
: public directory, containing all resource typesSystems
: system directory, divided into resource directories of each system, mainlyTextures/Sprites/Prefabs
We probably design each folder in the public part as a package Ab
. If a certain type of package has too much content, such as AnimationClips
, or can be divided into separate individuals, such as Models
in, all resources of each model can form a separate folders, these cases can be further divided into individual Ab
packages.
Common resources are generally not actively uninstalled, and useless resources ( Resources.UnloadUnusedAssets
) are manually triggered to be cleaned up only when the scene is switched or the memory reaches the warning value.
Then each system in the system is one Ab
, so that it can be uninstalled separately when not using a certain system. Of course, in order to improve the user experience, you can also choose not to uninstall immediately, but to adopt some other optimization strategies. For the sake of simplicity in this example, Use the direct uninstall method.
If a certain system is relatively large, such as a combat system, it can be further divided, generally according to the system-to-subsystem model.
At the same time, in order to simplify the example, we directly use it Asset Labels
to manage it Ab
instead of managing it through code. Interested students can refer to the previous article.
The entire directory structure is roughly like this:
role conception
Under normal circumstances, users (business developers) actually don't care whether we use or Ab
, AssetDatabase
or Resources
.
So our first character is: AssetManager
.
The main responsibilities and main interfaces of AssetManager
We use it AssetManager
as an external window for the entire resource management, and users only need to call its interface to retrieve and return resources.
That is to say, AssetManager
it will provide an interface for fetching and returning resources, and is responsible for maintaining the reference relationship of resources internally, loading and unloading resources or destroying instantiated objects at the right time.
Because many times, we will request multiple resources at the same time. If users are allowed to make records and return them when they are not in use, it will increase the user's usage cost, so we need a role to undertake this work, which is our Second character: AssetLoader
.
The main responsibilities and interfaces of AssetLoader
We use it AssetLoader
to bear AssetManager
the window between the user and the user. The user AssetManager
requests new ones AssetLoader
, and actually uses them AssetLoader
to request and return resources. After use, one-time destruction AssetLoader
can complete the return and destruction of all resources.
A common use scenario is to request a new one when each window is opened AssetLoader
, and all subsequent resources such as prefabs, special effects, textures, etc., pass through this AssetLoader
request, and when you exit the window, just destroy it AssetLoader
. Of course, you can use the object pool technology to reduce AssetLoader
Actual creation and destruction frequency, using reference counting to ensure normal unloading of resources.
In this way, it can also be combined with the window or display layer manager to encapsulate this part into the framework layer and call it in the appropriate life cycle, so that users do not worry about this process.
What the user actually gets is the resource itself, or the instantiated object of the resource, and all the hidden mechanisms behind do not need to care about it.
Resource information related classes
In order to maintain information such as resource usage status, we need to divide resources into different information roles:
-
The information of the resource itself,
AssetInfo
, supports reference counting, and the core attributes are:- name:
string assetName
- Full path:
string fullPath
- Package
Ab
information:AbInfo abInfo
- References to resource entities:
asset
- Dependent resource information list:
List<AssetInfo> dependencies
- name:
-
Resource location
Ab
information,AbInfo
, supports reference counting, the core attributes are:- name:
abName
- Full path:
fullPath
Ab
Entity references:ab
- List of other information that depends on
Ab
:List<AbInfo> dependencies
- name:
-
Resource instantiation object information,
ObjInfo
, supports reference counting, the core attributes are:- Citations for resource information:
AssetInfo assetInfo
- Citations for resource information:
-
By the way, if you use
Ab
the method of adding code, you can add the following role to serialize the mapping relationship between resources and paths. It is not used in our solution, but it is still listed for everyone-
The configuration information of the resource itself,
AssetConfigInfo
, supports serialization, and is used to map resource names and paths orAb
information- name:
string assetName
- Full path:
string fullPath
- Where
Ab
the package name:string abName
- name:
-
Configuration information of all resources,
AssetConfigInfoAsset
, supports serialization, used to store allAssetConfigInfo
-
Here is the simple code:
-
[Serializable]
public class AssetConfigInfo {
public string assetName;
public string abName;
[NonSerialized]
public string fullPath;
}
public class AssetConfigInfoAsset : ScriptableObject {
[SerializeField]
public List<AssetConfigInfo> assetLst;
[NonSerialized]
public Dictionary<string, AssetConfigInfo> assetDict;
public void Mapping() {
Assert.IsNotNull(assetLst, "资源列表为空!");
if (assetDict != null) return;
assetDict = new Dictionary<string, AssetConfigInfo>(assetLst.Count);
foreach(var assetConfigInfo in assetLst) {
if (assetDict.ContainsKey(assetConfigInfo.assetName)) {
Assert.IsTrue(false, string.Format("资源重名!: assetName {0}; abName {1}; fullPath {2}, ", assetConfigInfo.assetName, assetConfigInfo.abName, assetConfigInfo.fullPath));
}
assetDict.Add(assetConfigInfo.abName, assetConfigInfo);
}
}
}
For the time being, only these contents and roles are needed, and will be added in later articles if necessary.
There is not much content today, mainly design ideas. We will implement the design plan from the next article. Interested students can continue to pay attention, hoping to be helpful to everyone.