Load Scene in AssetBundle and Unload - unity3d

I load a scene in my AssetBundle like this:
IEnumerator AsyncLoad ()
{
using (var www = new WWW("file://" + Application.dataPath + "/AssetBundles/scenes"))
{
yield return www;
var bundle = www.assetBundle;
Application.LoadLevel("Scene1");
bundle.Unload(false);
}
}
The problem is sometimes Application.LoadLevel("Scene1"); works fine and sometimes Scene1 is empty. What's wrong here?
Side note: I noticed LoadLevel destroys the current scene before loading, so the lines after LoadLevel are not being executed (since the script was destroyed). As I need to unload the asset bundle in order to use it again another time, what's the solution?
Unity 5

you want to use dontdestroyonload on the object that has this loading script attached
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html

Application.LoadLevel will postpone load sceneobjects next frame, so you need to postpone unload AssetBundles.
IEnumerator AsyncLoad (){
using (var www = new WWW("file://" + Application.dataPath + "/AssetBundles/scenes")){
yield return www;
var bundle = www.assetBundle;
Application.LoadLevel("Scene1");
yield return null; // THIS LINE IS ADDED
bundle.Unload(false);
}
}
This may work for you.

Related

How can i load asset bundle which don't know the name of asset?

I want to load and instantiate asset from my asset bundle, but in unity 5.+ i can do it with code like this:
Note: my assetbundle have one asset inside itself, like:
AssetBundle myLoadedAssetBundle;
public string path;
void Start()
{
LoadAssetBundle(path);
}
void LoadAssetBundle(string bundleUrl)
{
myLoadedAssetBundle = AssetBundle.LoadFromFile(bundleUrl);
Debug.Log(myLoadedAssetBundle == null ? "Faild To Load" : "Succesfully Loaded!");
Debug.Log(myLoadedAssetBundle.mainAsset.name);
Instantiate(myLoadedAssetBundle.mainAsset);
}
}
actually even i use
Debug.Log(myLoadedAssetBundle.mainAsset.name);
to log name of mainasset of my assetbundle!
but in unity after 5+ , they say mainasset is obsolete.
my questions is:
1- How can i load asset bundle which don't know the name of asset?
2- How Instantiate or assign sprite which loaded of assetbundle ?
According to the AssetBundle documentation, there is now the ability to call GetAllAssetNames() to return a list of all asset names in a bundle as a string array. You can load the assets from the bundle via a for loop with those asset names.
Alternatively, if you are guaranteeing to only have 1 asset per bundle you can simply grab the string at index 0 (not recommended).
Additionally, you can load the assets without knowing the names by using LoadAllAssets() which returns an array of the specific type (in your case you would specify Sprite).
You could try something like this: (Note - You will need to know your directory path to each asset, here, I'll make some stuff up as an example)
private List<GameObject> assetBundle = new List<GameObject>();
private GameObject asset1 = Resources.Load("Weapon1") as GameObject;
private GameObject asset2 = Resources.Load("Weapon2") as GameObject;
private GameObject asset3 = Resources.Load("Weapon3") as GameObject;
private void Start()
{
assetBundle.Add(asset1);
assetBundle.Add(asset2);
assetBundle.Add(asset3);
}
Now you can access them from the list by element whenever you wish. However, I'm not 100% certain that Resources.Load() will work for what you're trying to do. I am about 65% - 70% though so I answered. Hope it helps!
Here's my solution,
IEnumerator LoadBundleFromDir(string bundleUrl)
{
//which type of asset i want load
GameObject model;
AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromFileAsync(bundleUrl);
yield return bundleRequest;
AssetBundle localeAssetBundle = bundleRequest.assetBundle;
Object[] allBundles = localeAssetBundle.LoadAllAssets();
foreach (Object item in allBundles)
{
if (item.GetType() == typeof(GameObject))
{
AssetBundleRequest assetRequest = localeAssetBundle.LoadAssetAsync<GameObject>(item.name);
yield return assetRequest;
model = assetRequest.asset as GameObject;
localeAssetBundle.Unload(false);
break;
}
}
}

Unity assetbundle scene unload

I have created few assetbundle scenes for my project. Now I am downloading the assetbundles and able to load scenes. Here the problem is that when I run a scene and exit from that and try to reload the same scene once again, it is giving an error like
"The Assetbundle mywebsite.com/bundles/assetbundle.unity3d can't be loaded because another AssetBundle with the same files is already loaded."
Im not able to open the scene for second time. Can anyone tell the problem and help me to resolve?! Thanks in advance.
Im adding the code here:
IEnumerator sceneLoad()
{
WWW www = WWW.LoadFromCacheOrDownload(myurl,version);
while (!www.isDone)
{
msg.text = "Downloading...";
float progress = Mathf.Clamp01 (www.progress / .9f);
progressslide.value = progress;
float val = progress * 100f;
double value = System.Math.Round (val, 2);
progresstext.text = value + "%";
Debug.Log ("Progress " + progresstext.text);
yield return null;
}
bundle = www.assetBundle;
msg.text = "Opening Scene...";
progressslide.gameObject.SetActive (false);
progresstext.gameObject.SetActive (false);
string[] scenepath = bundle.GetAllScenePaths ();
Debug.Log (scenepath [0]);
var async = SceneManager.LoadSceneAsync(System.IO.Path.GetFileNameWithoutExtension (scenepath [0]));
yield return null;
bundle.Unload (false);
}
The above code is perfectly working on unity engine in my pc but when I build apk and run on phone, the progress bar is not working but bundle is downloading and scene is opening. Later when I exit the scene, comes to my app main page and again open the same scene, it was showing the error as
"The Assetbundle mywebsite.com/bundles/assetbundle.unity3d can't be loaded because another AssetBundle with the same files is already loaded."
I am using Vuforia in the downloaded scene.
You should unload the loadded asset bundle when you exit the scene.
Maybe you will find this proper asset bundle guide.

Cannot load an Asset Bundle

I created an asset bundle from an .fbx file. Then; I use this code for loading it into a very simple unity project
public class k : MonoBehaviour {
public string url;
// Use this for initialization
public string AssetName;
void Start()
{
}
IEnumerator DownloadAndCache(string bundleURL)
{
while (!Caching.ready)
yield return null;
using (WWW www = WWW.LoadFromCacheOrDownload(bundleURL, 1))
{
yield return www;
if (www.error != null)
throw new Exception("WWW download had an error:" + www.error);
AssetBundle bundle = www.assetBundle;
if (AssetName == "")
Instantiate(bundle.mainAsset);
else
Instantiate(bundle.LoadAsset(AssetName));
bundle.Unload(false);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.D))
StartCoroutine(DownloadAndCache(url));
}
}
but always is having the next issue
and I don't understand. Since i'm passing a valid local url in the next format :
file:///c:/asset/robot.unity3d
please help
A file with a unity3d extension isn't usually an AssetBundle.
To have an AssetBundle with the model in it you have to:
Import the model in Unity
Select the imported model so you see its properties in the Inspector
At the bottom of the Inspector there is a little interface to create and select AssetBundles (this way the model will be assigned to the selected AssetBundle)
After assigning every asset to their AssetBundle, you need to build the Bundles
Put the bundles files on a server or in the StreamingAssets folder and use their URL
AssetBundle management in Unity is still a painfull process so I suggest you to thoroughly read the Guide to AssetBundles and Resources.
There is also an AssetBundleManager here but I find it's code is a mess.
It's buggy and almost impossible to decipher: I ended up writing my own so I can't really suggest you to use it yet (I linked it because it might get better in the future).
Try calling bundle.GetAllAssetNames() to see what is inside the bundle before trying to instantiate anything.
AssetBundle bundle = www.assetBundle;
foreach(var name in bundle.GetAllAssetNames()){
Debug.Log(name);
}
mainAsset may be null depending on how the AssetBundle was created, so maybe that is what happening here, does it gives you the null exception if you try loading assets by name?

Unity5 Building Asset Bundles with scenes

I am trying to create an asset bundle with scenes. This is what I did in unity4
[MenuItem("Bundle/Create ios Scene SceneLoader")]
static void iosBuild(){
string[] levels = new string []{"Assets/Scenes/01 SceneLoader.unity", "Assets/Scenes/02 Level1.unity","Assets/Scenes/02 Level2.unity" ,"Assets/Scenes/02 Level3.unity"};
BuildPipeline.BuildStreamedSceneAssetBundle( levels, "Assets/Bundles/bundle-ios.unity3d", BuildTarget.iOS);
}
After that I load my bundle via this code:
using(WWW www = WWW.LoadFromCacheOrDownload (url, 0)){
while(!www.isDone){
status.text = "loading \n" + (www.progress * 100).ToString() + "%";
yield return null;
}
yield return www;
//check if server response is an error
if (www.error != null){
throw new Exception("WWW download had an error: " + url + " " + www.error);
}
//Load the asset bundle
AssetBundle bundle = www.assetBundle;
//obsolete bundle.LoadAll();
bundle.LoadAllAssets();
Application.LoadLevel ("01 SceneLoader");
}
This code worked in unity4, but now, when I load my Scene, all the script references are missing. Objects are in the scene but no scripts. Also, unity tells me that BuildStreamedSceneAssetBundle is obsolete. So my question is, why aren't my script references in the core scene ? So that when I load an asset bundle, all the scripts aren't missing. Also my NGUI Atlas that I use in the loaded scene is missing.
Would be glad if someone has an idea!
EDIT: the first string in "levels" will have all script references. How is that possible ?
I think this problem is unity bug.
My project has same problem.
I found solution, but it's very inconvenient.
If you must use scene asset bundle,
make one asset bundle per one scene.
string[] level1 = new string []{"Assets/Scenes/01 SceneLoader.unity"};
string[] level2 = new string []{"Assets/Scenes/02 Level1.unity"};
.....
BuildPipeline.BuildStreamedSceneAssetBundle( level1, "Assets/Bundles/bundle-ios1.unity3d", BuildTarget.iOS);
BuildPipeline.BuildStreamedSceneAssetBundle( level2, "Assets/Bundles/bundle-ios2.unity3d", BuildTarget.iOS);
.....
I used "BuildPipeline.BuildAssetBundles" func at Unity5.
But I think that "BuildPipeline.BuildStreamedSceneAssetBundle" and "BuildPipeline.BuildAssetBundles" is similar.

Add remote image as texture during loop

I am very new to Unity3d.
I have a JSON array that contains the parameters of the prefabs I want to create at runtime.
I want to display images that are stored on my server in the scene.
I have a prefab "iAsset" that has a plane (mesh filter) and I want to load the image files as the texture of the plane.
I am able to Instatiate the prefabs however the prefab is showing up as a white square. This is my code:
for(var i = 0; i < bookData.Assets.Count; i++){
GameObject newAsset = null;
newAsset = (GameObject)Instantiate(iasset, new Vector3(2*i, 0, 0), Quaternion.identity);
if(!imageAssetRequested )
{
remoteImageAsset = new WWW(((BookAssets)bookData.Assets[i]).AssetContent);
imageAssetRequested = true;
}
if(remoteImageAsset.progress >=1)
{
if(remoteImageAsset.error == null)
{
loadingRemoteAsset = false;
newAsset.renderer.material.mainTexture = remoteImageAsset.texture;
}
}
}
the urls to the images on my server is retrieved from the JSON array:
((BookAssets)bookData.Assets[i]).AssetContent);
The code builds without any errors, I would very much appreciate any help to display the remote images.
You are not waiting for your downloads to complete.
The WWW class is asynchronous, and will commence the download. However, you need to either poll it (using the code you do have above) at a later time, or use a yield WWW in a CoRoutine that will block your execution (within that CoRoutine) until the download finishes (either successfully or due to failure).
Refer to Unity Documentation for WWW
Note however, that page sample code is wrong, and Start is not a CoRoutine / IEnumarator. Your code would look something like :
void Start()
{
... your code above ...
StartCoroutine(DownloadImage(bookData.Assets[i]).AssetContent, newAsset.renderer.material.mainTexture));
}
IEnumerator DownloadImage(string url, Texture tex)
{
WWW www = new WWW(url);
yield return www;
tex.LoadImage(www.bytes)
}