【问题标题】:How can i load and instantiate any game object from assetbundle?如何从assetbundle 加载和实例化任何游戏对象?
【发布时间】:2019-12-04 15:11:12
【问题描述】:

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

我的示例资产:c6f97739ec43264ef3bfae7b1dc55e88.unity3d

链接:https://www.file-up.org/891dtdi54n0l

所以,我们已经使用了assetBundle.mainAsset 来访问那个游戏对象。但在统一 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. 如何使用新的资产包统一系统加载主要资产,因为我的资产包具有任何类型的游戏对象,例如:sprite、obj、声音、视频等。

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

【问题讨论】:

  • 有什么解决办法吗?

标签: unity3d instantiation assetbundle


【解决方案1】:

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

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

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

我们必须完成这个函数的编写,它不会返回这样的方法,但目前只需将其视为从给定捆绑包中请求给定资产的方法,您所关心的是你得到了一些回报。

2- 我不知道如何实例化加载的资产?

我们将通过修改我们的函数来获取更多参数来做到这一点,OnLoad 我们希望在我们想要的资产最终在内存中并且可用时发生,以及 OnLoadFailed 在 oops 时调用,坏事发生了。我们不知道加载捆绑包和/或加载资产需要多长时间,因此我们必须等待并依赖回调。

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!");
        }
    );
}

根据您要加载的类型,您需要对它做不同的事情,实例化它,将它分配给一个字段,等等。失败时,您可能想要打印某种消息。在运行时,您可能想要假设捆绑包总是成功(“我知道我会将它们一起发送”)或向用户显示一条消息(“下载捆绑包失败,请检查您的连接”)。由你决定。你甚至可以让OnLoadFail 函数接受一个字符串参数,这样你就可以提供更多信息(因为我们将从多个地方调用它)。

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

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

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,了解有关在代码中获取或使用资产包的更多详细信息,包括如何从远程位置下载以及Application 类,了解有关persistentDataPath 和相关路径的详细信息。

【讨论】:

  • 谢谢,我可以用纹理做什么?加载时,是否可以将其移至温度?还是..?
  • 您可以加载一个Texture2D 对象,您可以将其分配给组件的字段,变成精灵(并将其分配给组件),或者创建一个空的游戏对象,附加一个SpriteRenderer,并将精灵分配给它。
  • 再次感谢,但我无法理解 AssetManagement.Asset.Load,尤其是 AssetManagement!代码块 2 中的内容是什么?
  • 我很抱歉!事实证明,那段代码是我的项目的一部分,并且是几件事情的包装。我会看看我是否可以为你梳理一下并更新我的答案。
【解决方案2】:

从设备(本地)加载assetbundle

使用 System.IO;

使用 UnityEngine;

使用 UnityEngine.SceneManagement;

公共类 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);
        }
    }
}

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多