我如何从 assetbundle 加载和实例化任何游戏对象?

How can i load and instantiate any game object from assetbundle?

我有一些我们为 unity 5.6 自动创建的资产包,这些资产包中的任何一个都包含一个游戏对象。

我的示例资产:c6f97739ec43264ef3bfae7b1dc55e88.unity3d

link: https://www.file-up.org/891dtdi54n0l

所以,我们已经使用 assetBundle.mainAsset 访问了那个游戏对象。但在 unity 2018.3 中,assetBundle.mainAsset 已过时。

我读了统一文档,他们说使用

LoadAsset<GameObject>(name);

有名字或类型!但是当我创建资产包时,我不知道要访问它的游戏对象名称。

我尝试加载它:myLoadedAssetBundle.GetAllAssetNames()[0]).

void LoadAssetBundle(string bundleUrl)
{
    myLoadedAssetBundle = AssetBundle.LoadFromFile(bundleUrl);
    Debug.Log(myLoadedAssetBundle == null ? "Faild To Load" : "Succesfully Loaded!");

    Debug.Log(myLoadedAssetBundle.LoadAsset(myLoadedAssetBundle.GetAllAssetNames()[0]));

    GameObject prefab = myLoadedAssetBundle.LoadAsset<GameObject>(myLoadedAssetBundle.GetAllAssetNames()[0]);

    Instantiate(prefab);

    myLoadedAssetBundle.Unload(true);
}

我的问题是:

  1. 如何使用新的 assetbundle 统一系统加载主要资产,我的 assetbundle 具有任何类型的游戏对象,如:精灵、obj、声音、视频等。

  2. 我不知道如何实例化我加载的资源?

1- how can I load main asset with new assetbundle unity system with my assetbundles have any type of game object like : sprite, obj, sound, video and etc.

您必须使用通用函数,例如:

MyAssetHelper {
    public static T Load<T>(string bundle, string asset) {
        return SomeT;
    }
}

我们将不得不完成此函数的编写,它不会 return 那样的方法,但目前只需将其视为从给定包中请求给定资产的方法你所关心的只是你能得到一些回报。

2- I do not know how I can instantiate my loaded asset?

我们将通过修改我们的函数以获取更多的两个参数来做到这一点,OnLoad 我们希望当我们想要的资产最终在内存中并可用时发生,OnLoadFailed 当糟糕的事情发生时被调用。我们不知道加载包需要多长时间 and/or 加载资产,所以我们必须等待并依赖回调。

MyAssetHelper {
    public static void Load<T>(string bundle, string asset, UnityAction<T> OnLoad, UnityAction OnLoadFailed) where T : UnityEngine.Object {
        T obj;
        //get the object somehow
        if(obj != null) OnLoad.Invoke(obj); //we have an object
        else OnLoadFailed.Invoke(); //something failed!
    }
}

现在你必须在调用函数时指定你想要的类型(无论如何你之前需要,但你总是使用 GameObject)以及加载东西时的回调函数(或他们失败了)。

所以,一个如何调用它的例子:

public void LoadASprite() { //arbitrary function, could be Start
    MyAssetHelper.Load<Sprite>( //the above function in a static class
        "bundle","sprite_asset", sprite => { //anonymous lambda expression (success)
            Debug.Log("We loaded a sprite! " + sprite);
        }, () => { //anonymous lambda expression (failure)
            Debug.Log("Failed to load sprite!");
        }
    );
}

根据您正在加载的类型,您需要对它做不同的事情,实例化它,将它分配给一个字段,等等。失败时,您可能想要打印某种消息。在运行时,您可能想要假设捆绑总是成功 ("I know that I'll be shipping them together") 或向用户显示一条消息 ("Failed to download bundle, check your connection")。由你决定。您甚至可以让 OnLoadFail 函数接受一个字符串参数,这样您就可以提供更多信息(因为我们将从多个地方调用它)。

不过,现在我们必须完成实际加载方法的编写。我们已经模板化了它需要看起来的东西(接受一个包名称,一个资产名称,并有两个回调函数),但我们仍然需要进行实际加载。

我们知道它不会马上 return(这就是我们创建回调的原因),所以我们需要将我们的内容移到一个新方法,这将是一个协程,所以我们需要启动协程。

MyAssetHelper {
    public static void Load<T>(string bundle, string asset, UnityAction<T> OnLoad, UnityAction OnLoadFailed) where T : UnityEngine.Object {
        StartCoroutine(DoLoad(bundle, asset, OnLoad, OnLoadFailed));
    }

    private IEnumerator DoLoad(string bundlePath, string assetName, UnityAction<T> OnLoad, UnityAction OnLoadFailed);
        T obj;

        yield return null; //operational bundle loading goes here

        if(obj != null) OnLoad.Invoke(obj); //we have an object
        else OnLoadFailed.Invoke(); //something failed!
    }
}

下一位将替换 DoLoad 中的那四行,因为它的块将相当大,只是想确保添加的处理协程的层被理解。下面发生的所有事情是我们请求加载一个资产包,当它完成时,我们必须从包中请求一个资产,当它完成时,调用 OnLoad.Invoke(obj)。在每一步,如果出现梨形,请改为调用 OnLoadFailed.Invoke()

string path = Path.Combine(Application.persistentDataPath,bundlePath);
if (File.Exists(path)) { //load asset from local computer (in Unity's persistent data directory)
    AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromFileAsync(path);
    yield return bundleRequest;

    AssetBundle bundle= bundleRequest.assetBundle;
    if (bundle == null) {
        OnLoadFailed.Invoke();
        return;
    }
}
else {
    OnLoadFailed.Invoke();
    return;
}

AssetBundleRequest assetRequest = bundle.assetBundle.LoadAssetAsync<T>(assetName);
yield return assetRequest;

if (null != assetRequest.asset) {
    onLoad?.Invoke((T)assetRequest.asset);
}
else {
    onLoadFail?.Invoke();
}

请务必查看 the documentation for additional details about fetching or using Asset Bundles in the code, including how to download from a remote location as well as the Application class 以了解有关 persistentDataPath 和相关路径的详细信息。

从设备(本地)加载资产包

使用System.IO;

使用 UnityEngine;

使用UnityEngine.SceneManagement;

public class LoadAssetBundles:MonoBehaviour

{

void Start() { 

    //verify scenename of scene you are use it if you have more than one scene

    Scene scenename = SceneManager.GetActiveScene();

    //unload all assetbundles use it if your project use scenes which can be accessed twice or more like a settings menu

    AssetBundle.UnloadAllAssetBundles(true);

    //if(Application.platform == RuntimePlatform.platform) for multiplatform

    if(Application.platform == RuntimePlatform.WindowsPlayer){

    if (scenename.name == "MainMenu")

        {

            var mainmenu AssetBundle.LoadFromFile(Path.Combine("assetbundle folder path","name of assetbundle"));
            //load assets of bundle

            var mainMenuCanvas = mainmenu.LoadAsset<GameObject>("canvas");
            //verification if bundle was sucefully loaded

            if (mainmenu == null) {
                Debug.Log("Failed to load mainmenu AssetBundle!");
            }
            //instantiate objects

            Instantiate(mainMenuCanvas);
        }
    }
}

}

你可以使用第三个插件,比如 http://u3d.as/2MsR 使用像 RM.LoadAsset(assetname);