There are two different APIs that you can use to load AssetBundles.
This API is highly-efficient when loading uncompressed and chunk compressed bundles (LZ4) from local storage because it can read content of the file incrementally, directly from disk. Loading a file that is compressed with full file compression (LZMA) using this method is less efficient because it requires that the file be fully decompressed into memory first.
LoadFromFile
를 사용한 예제
using System.IO;
using UnityEngine;
public class LoadFromFileExample : MonoBehaviour
{
void Start()
{
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
Instantiate(prefab);
}
}
Rather than blocking your app during the load process you can also use the asynchronous version, AssetBundle.LoadFromFileAsync
.
There are several other methods available to load an AssetBundle if it is not actually stored in a local file. For example you can use AssetBundle.LoadFromMemoryAsync.
The UnityWebRequestAssetBundle API can be called to create a special web request for downloading, caching and loading AssetBundles.
Typically the URL would be a ‘https://’ address pointing to the file as exposed by a web service. It could also be ‘file://’ to access local data on platforms that do not support direct file system access.
This request can be passed into DownloadHandlerAssetBundle.GetContent(UnityWebRequestAssetBundle) to get the AssetBundle object for the loaded AssetBundle.
For example
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class DownloadExample : MonoBehaviour
{
IEnumerator Start()
{
string uri = "https://myserver/myBundles/bundle123";
uint crc = 1098980; // Expected content CRC
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, crc);
yield return request.SendWebRequest();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
var loadAsset = bundle.LoadAssetAsync<GameObject>("Assets/Players/MainPlayer.prefab");
yield return loadAsset;
Instantiate(loadAsset.asset);
}
}
For simplicity the example shows a CRC value that is hardcoded in the code. But in practice the expected CRC values for your AssetBundles would be downloaded separately, or retrieved from a file, prior to downloading the AssetBundles. See AssetBundle Download Integrity and Security.
Note: In order to avoid downloading the entire AssetBundle content each time this code is called you could enable caching for your AssetBundle. This is done by passing the AssetBundle hash when calling UnityWebRequestAssetBundle.GetAssetBundle. The hash is available from the AssetBundle Manifest, which is described later in this section. The hash acts as version identifier for the precise build of the AssetBundle that you are requesting. See AssetBundle compression and caching for details of the Cache and the associated considerations about compression.
Now that you’ve successfully loaded your AssetBundle, it’s time to finally load in some Assets.
일반 코드 스니핏:
T objectFromBundle = bundleObject.LoadAsset<T>(assetName);
T는 로드하려는 에셋 타입입니다.
에셋 로드 방법을 결정할 때 선택할 수 있는 몇 가지 옵션이 있습니다. LoadAsset
및 LoadAllAssets
와 각각에 Async를 추가한 LoadAssetAsync
또는 LoadAllAssetsAsync
를 선택할 수 있습니다.
에셋 번들에서 에셋을 동기식으로 로드하는 방법은 다음과 같습니다.
To load a single Asset (for example the root GameObject of a Prefab):
GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);
모든 에셋을 로드하려면 다음을 사용합니다.
Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
This returns an array with all the root Object of each Asset.
Now, whereas the previously shown methods return either the type of object you’re loading or an array of objects, the asynchronous methods return an AssetBundleRequest. You’ll need to wait for this operation to complete before accessing the asset. To load an asset asynchronously:
AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
yield return request;
var loadedAsset = request.asset;
또는
AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request;
var loadedAssets = request.allAssets;
에셋을 다운로드한 후 곧바로 시작할 수 있습니다! 로드된 오브젝트는 Unity의 다른 모든 오브젝트처럼 사용할 수 있습니다.
에셋 번들 매니페스트를 로드하면 에셋 번들의 종속성을 다루는 경우에 매우 유용할 수 있습니다.
유용한 AssetBundleManifest 오브젝트를 얻으려면 해당 추가 에셋 번들(들어가 있는 폴더와 이름이 같은 에셋 번들)을 로드하고 이 에셋 번들에서 타입이 AssetBundleManifest인 오브젝트를 로드해야 합니다.
매니페스트 자체를 로드하는 방법은 다른 에셋을 에셋 번들에서 로드하는 방법과 똑같습니다.
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
이제 위 예제의 매니페스트 오브젝트를 통해 AssetBundleManifest
API 호출에 액세스할 수 있습니다. 여기서 매니페스트를 사용해 해당 에셋 번들에 대한 정보를 얻을 수 있습니다. 이 정보에는 에셋 번들에 대한 종속성 데이터, 해시 데이터 및 배리언트 데이터가 포함됩니다.
The earlier section on AssetBundle Dependencies discussed how, in order to load an Asset from an AssetBundle, you must first load any AssetBundles that the AssetBundle depends on. The manifest object makes dynamically finding and loading dependencies possible, so you do not have to hardcode all the AssetBundle names and their relationships explicitly in your code. Let’s say we want to load all the dependencies for an AssetBundle named “assetBundle”.
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("assetBundle"); //Pass the name of the bundle you want the dependencies for.
foreach(string dependency in dependencies)
{
AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}
이제 에셋 번들 또는 에셋 번들 종속성과 에셋을 로드하려고 하므로, 이렇게 로드된 에셋 번들을 모두 관리하는 방법에 대해 설명하겠습니다.
Note: The Addressables package provides a ready-made system to manage loading AssetBundles, dependencies, and Assets. Unity recommends using Addressables rather than managing AssetBundles yourself.
참고 항목: 로드된 에셋 번들 관리의 Unity 학습 튜토리얼
Unity에서는 오브젝트가 액티브 씬에서 제거될 경우 자동으로 언로드되지 않습니다. 에셋 정리는 특정 시간에 실행되고, 수동으로 실행할 수도 있습니다.
It is important to know when to load and unload an AssetBundle. Improperly unloading an AssetBundle can lead to duplicating objects in memory or missing objects.
The biggest things to understand about AssetBundle management is when to call AssetBundle.Unload(bool) – or AssetBundle.UnloadAsync(bool) – and if you should pass true or false into the function call. Unload is a non-static function that will unload your AssetBundle by removing the AssetBundle header and other data structures from memory. The argument indicates whether to also unload all Objects instantiated from this AssetBundle.
AssetBundle.Unload(true)
unloads all GameObjects (and their dependencies) that were loaded from the AssetBundle. This does not include objects that you have copied into your scene (e.g. by calling Instantiate
) because that copied data does not belong to the AssetBundle. If the objects in your scene references Textures that were loaded from the AssetBundle (and still belong to it), then this call will cause the Textures to disappear, and Unity treats them as missing Textures.
As an example, let’s assume Material M is loaded from AssetBundle AB as shown below and used in Prefab P.
If AB.Unload(true) is called then any instance of M referenced from objects in the active scene will be destroyed.
If you were instead to call AB.Unload(false) then the instances of M will remain in memory. They will become independent objects that are not linked back to the original AssetBundle.
If AB is loaded again later Unity will not re-link the existing copies of M to the Material inside the AssetBundle.
If you create another instance of Prefab P, it will not use the existing copy of M. Instead a second copy of M is loaded.
Generally, using AssetBundle.Unload(false)
can lead to duplicated objects and other issues. Most projects should use AssetBundle.Unload(true)
to avoid this. There are two common strategies for safely calling AssetBundle.Unload(true)
:
애플리케이션 수명 중에 임시 에셋 번들이 언로드되는 시점(예: 레벨 간 또는 화면 로딩 중)을 분명히 정의하는 방법
개별 오브젝트에 대해 레퍼런스 카운트를 유지하고 모든 구성 오브젝트가 사용되지 않을 때만 에셋 번들을 언로드하는 방법. 이 방법을 사용하면 애플리케이션이 메모리 중복 없이 개별 오브젝트를 언로드하고 다시 로드할 수 있습니다.
애플리케이션이 AssetBundle.Unload(false)
를 사용해야 하는 경우 개별 오브젝트를 다음 두 가지 방법으로만 언로드할 수 있습니다.
Eliminate all references to an unwanted Object, e.g. make sure no other loaded object has a field that points to it. After this is done, call Resources.UnloadUnusedAssets.
씬을 추가하지 않고 로드하는 방법. 이 방법을 사용하면 현재 씬의 모든 오브젝트가 제거되고 Resources.UnloadUnusedAssets이 자동으로 호출됩니다.