Unity Assetbundle Crawl Pit notes

Source: Internet
Author: User
Tags unique id

Transferred from: http://www.cnblogs.com/ybgame/p/3973177.html

This article from Assetbundle's packaging, use, management and memory footprint of the various aspects of a more comprehensive analysis of assetbundle use the process of some pits to fill guidelines and spray! Assetbundle is the way Unity recommends resource management, the official list of such as hot update, compression, flexibility and so on, but the Assetbundle pit is very deep, a lot of hidden details so you need to be very cautious, accidentally will fall into the deep pit, packaging is not planned well, 20MB of resources "compressed" to 30MB, or a large number of packages resulting in packaging and loading the various inefficiencies, or somehow lost associations, or memory explosion, and a variety of load failures, in the online study of a large number of articles on Assetbundle, but after each reading, there are still many questions, So only through practice to answer the questions in mind, in order to ensure the accuracy of the results, the following test under the editor, Windows,ios under the test comparison. First of all why you choose Assetbundle, even if he has thousands of advantages, but the general choice Assetbundle reason is to do hot update, dynamic update game resources, or you resource under the limit of resources (2GB or 4GB? If you do not have such a need, then it is recommended that you do not use this bad, upset ~ ~ When you choose Assetbundle, and I started to spray assetbundle before, We need to make a simple introduction to the Assetbundle Workflow: Assetbundle can be divided into packaging assetbundle and using Assetbundle packaging need to write some simple code under Unityeditor, to take out the resources you want to package , and then call the packaging method to package
Object obj = Assetdatabase.loadmainassetatpath ("Assets/test.png"); Buildpipeline.buildassetbundle (obj, null,                                  Application.streamingassetspath + "/test.assetbundle",                                 buildassetbundleoptions.collectdependencies | Buildassetbundleoptions.completeassets                                 | Buildassetbundleoptions.deterministicassetbundle, buildtarget.standalonewindows);

When using, you need to load the bundle with WWW, and then load the resource with the loaded bundle.
www w = new www ("file://" + Application.streamingassetspath + "/test.assetbundle"); mytexture = W.assetbundle.load ("Test" );

"One, pack"Next we look at packaging:   1. Collection of resources  Before packaging, we can walk through the directory to automate the packaging, you can selectively package some directories into a bundle, which can also be used to manage resources in various configuration files, but also can be used to manage the directory specification I use a directory specification for a large classification of resources, divided into public and in-game     , several large modules outside the game, and then use a set of simple naming conventions to guide packaging, such as using OBO (OneByOne) as a directory suffix to guide the directory of all resources to be packaged independently, default into a package, with the base prefix to indicate that this is a public package, the other directory in the sibling directory needs to rely on it Using the GetFiles and getdirectories of the directory makes it easy to get to the directories and files in the directory
    Directory.GetFiles ("Assets/mydirs", "* *", searchoption.topdirectoryonly);    Directory.getdirectories (Application.datapath + "/resources/game", "* *", searchoption.alldirectories);
2. Resource reads
The resource path that GetFiles collects can be loaded, before loading it needs to determine if the suffix is. Meta, if yes, do not remove the resource, then convert the path to a relative path at the beginning of assets, and then load the resource
    String NewPath = "Assets" + mypath. Replace (Application.datapath, "");    NewPath = newpath.replace ("\ \", "/");    Object obj = Assetdatabase.loadmainassetatpath (NewPath);
3. Packaging functionsWe call Buildpipeline.buildassetbundle to package: Buildpipeline.buildassetbundle has 5 parameters, the first is the primary resource, the second is the resource array, the two parameters must have a non-null, if the primary resource exists in the resource array, there is no relationship, if the master resource is set, you can pass the Bundle.mainasse T to use it directly the third parameter is the path, generally we set the target path to Application.streamingassetspath + bundle and bundle name fourth parameter has four options, buildassetbundleoptions. Collectdependencies is going to look for dependencies, Buildassetbundleoptions.completeassets will force the entire resource to be included, Buildassetbundleoptions.deterministicassetbundle will ensure that a unique ID is generated and will be useful when packaging dependencies, other options It doesn't make any sense. The fifth parameter is the platform, in Android, IOS,PC, we need to pass in different platform identity, to play different platform for the package, Note that the Windows platform is out of the package and cannot be used for iOS  Before hitting the corresponding package, you should select the appropriate platform to repackage 4. Packaged decisionsIn packaging, we need to balance the size and quantity of the package, all the resources into a package, a resource to hit a package, are more extreme, their problems are obvious, more often we need to combine them into a package of the disadvantage is to load this package, What we don't need will also be loaded in, Occupy extra memory, and not conducive to hot update into multiple packages of the disadvantage is that easy to create redundancy, first affect the packet read speed, and then the content between the package may be duplicated, and too many packages are not conducive to resource management which modules into a package, which modules into multiple packages, Need to be based on the actual situation, for example, each monster in the game needs to be a package, because each monster is independent, such as the game's basic UI, can be made into a package, because they will appear in each interface PS. To package the binaries in Assetbundle, the file name suffix must be ". bytes "Two, unpacking"Unpacking the first step is to load the bundle in, new a www into a URL to load bundles, we can pass in a bundle URL, download from the network, you can also pass in the path of the local package, generally we start with file://+bundle path, To specify the local bundle, specify the network bundle with HTTP//or https://start +bundle URL
String. Format ("File://{0}/{1}", Application.streamingassetspath, Bundlepath);
Under Android, the path is different, if it is the local bundle of the Android platform, you need to prefix it with jar:file://, and you need to set a special path to load
String. Format ("Jar:file://{0}!/assets/{1}", Application.datapath, Bundlepath);
After passing in the specified URL, we can load the bundle with WWW, and it takes some time to load the bundle, so we typically load the bundle in synergy, and if the load fails, you can get the reason for the failure in Www.error
IEnumerator loadbundle (string url) {    www www = = new www (URL);    yield return www;    if (www.error! = null)    {    debug.logerror ("Load Bundle faile" + URL + "error is" + www.error);    yield break;    }    Do something ...}
In addition to creating a WWW, there is another way to load bundle,www. Loadfromcacheordownload (URL, version), using this function will be much less memory footprint, but each repackaging will need to update the bundle corresponding version number (the second parameter version), or else may use the previous package, Instead of the newest package, Loadfromcacheordownload will extract the bundle from the network or program resources to a disk cache, which is generally understood to be extracted to a local disk, and if the local disk already has that version of the resource, use the extracted resources directly. For Assetbundle all memory usage, there is a section later that specifically describes it Loadfromcacheordownload records all the usage of bundles and, when appropriate, removes the most recently used resource bundles. It allows you to have two different versions of a resource bundle with the same name, which means that after you update the resource bundle, if you do not update the version number in the code, you may get an older version of the resource bundle, resulting in some other bugs. Also, when you're running out of disk space (the hard drive is exploding), loadfromcacheordownload is just a normal new www! The following section on memory introduction will also introduce this exclamation point to get the bundle, we need to load the resources inside, there are load,loadall and Loadasyn to choose from
    Load all objects Resource    object[] Objs = bundle. Loadall ();     Load the resource named obj    Object obj = bundle. Load ("obj");     Asynchronously loads a resource named Resname, type    assetbundlerequest res = bundle. LoadAsync (resname, type);        Yield return res;    var obj = Res.asset;
We often make a variety of game objects into a prefab, then prefab will be a common resource in our bundle, we need to pay attention to the use of prefab, The prefab loaded in the bundle cannot be used directly, it needs to be instantiated before it can be used, and for this prefab, after instantiation, the bundle can be freed.
    The    gameobject obj = gameobject.instantiate (bundle) needs to be instantiated first. Load ("Myprefab")) as Gameobject;
     for prefab loaded from bundles, it can be understood that we dragged directly from the resource directory to a public variable on the script, a prefab that was not instantiated, just a template      If you use the above code to load the resources, when your resources slowly up, you may find a very big problem, you have to load the resources failed to load, for example, you want to load a gameobject, but the entire loading process did not error, And when you want to use this gameobject, error, and the same code, we may not find this problem on the PC, when we hit the Android or iOS package, a resource failed to load.      This magical problem, first of all, is the question of packaging, the package is too big? Erase some of the content, no! A re-hit? Or not! And then found to go back and forth, is this a gameobject report of the fault, is this gameobject inside some resources have problems? To this gameobject all kinds of analysis, the big unloading eight pieces, processing into a very simple gameobject, or not! Is it a question of name? Change the name of this gameobject, please!      It's the end of the story, but it's too confusing! Moreover, the most important thing is that elder brother likes the original name!! Change this resource to a new name, how to see how to change the twist, how to see the original name is not good, so continue to toss up ~     first step tracking to this resource load, the resources were successfully load out, but the load out of something a little strange, Obviously not a gameobject, but a puzzling thing, maybe a middle object generated by unity, perhaps an indexed object, but it's not what I want, how does the packaged gameobject turn into this thing? So in the place where the bundle is loaded, loadall the bundle and then look at the contents of the bundle       Here we can see that There is a gameobject called Roomhallview and Roommainview, and the resources behind the Loadall are much more than the resources I have packed, and it seems that all the associated resources are automatically packed in. The 427 of the array is Roomhallview Gameobject, and 431 is the gameobject of Roommainview. You can see the name Roommai.Nview and Roomhallview have several objects, Gameobject,transform, and a name-only object whose type is a referencedata.      A closer look reveals that Roomhallview's Gameobject is the first of all the objects in the array named Roomhallview, And Roommainview is referencedata in front, when we load or Loadasyn, is the traversal of an array, when traversing to the name matching object, the object is returned, Loadasyn will match the type, But since we passed in an object, and almost all objects are object, the result returned is the first matching object       in Load and Loadasyn, in addition to the name, the type of the object to be loaded is also passed in, and debugging, the original name can also be read to the normal, this detail is very pit, because there is no reminder on the official website, and the sample is not said to be aware of this place, and there is a small chance of problems. So when it comes up, it's a dead hole.
Bundle. Load ("Myprefab", typeof (Gameobject))
Other than that do not test assetbundle on the iOS emulator, you will receive the bad URL error "Three, Reliance"Dependence and packaging are closely related, the reason is to separate the dependence, because this thing is too pit ... "1. Packaging dependencies" When we pack up two resources into separate packages, the resources shared by two resources will be packaged in two parts, resulting in redundancy, and So we need to pull out the public resources, make a bundle, and then two resources to rely on the public package, then there is another way to make them three dozen into a package, but this is not conducive to later maintenance we use Buildpipeline.pushassetdependen Cies () and buildpipeline.popassetdependencies () to turn on dependencies between bundles, when we call pushassetdependencies, we turn on dependency mode, and when we pack A B C in turn, If a contains a resource for B, B does not contain the resource, but rather relies on a, and if A and b contain the resources of C, then the resource of C will not be packaged in the old, but instead rely on a and B. As long as we have the same resources, we will rely on it, when we want B and C to rely on a, but B and C do not depend on each other, we need to nest push POPs, when we call popassetdependencies will end the dependency
  string path = Application.streamingassetspath;   Buildpipeline.pushassetdependencies ();    Buildtarget target = buildtarget.standalonewindows;                                 Buildpipeline.buildassetbundle (Assetdatabase.loadmainassetatpath ("assets/ui_tck_icon_houtui.png"), NULL,  Path + "/package1.assetbundle", buildassetbundleoptions.collectdependencies | Buildassetbundleoptions.completeassets |    Buildassetbundleoptions.deterministicassetbundle, Target);                                 Buildpipeline.buildassetbundle (Assetdatabase.loadmainassetatpath ("Assets/new material.mat"), NULL, Path + "/package2.assetbundle", Buildassetbundleoptions.collectdependencies | Buildassetbundleoptions.completeassets |    Buildassetbundleoptions.deterministicassetbundle, Target);  Buildpipeline.pushassetdependencies (); Buildpipeline.buildassetbundle (Assetdatabase.loadmainassEtatpath ("Assets/cube.prefab"), NULL, path + "/package3.assetbundle", buildassetbundleoptions.collectdependencies | Buildassetbundleoptions.completeassets |  Buildassetbundleoptions.deterministicassetbundle, buildtarget.standalonewindows);     Buildpipeline.popassetdependencies ();  Buildpipeline.pushassetdependencies ();                                 Buildpipeline.buildassetbundle (Assetdatabase.loadmainassetatpath ("Assets/cubes.prefab"), NULL, Path + "/package4.assetbundle", Buildassetbundleoptions.collectdependencies | Buildassetbundleoptions.completeassets |  Buildassetbundleoptions.deterministicassetbundle, Target);   Buildpipeline.popassetdependencies (); Buildpipeline.popassetdependencies ();
The above code demonstrates how to use dependencies, this test uses a texture, a material, a cube prefab, and two cubes of the prefab, the texture of the material used, and the two groups of cubes use this material, the above code with push to open the dependency, packaging texture,     Then packaging the material (the material automatically depends on the texture), and then nested a push, packaging the cube (the cube depends on the front of the material and texture), then pop, then nested a push, packaging that group of cubes (independent of the front cube, dependent on the material and texture)     If we only open the outermost push POPs, without nesting push pops, then the prefab of the two cubes will rely on the prefab of a single cube, relying on a double-edged sword, which can remove redundancy, but sometimes we need a little redundancy "2. Dependency Loss" When we have dependencies between bundles, we cannot simply load the corresponding bundles as before, we need To load the bundle that the bundle relies on first, this load is just www or Loadfromcacheordownload, there is no need to load this bundle, if Bundleb relies on Bundlea, when we want to load Bundleb resources, assuming Bundlea is not loaded, or has been unload, then Bundleb dependent Bundlea parts will be lost, for example, each cube is hung with a script, When we do not nest push POPs, the bundles of a single cube are not loaded or unloaded, and the script on the set of cubes we load is lost, scripts are also a resource, when a script has been packaged, dependent on the resources of this package, it will not be called back into the cubes and cube mount the same script, Testobje,cubes depends on the cube, the cube is located in the bundle Unload, and then load cubes bundle,     Cubes's scripts are missing, scripts, textures, materials and all the resources are so "3. Update Dependencies" In packaging we need to specify the Buildassetbundleoptions.deterministicassetbundle option, which generates a unique ID for each resource, and when the resource is repackaged, it is determined that the ID does not change, and that the dependency of the package is based on that ID. , the advantage of using this option is that when a resource needs to be updated, it relies on other resources of that resource, does not need to repackage A-B-C when a relies on B, b updates, needs to repackage c,b, and A does not need to move, packing C because B depends on C, if C is not packaged, straight Pack B, then C's resources will be re-packaged, and B and C dependencies will be broken "Four, Memory"When using the WWW load bundle, will open up a piece of memory, this memory is the bundle file after decompression memory, which means that the memory is very large, through the bundle.unload can be freed out of this memory, Unload true and Unload false Will release this memory, and this bundle can no longer be used, if you want to re-use, you need to reload the bundle, It is important to note that other bundles that rely on this bundle will get an error when loadAfter getting bundles, We use Bundle.load to load resources, which are copied from the bundle's memory and put into memory as asset, which means that this memory, too, is very large, asset the release of memory, like the release mechanism of other unity resources, can be resources.unloadunus Easset to release a resource that is not referenced, or by Bundle.unload (true) to force the release of asset, which causes all objects referencing this resource to lose the resource the two paragraphs above can come to the conclusion that at New WWW (URL), will open up a memory to store the extracted bundle, and after the resources are load out, will open up a piece of memory to store asset resources, WWW. The Loadfromcacheordownload (URL) function is the same as the new WWW (URL), but loadfromcacheordownload is extracting the bundle into disk space instead of memory. So the WWW object returned by Loadfromcacheordownload itself does not take up too much memory (just some index information, the disk path for each resource, and the disk that is removed from the drive at load), for a small amount of memory on the phone. Use WWW. Loadfromcacheordownload replaces new www to save memory efficiently。 But Loadfromcacheordownload Dafa also has a time when it is not efficacious, L Oadfromcacheordownload The returned WWW object will occupy the same memory as the new WWWSo no matter how your bundle is created, you need to unload it out in time when you're not using it.。 Another problem to be aware of when using loadfromcacheordownload is that the second parameter, the version number, the bundle is repackaged, the version number is not updated, and the old version of the bundle is removed. And there may be multiple older bundles in a bundle cache, such as a three-in-one bundle that does not need to use the bundle after the bundle has been load, unload, if there are other bundles that depend on the bundle,        You should wait for bundles that depend on the bundle to not load again, unload this bundle, usually in the big scene switch. We know that when bundling bundles, one parameter is Mainasset, and if passed in, then the resource is treated as the master resource package, and after the bundle is obtained, Can be used directly with Assetbundle.mainasset, then whether to get bundles at www, the Mainasset has been pre-load out? No! before we call when Assetbundle.mainasset takes out Mainasset, its get method blocks to load MainassetAnd then returns, Assetbundle.mainasset equivalent to the load ("Mainassetname") PS. Repeating load the same resource does not open up new memory to store this resource "Five, other"In the development process of using assetbundle, we often adjust the resources, then we need to package the resources to take effect and have a great impact on the development efficiency, so we use resource and bundle compatible ways in development. It is up to you to encapsulate the resource management in a manager, from the load resource in the bundle to the load resource in the resource, so that the upper logic code does not need to care about the current resource management type of course, all of our objects to be packaged, are in the resource directory, and use strict directory specifications, and then use the script object to record the bundle of each resource, and the corresponding resource directory, in the event of resource changes, update the Script object, manager at run time using the Script object configuration information, Here the Script object we are automatically generated using code, of course, you can also use the configuration table, the effect is the same version management can also be referred to the script object to implement, each package of resources, need to be version number +1, the script object can store all the resources of the version number, The version number can be used for loadfromcacheordownload, or can be manually written to the configuration table, in the Script object I designed, each resource will have a subordinate bundle,resource under the relative path, version number and other three properties when the release of the version, You need to pack the bundle once, change the resource directory to another name, and then package it to make sure that the resources in the resource directory are not re-packaged, and if you want to hit the resource version, You will need to delete the bundle file under Streamingassets using the following script object: 1. Design the storage structure first 2. Write a class that inherits from ScriptObject, stores the data structure with a serializable container (list or array), dictionary, etc. Container cannot be serialized, public after
[Serializable]public class resconfigdata{public    string resname;//Resource name public    string Bundlename;//Package name    public string Path; Resource path public    int vesrion;//Version number} [System.serializable]public class resconfig:scriptableobject{public    List <ResConfigData> Configdatas = new list<resconfigdata> ();}
4. Read the object in the specified path, and create the object if it is not read
Resconfig obj = (resconfig) assetdatabase.loadassetatpath (Path, typeof (Resconfig)), if (obj = = null) {   obj = Scriptableobject.createinstance<resconfig> ();   Assetdatabase.createasset (obj, path);}
3. Write the data, modify the array of obj directly and save (without saving the next time the unity data will be lost)
Editorutility.setdirty (obj);
Because the array operation is inconvenient, we can convert the data into a dictionary container store that facilitates various additions and deletions, and writes it to the persisted container when it is persisted.

Finally, found that some of the previous articles were "original", Do not "original" this article

(turn) Unity assetbundle Crawl Pit notes

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.