1
votes

I have some assetbundles which we create for unity 5.6 automatically, any of these assetbudles has one game object inside it.

my example asset: c6f97739ec43264ef3bfae7b1dc55e88.unity3d

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

so, we have already used assetBundle.mainAsset to access to that one game object. but in unity 2018.3 , the assetBundle.mainAsset is obsolete.

i read the unity document and they say use

LoadAsset<GameObject>(name);

with name or type ! but when i create asset bundle, i don't know the gameobject name to access it.

i try to load it with : 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);
}

my question is :

  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.

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

2

2 Answers

1
votes

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.

You would have to use a generic function, eg:

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

We'll have to finish writing this function, and its not going to return a method like that, but for the moment just think of it as a method that requests a given asset from a given bundle and all you care is that you get something back.

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

We're going to do this by modifying our function to take two more parameters, OnLoad which we want to have happen when the asset we want is finally in memory and available, and OnLoadFailed which gets called when oops, something bad happened. We don't know how long it will take to load the bundle and/or load the asset, so we have to wait and rely on the callbacks.

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!
    }
}

Now you'll have to specify what type you want when you call the function (which you needed before anyway, but you were always using GameObject) as well as callback functions when things are loaded (or they fail).

So, an example of how to call this:

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

Depending on what type you're loading you'd need to do different things with it, Instantiating it, assigning it to a field, whatever. On failure, you probably want to print some kind of message. In runtime you may either want to assume that the bundle always succeeds ("I know that I'll be shipping them together") or display a message to the user ("Failed to download bundle, check your connection"). Its up to you. You could even make the OnLoadFail function take a string parameter so you can provide more information (as we're going to call it from multiple places).

Now, though, we have to finish writing out our actual load method. We've templated out what it needs to look like (takes in a bundle name, an asset name, and has two callback functions), but we still need to do the actual loading.

We know it isn't going to return right away (that's why we created callbacks), so we need to move our contents off to a new method, which will be a coroutine, so we need to start that coroutine.

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!
    }
}

This next bit is going to replace those four lines inside DoLoad, as it chunk is going to be rather large, just wanted to make sure that the added layer to handle a coroutine was understood. All that's going on below is that we're requesting that an asset bundle be loaded, when that finishes, we have to request an asset out of the bundle, and when that finishes, call OnLoad.Invoke(obj). And at every step, if something goes pear-shaped, call OnLoadFailed.Invoke() instead.

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();
}

Be sure to check out 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 for details on the persistentDataPath and related paths.

0
votes

Load assetbundle from device(local)

using System.IO;

using UnityEngine;

using 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);
        }
    }
}

}