1.18 Learning Unity game development from 0--resource loading

In the last article, we probably started to get in touch with resource loading. Scene resources are a special resource. We only need to add it to Build Settings, then we can directly load it through the API.

But what about other types of resources? For example, when we make an online game and receive the returned data from the background to install a gun on the character, it is impossible for us to assign all the guns as member data. We definitely want to load whichever one is used, so at this time It is necessary to support loading resources by similar names or paths.

Therefore, in this chapter, we will explain what resources are in Unity, how to load them, and the scenarios where several loading methods are applicable.

load by reference

In the previous chapters, when we want to use a certain resource, we add member variables to the code, and display it on the editor panel with the help of Unity’s serialization capability. Then we drag and drop the objects in the scene or the Project window. The resource is assigned to the corresponding variable. This method of loading resources is loaded by reference.

We have analyzed the actual scene file before. Whether our GameObject or component class, a unique id will be generated during serialization. This id is used to store the reference relationship, and it will be created when the scene starts. Load the existing GameObject in the scene, and then index all reference relationships according to the id data in the file.

But there is a problem, we actually used Prefab to assign to the component variable of the object in the scene before, so what is the reference relationship?

We might as well open the Demo.unity file in text mode and find the FireController component of the FireController object we assigned the bullet to:

It can be seen that here we see fileID again, but obviously we cannot search for the second use of this fileID in the scene file. After all, the Prefab assigned here exists in the Project window instead of the scene, so we pay attention There is also a guid at the back. Friends who are good at global search may try to search the entire Assets directory, and they will soon find that this guid exists in the Bullet.prefab.meta file:

Open to see the content is like this:

You can see that the GUID recorded in this meta file is consistent with the GUID stored on the variable that references the Prefab in our scene, and if you open Bullet.prefab again, you can find the component on the Prefab corresponding to the fileID.

At this time, I actually understand that for resources that can be directly referenced in non-scenes, resource files outside the scene will have a .meta file, which stores the guid of the resource, and the method of referencing resources outside the scene is Search by this guid.

You can observe carefully that all files under the Assets folder will carry a .meta file, which means that all files, including folders, can be referenced in Unity.

This also explains by the way that if our game project needs to be uploaded to a version control system such as git or svn, p4, the .meta file must be uploaded. If it is not uploaded, when other people open the project, Unity will automatically generate a new .meta file, at that time all your resources referenced by guid will be invalid.

Of course, the .meta file not only stores guid information, but also a lot of other information, which we will explain in detail later in the advanced tutorial for each resource type.

After understanding how Unity handles the references of resources inside and outside the scene, you can actually understand why our things can be packaged, because Unity packages find all resource references from the scenes added in Build Settings, all All resources used will be packaged into the final game package.

Resources folder

When we don't directly reference components or GameObject or Prefab resources in any code members, how do we dynamically load a Prefab or other resources? Unity provides a special unspoken rule, a folder named Resources. In your Assets directory, any folder named Resources is fine, and multiple Resources folders in different directories can exist at the same time. These files The folder will be uniformly recognized by Unity, and then you can use the Resources.Load API to load the resources inside:

Unity - Scripting API: Resources.Load​docs.unity3d.com/ScriptReference/Resources.Load.html

It's a bit similar to loading a new scene. We can load the contents of the Resources folder through a relative path. Note that the path must use / instead of \ as the path separator.

For example:

  1. Assets/Test1/Resources/a.prefab, then you use a when loading, without file extension
  2. Assets/Test1/Resources/BB/a.prefab, then you use BB/a when loading
  3. Assets/Test2/Resources/BB/a.prefab, you will conflict with 2, and Unity will tell you that all files in the Resources folder cannot have the same relative path

OK, let’s try it out. Previously, our Bullet was directly assigned to a member variable. Now we put the Prefab resource in the Resources folder. We don’t have one at present, so we create a new Resources folder, or right-click Create- in the Project window. >Folder, and then drag our Bullet prefab file directly into it, which is equivalent to cutting.

Note that if you are doing this operation directly in Windows Explorer, you should also cut the corresponding .meta file. I also said that this .meta file has the guid information of this resource. If you don’t cut it If it is cut away, the original reference relationship will not be found (although it is loaded directly with Resources, it may not affect it). You can't see the .meta file in Unity's Project window, because it will automatically handle it for you when you cut the resource.

Then we need to modify the code of the FireController that created the bullet before:

using UnityEngine;
using Object = UnityEngine.Object;

public class FireController : MonoBehaviour
{
    private bool isMouseDown = false;
    private float lastFireTime = 0f;
    private Vector3 fireDirection;
    private AddVelocity bullet;
    public string bulletResourcesPath;
    public float fireInterval = 0.1f;
    public Transform fireBeginPosition;

    private void Start()
    {
        bullet = Resources.Load<AddVelocity>(bulletResourcesPath);
    }

    void Update()
    {
        if (Input.GetButton("Fire1"))
        {
            if (!isMouseDown)
            {
                isMouseDown = true;
                lastFireTime = Time.time;
                Fire();
            }
            else if (Time.time - lastFireTime > fireInterval)
            {
                lastFireTime = Time.time;
                Fire();
            }
        }
        else
        {
            isMouseDown = false;
        }
    }

    void Fire()
    {
        // 在这里实现每次触发的逻辑

        // 创建新的子弹,每次都是从模板bullet复制一个出来
        AddVelocity newBullet = Object.Instantiate(bullet);
        newBullet.transform.position = fireBeginPosition.position;
        newBullet.SetDirection(fireDirection);
    }

    public void SetDirection(Vector3 direction)
    {
        fireDirection = direction;
    }
}

Our modification is mainly to replace the previous public member bullet with a private member. We no longer need to serialize this member. Instead, we use a string member to allow the editor to fill in the resource path.

Then we load this resource once through Resources.Load in the Start method, and the follow-up is the same as the previous method. The Resources.Load method has a generic type, or in C++ terms, it is a template type. The type filled in <> will be obtained from the loaded GameObject using a method similar to GetComponent. Of course, you want to load the GameObject as well. You can fill in the type GameObject in <>.

OK, let's directly fill in the resource path Bullet of our bullet in the editor:

You can run it again and see that we can also create bullets and get the same effect as before.

This loading method has a disadvantage: the resources placed in the Resources folder will not care whether they are referenced or not, and will be packaged when packaging the game. After all, Unity does not know which one you want to use, so this method is more suitable for small Volume resources.

AssetDatabase

The dedicated resource loading method in the editor mode is mainly used for expansion and functional operations in the editor. It is independent of the normal game operation logic. Since it involves the concept of the editor's game runtime, this chapter will not explain it. I will save it until the time when I specifically explain the development of editor extensions.

AssetBundle

The orthodox game provided by Unity is the normal resource loading method after the game is packaged and released, but many concepts are quite troublesome to understand. This chapter series of articles is only at the initial stage of getting started. I will not talk about this part for the time being. I will leave it to explain the game packaging in detail later. Let's talk about resource management again.

thinking questions

  1. Resources.Load will load resources synchronously and block code execution. Obviously, the official API has an asynchronous version. How should it be written if it is changed to asynchronous?

next chapter

Above we explained two resource loading methods, one is automatic loading by reference, and the other is dynamic loading by path. Although Resources.Load is frustrating, it is enough for us to initially learn Unity's resource loading at this stage.

In the next chapter, we will briefly introduce the editor extension. The Unity editor is not unchanged, but can be adjusted as we like through our code. This is also the editor extension capability provided by modern commercial game engines. Through extension capabilities, We can better make the engine serve our customized needs. Of course, you will also learn the difference between the logic of the editor and the logic of the game.

Guess you like

Origin blog.csdn.net/z175269158/article/details/130258917