Unity3D:在下载大型 3D 模型文件之前不要继续代码

Unity3D: Don't continue the code until a large 3D model file is downloaded

我需要通过单击按钮从服务器加载大约 10 个 3D 模型。

public GameObject DownloadFile(String url)
{
    GameObject obj = null;
    Debug.Log("url: " + url);

    string path = GetFilePath(url);
    Debug.Log("Path: " + path);

    if (File.Exists(path))
    {
        Debug.Log("Found file locally, loading...");
        Debug.Log(path);
        obj = LoadModel(path);

        return obj;
    }
    Debug.Log(path);


    StartCoroutine(GetFileRequest(url, (UnityWebRequest req) =>
    {
        if (req.isNetworkError || req.isHttpError)
        {
            // Log any errors that may happen
            Debug.Log($"{req.error} : {req.downloadHandler.text}");
        }
        else
        {
            // Save the model into a new wrapper
            obj = LoadModel(path);

            obj.SetActive(false);

            StopAllCoroutines();

        }
    }));



    return obj;
}


string GetFilePath(string url)
{
    filePath = $"{Application.persistentDataPath}/Files/";
    string[] pieces = url.Split('/');
    string filename = pieces[pieces.Length - 1];

    return $"{filePath}{filename}";
}



IEnumerator GetFileRequest(string url, Action<UnityWebRequest> callback)
{
    using (UnityWebRequest req = UnityWebRequest.Get(url))
    {
        req.downloadHandler = new DownloadHandlerFile(GetFilePath(url));
        yield return req.SendWebRequest();
        callback(req);
    }
}

GameObject LoadModel(string path)
{
    ResetWrapper();
    GameObject model = Importer.LoadFromFile(path);



    return model;
}

这是我现在的代码。我使用 URL 作为参数从我的脚本调用 DownloadFile 函数。下载函数 return 是一个空对象,因为下载一个大文件需要时间。所以它 returns obj 没有被下载。如何在下载完成后才能return?

如果你按照你的要求去做,你会完全冻结你的应用程序......如果这是你想要的,你当然可以而不是运行协程简单地做

var request = GetFileRequest(url, (UnityWebRequest req) =>
{
    if (req.isNetworkError || req.isHttpError)
    {
        // Log any errors that may happen
        Debug.Log($"{req.error} : {req.downloadHandler.text}");
    }
    else
    {
        // Save the model into a new wrapper
        obj = LoadModel(path);

        obj.SetActive(false);

        StopAllCoroutines();
    }
}

while(request.MoveNext())
{
    // freeze
}

return obj;

然而,在大多数情况下,这绝对不是您想要的 ;)


与其给它一个 return 类型,我宁愿通过回调来解决这个问题:

public void DownloadFile(String url, Action<GameObject> onResult)
{
    GameObject obj = null;
    Debug.Log("url: " + url);

    string path = GetFilePath(url);
    Debug.Log("Path: " + path);

    if (File.Exists(path))
    {
        Debug.Log("Found file locally, loading...");
        Debug.Log(path);
        obj = LoadModel(path);

        onResult?.Invoke(obj);
    }
    Debug.Log(path);


    StartCoroutine(GetFileRequest(url, (UnityWebRequest req) =>
    {
        if (req.isNetworkError || req.isHttpError)
        {
            // Log any errors that may happen
            Debug.LogError($"{req.error} : {req.downloadHandler.text}");
        }
        else
        {
            // Save the model into a new wrapper
            obj = LoadModel(path);

            obj.SetActive(false);

            StopAllCoroutines();

            onResult?.Invoke(obj);
        }
    }));
}

所以而不是例如做类似

的事情
var result = DownloadFile(url);

你更愿意

DownloadFile(url, result => {
    // whatever to do with the result object
});