Unity docking background and loading images

1 Introduction

        Use await on the web side to connect with the backend is not supported yet, so coroutine has become a better general method. The following applies to all connections except post access.

2. Connect with the background
2.1. Install plug-in

        ​ ​ ​ First we need to use Newtonsoft.dll. If you don’t have this .dll, please install it with me. We first create a script WebRequest.cs, and then double-click the script to open VS2022

In the upper row of toolbars, click the "Tools" option

 Select NuGet Package Manager-Manage the NuGet package of the solution, and a window will pop up.

Click "Browse"

The first thing on the list is the plug-in we need to use. The plug-in is lightweight and easy to use.

After clicking this, a small window on the right will pop up, check it like I did, and then install it.

 After the installation is complete, we return to the script page and right-click to open the folder where it is located.

We return to the project directory. There is a Newtonsoft in the folder Packages Folder, this is our plug-in

There are many net versions after clicking on the folder. I personally recommend netstandard2.0.

 Drag Newtonsoft.Json.dll under netstandard2.0 into our project, and let’s start our text

2.2. Code

        Back to the topic, after we create WebRequest.cs, the structure is as follows

using Newtonsoft.Json.Linq;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class WebRequest : MonoBehaviour
{
    public string address;
    // Start is called before the first frame update
    void Start()
    {
        
    }
    /// <summary>
    /// 获取返回对象,如果不存在返回为null
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path">路径</param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public IEnumerator RequestURLWithArray(string path, System.Action<JObject> callback)
    {
        string paths = address + path;
        Debug.LogError("当前链接+++" + paths);
        //jishi();
        using (var request = UnityWebRequest.Get(paths))
        {
            // 发送HTTP请求并等待响应
            yield return request.SendWebRequest();

            // 检查是否有错误发生
            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.LogError(request.error + "链接:" + paths);
                yield break;
            }
            if (!string.IsNullOrEmpty(request.downloadHandler.text))
            {

                callback(JObject.Parse(request.downloadHandler.text));
            }

        }
    }
}

Since I am teaching, I don’t have an existing backend interface, so I use local json instead. The backend docking can be continued by just changing the link.

After writing the above code, we create the StreamingAssets folder under the project directory Assets, in StreamingAssets Create "test.json" in the folder. The data structure of test.json is as follows:

{
"name":"11111",
"id":123456789,
"password":"123456789"
}

Brothers must pay attention, json must beutf8The format is saved, otherwise bugs such as reading failure or garbled characters may occur

A very simple json, mainly for testing. I plan to build a login interface for testing, so there is not much data. If you have a lot of data, you can also use this set of things. The blogger personally tested it, dozens of interfaces + hundreds piece of data, perfect connection, the delay is basically a few hundred ms, acceptable

Then we write the acquisition in the Start of WebRequest and rewrite the WebRequest

using Newtonsoft.Json.Linq;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class WebRequest : MonoBehaviour
{
    public string address;
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(RequestURLWithArray(Application.streamingAssetsPath + "/测试.json", (a) =>
        {
            Debug.Log($"name:{a["name"]} id: {a["id"]} password: {a["password"]}");
        }));
    }
    /// <summary>
    /// 获取返回对象,如果不存在返回为null
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path">路径</param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public IEnumerator RequestURLWithArray(string path, System.Action<JObject> callback)
    {
        string paths =  path;
        Debug.LogError("当前链接== " + paths);
        //jishi();
        using (var request = UnityWebRequest.Get(paths))
        {
            // 发送HTTP请求并等待响应
            yield return request.SendWebRequest();

            // 检查是否有错误发生
            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.LogError(request.error + "链接:" + paths);
                yield break;
            }
            if (!string.IsNullOrEmpty(request.downloadHandler.text))
            {

                callback(JObject.Parse(request.downloadHandler.text));
            }

        }
    }
}

You should pay attention here, Hit the key points on the blackboard

The output I write here is converted into a JObject object and obtained directly in the form of key pairs.

Debug.Log($"name:{a["name"]} id: {a["id"]} password: {a["password"]}");

All the keys here must match the variables in json before they can be obtained. Of course, in addition to JObject, there is also an array form, which is another structure. We will talk about it later.

After writing, save it, return to unity, create an empty object WebRequest, hang the script on it, and start running.

At this time, the console will output the data we want:

The above is the basic usage. It is not recommended to use it this way. If there is only one json or interface, you can write it as above, but if there is more than one and there is a lot of data, we have to read it in another way.

2.3. Advanced usage

        Next is the advanced usage. We first create an abstract class. This class inherits MonoBehaviour and has an encapsulated JObject parameter and a virtual method init to process the received data:

1. Create a new abstract class Dataabstract.cs

using Newtonsoft.Json.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Dataabstract : MonoBehaviour
{
    public string path;
    protected JObject data;
    public JObject Data
    {
        get { return data; }
        set 
        { 
            if (value != null)
            {
                data = value;
                init();
            }
            else
            {
                Debug.LogError("获取失败,请检查链接地址");
            }
        }
    }
    protected virtual void init()
    {

    }
}

2. Modify WebRequest.cs

using Newtonsoft.Json.Linq;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class WebRequest : MonoBehaviour
{
    public string address = Application.streamingAssetsPath;
    public Dataabstract[] Dataabstracts;
    // Start is called before the first frame update
    void Start()
    {
        init();
    }
    void init()
    {
        for (int i = 0; i < Dataabstracts.Length; i++)
        {
            StartCoroutine(RequestURLWithArray(address+"/"+Dataabstracts[i].path, (a) =>
            {
                Dataabstracts[i].Data = a;
            }));
        }
    }
    /// <summary>
    /// 获取返回对象,如果不存在返回为null
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path">路径</param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public IEnumerator RequestURLWithArray(string path, System.Action<JObject> callback)
    {
        string paths =  path;
        Debug.LogError("当前链接== " + paths);
        //jishi();
        using (var request = UnityWebRequest.Get(paths))
        {
            // 发送HTTP请求并等待响应
            yield return request.SendWebRequest();

            // 检查是否有错误发生
            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.LogError(request.error + "链接:" + paths);
                yield break;
            }
            if (!string.IsNullOrEmpty(request.downloadHandler.text))
            {
                callback(JObject.Parse(request.downloadHandler.text));
            }

        }
    }
}

3. Create a new test class Test1. Test1 inherits the abstract class Dataabstract and overrides the init method.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test1 : Dataabstract
{
    protected override void init()
    {
        Debug.Log($"name:{data["name"]} id: {data["id"]} password: {data["password"]}");
    }
}

Go back to unity, create a new empty object Test1, hang up the Test1 script, and write our json name on the path on the panel. Please note that you must put the suffix , on the suffix, on the suffix          

Then we drag Test1 into the Dataabstracts array of WebRequest

Then run it and you can see that we got the data

This is mainly used to deal with a large number of different json or interfaces that need to be read. This is the diversity of this format. Let’s look at another format of json.

2.4. Another json reading with array

We create another json under StreamingAssets, named test 1.json, the data is as follows

{
  "data": [
    {
      "name": "123",
      "id": 1,
      "password": "爱上放大"
    },
    {
      "name": "456",
      "id": 2,
      "password": "各色地方"
    },
    {
      "name": "789",
      "id": 3,
      "password": "奥尔格和"
    }
  ]
}

Create a new Test2 script

using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.UI;

public class Test2 : Dataabstract
{
    public int index;
    [SerializeField] Text[] text;
    protected override void init()
    {
        JArray jArray = (JArray)data["data"];
        for (int i = 0; i < text.Length; i++)
        {
            text[i].text = jArray[index][text[i].name].ToString();
        }
    }
}

Next we go back to unity and create good things according to my structure

Hang Test2 on the GameObject, and then separate the indexes of each GameObject. My json here has three sets of data, so I fill in 0-2 here. This is used as an index to find data in the data array in the json. Each GameObject Drag the three Texts below into the Text array in Test2

 Then drag the three GameObjects with Test2 attached into the array in WebRequest.

You can see the results by running it directly 

As you can see, we successfully obtained the data with almost no delay, basically just running

2.5. Summary

When faced with the following simple json, we use JObject to get the data

{
  "name": "11111",
  "id": 123456789,
  "password": "123456789"
}

When faced with the following slightly complex json, we use JArray to retrieve data

{
  "data": [
    {
      "name": "123",
      "id": 1,
      "password": "爱上放大"
    },
    {
      "name": "456",
      "id": 2,
      "password": "各色地方"
    },
    {
      "name": "789",
      "id": 3,
      "password": "奥尔格和"
    }
  ]
}

The abstract class we built just uses a simplified version of the observer pattern to build our communication module, which facilitates maintenance and reduces coupling.

3. Load pictures
public void show(string url,Action<Sprite> ac)
{
    StartCoroutine(LoadImageFromUrl(url,ac));
}
IEnumerator LoadImageFromUrl(string url, Action<Sprite> ac)
{
    using (var request = UnityWebRequestTexture.GetTexture(url))
    {
        yield return request.SendWebRequest();

        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(request.error);
        }
        else
        {
            Texture2D texture = DownloadHandlerTexture.GetContent(request);
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
            ac(sprite);
        }
    }
}

We can create a script to test this code and create a new Test3

using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class Test3 : MonoBehaviour
{
    [SerializeField] Image im;
    private void Start()
    {
        show("https://img1.baidu.com/it/u=4049022245,514596079&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1701622800&t=c88ca2191a6df508642839cff923ed20", (a) =>
        {
            im.sprite = a;
        });
    }
    public void show(string url,Action<Sprite> ac)
    {
        StartCoroutine(LoadImageFromUrl(url,ac));
    }
    IEnumerator LoadImageFromUrl(string url, Action<Sprite> ac)
    {
        using (var request = UnityWebRequestTexture.GetTexture(url))
        {
            yield return request.SendWebRequest();

            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.Log(request.error);
            }
            else
            {
                Texture2D texture = DownloadHandlerTexture.GetContent(request);
                Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
                ac(sprite);
            }
        }
    }
}

Go back to unity, create a new Image, hook up Test3, and run

 You can see that the image has been loaded, which is very easy to use. Of course, if there are many images, you can refer to the above format of reading json and rewrite it. Create an image management module to specifically load images. We will see you in the next issue.

Guess you like

Origin blog.csdn.net/k253316/article/details/134753300