API для доступа к содержимому файлов AssetBundle.
Этот класс предоставляет API в виде статических методов для загрузки AssetBundle и управления ими.
Этот же класс предлагает нестатические методы и свойства, открывающие содержимое конкретного загруженного AssetBundle, в том числе загрузку ассета из него.
Создание AssetBundles путем вызова BuildPipeline.BuildAssetBundles или с использованием Addressables пакет. Процесс сборки формирует один или несколько файлов AssetBundle, и каждый такой файл содержит сериализованный экземпляр этого класса.
Дополнительные ресурсы: Введение в AssetBundles, UnityWebRequestAssetBundle.GetAssetBundle, BuildPipeline.BuildAssetBundles.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class SampleBehaviour : MonoBehaviour
{
IEnumerator Start()
{
var uwr = UnityWebRequestAssetBundle.GetAssetBundle("https://myserver/myBundle.unity3d");
yield return uwr.SendWebRequest();
// Get an asset from the bundle and instantiate it.
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
var loadAsset = bundle.LoadAssetAsync<GameObject>("Assets/Players/MainPlayer.prefab");
yield return loadAsset;
Instantiate(loadAsset.asset);
bundle.Unload(true);
}
}
Сцены внутри AssetBundles
- AssetBundle может содержать сцены или ресурсы, но не может содержать комбинацию обоих типов.
- AssetBundle.LoadAssetи другие методы Load не поддерживают загрузку сцен из AssetBundles.
- Сцены могут быть загружены из AssetBundles с помощью SceneManager. При запуске в режиме Проигрывателя или Редактирования в Редакторе, сначала загрузите сцены, содержащие AssetBundle. Затем вызовите SceneManager.LoadScene или SceneManager.LoadSceneAsync с путем или именем сцены.
- Когда Редактор находится в режиме редактирования, он не поддерживает загрузку сцен из AssetBundles. Вызовы EditorSceneManager.OpenScene с путем сцены внутри загруженного AssetBundle не удается и регистрирует ошибку, указывающую, что файл сцены не найден.
//This example shows how to build a scene into an AssetBundle, and then build a Player with that AssetBundle included.
//When the Player starts it loads the scene and then unloads after a few seconds.
//
//To try this example:
// - Save it into a file, for example "Assets/AssetBundleSceneLoader.cs". The source file name needs to match the name of the MonoBehaviour.
// - From the Editor Menu select "Example" / "Scene in AssetBundle Example".
//
//It is also possible to try it in Play mode in the Editor:
// - Run the menu at least once to create the scenes and AssetBundle
// - Open "Assets/Scenes/StartingScene.unity"
// - Enter Play mode
using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEditor.SceneManagement;
#endif
public class Constants
{
// Scene in the project that is intended for an AssetBundle
public static readonly string SceneForAssetBundle = "Assets/Scenes/SceneForBundle.unity";
// Scene for the Player build that contains the "AssetBundleSceneLoader" MonoBehaviour
public static readonly string StartingSceneForPlayer = "Assets/Scenes/StartingScene.unity";
// Note: AssetBundles are always created lower case
public static readonly string AssetBundleFileName = "scenebundle";
// Path for AssetBundle (relative to the StreamingAsset location)
public static readonly string AssetBundlePath = "/AssetBundles";
// Output directory for the player build (Relative to project and not inside Assets)
public static readonly string PlayerBuildPath = "PlayerBuild";
// Name of the player executable inside PlayerBuildPath
public static readonly string PlayerExecutable = "PlayerBuild";
}
#if UNITY_EDITOR
// Note: Typically this would be in its own source file, in an Editor-only assembly.
public class BuildBundleWithScene
{
[MenuItem("Example/Scene in AssetBundle Example")]
public static void BuildAssetBundle()
{
// Location inside StreamingAssets so the AssetBundle content is included in the Player
string AssetBundleBuildPath = Application.streamingAssetsPath + Constants.AssetBundlePath;
// Create the content expected by this example
CreateStartingScene();
CreateSceneForAssetBundle();
var buildTargetPlatform = EditorUserBuildSettings.activeBuildTarget;
if (!Directory.Exists(AssetBundleBuildPath))
Directory.CreateDirectory(AssetBundleBuildPath);
// Define an AssetBundle containing the Scene
var bundleContents = new AssetBundleBuild[]
{
new AssetBundleBuild()
{
assetBundleName = Constants.AssetBundleFileName,
assetNames = new string[]
{
Constants.SceneForAssetBundle
}
}
};
var buildAssetBundlesParameters = new BuildAssetBundlesParameters()
{
targetPlatform = buildTargetPlatform,
bundleDefinitions = bundleContents,
outputPath = AssetBundleBuildPath
};
BuildPipeline.BuildAssetBundles(buildAssetBundlesParameters);
var buildReport = BuildReport.GetLatestReport();
if (buildReport.summary.result != BuildResult.Succeeded)
{
Debug.Log("AssetBundle Build failed.");
return;
}
// Perform a Player build. It will include the content of the
// StreamingAssets folder.
if (!Directory.Exists(Constants.PlayerBuildPath))
Directory.CreateDirectory(Constants.PlayerBuildPath);
var buildOutput = Constants.PlayerBuildPath + "/" + Constants.PlayerExecutable;
if (buildTargetPlatform == BuildTarget.StandaloneWindows64)
buildOutput += ".exe";
var buildPlayerParameters = new BuildPlayerOptions()
{
scenes = new string[] { Constants.StartingSceneForPlayer },
target = buildTargetPlatform,
locationPathName = buildOutput,
options = BuildOptions.Development | BuildOptions.AutoRunPlayer,
assetBundleManifestPath = AssetBundleBuildPath + "/AssetBundles.manifest"
};
if (buildTargetPlatform == BuildTarget.StandaloneWindows64)
buildPlayerParameters.locationPathName += ".exe";
var playerBuildReport = BuildPipeline.BuildPlayer(buildPlayerParameters);
if (playerBuildReport.summary.result != BuildResult.Succeeded)
{
Debug.Log($"Player Build failed. {playerBuildReport.SummarizeErrors()}");
return;
}
}
static void CreateStartingScene()
{
var startingScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
var go = new GameObject();
go.AddComponent<AssetBundleSceneLoader>();
GameObject.CreatePrimitive(PrimitiveType.Sphere);
EditorSceneManager.SaveScene(startingScene, Constants.StartingSceneForPlayer);
}
static void CreateSceneForAssetBundle()
{
var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
GameObject.CreatePrimitive(PrimitiveType.Cube);
EditorSceneManager.SaveScene(scene, Constants.SceneForAssetBundle);
}
}
#endif
// MonoBehaviour that is included in the starting scene.
public class AssetBundleSceneLoader : MonoBehaviour
{
AssetBundle sceneBundle = null;
bool sceneLoaded = false;
// Triggered when the scene containing this MonoBehaviour is loaded
void Start()
{
StartCoroutine(LoadAssetBundleAndScene());
StartCoroutine(CleanupAfterDelay());
}
IEnumerator LoadAssetBundleAndScene()
{
// Determine the path to the AssetBundle.
// Application.streamingAssetsPath is used so that this works in both the Player and Play mode in the Editor.
string AssetBundleBuildPath = Application.streamingAssetsPath + Constants.AssetBundlePath;
var bundlePath = AssetBundleBuildPath + "/" + Constants.AssetBundleFileName;
var op = AssetBundle.LoadFromFileAsync(bundlePath);
yield return op;
sceneBundle = op.assetBundle;
if (sceneBundle == null)
{
Debug.LogError("Failed to load AssetBundle: " + Constants.AssetBundleFileName);
}
else
{
var sceneLoadOp = SceneManager.LoadSceneAsync(Constants.SceneForAssetBundle, LoadSceneMode.Additive);
if (sceneLoadOp == null)
Debug.Log($"Failed to load {Constants.SceneForAssetBundle}");
else
{
yield return sceneLoadOp;
Scene sceneLookup = SceneManager.GetSceneByPath(Constants.SceneForAssetBundle);
//Will report "Finished loading SceneForBundle (index -1)."
Debug.Log($"Finished loading {sceneLookup.name} (index {sceneLookup.buildIndex}).");
sceneLoaded = true;
}
}
}
IEnumerator CleanupAfterDelay()
{
yield return new WaitForSeconds(3.0f);
if (sceneLoaded)
yield return SceneManager.UnloadSceneAsync(Constants.SceneForAssetBundle);
sceneLoaded = false;
if (sceneBundle != null)
yield return sceneBundle.UnloadAsync(true);
sceneBundle = null;
Debug.Log("Finished unloading Content");
}
}