Unity AssetBundleの基本と実装ガイド

AssetBundleの概要 (Unity 2017ベース)

AssetBundleは、ゲーム実行時に動的に読み込むことができる圧縮ファイル形式です。モデル、テクスチャ、プレハブ、音声、さらにはシーン全体を含むことができます。

AssetBundleの定義と役割

AssetBundleの主な特徴:

  • モデル、テクスチャ、プレハブ、音声、シーンなどを含む圧縮パッケージ
  • 相互依存関係を保持(manifestファイルに記録)
  • LZMAとLZ4圧縮アルゴリズムを使用可能
  • インストールサイズの削減に貢献

AssetBundleの実体

AssetBundleは2つの側面を持つ:

  1. ハードドライブ上のファイル形式
    • シリアライズされたファイル(オブジェクトとして保存)
    • リソースファイル(画像、音声など)
  2. AssetBundleオブジェクト
    • コードからロード可能なオブジェクト
    • パッケージ内の全コンテンツを保持

AssetBundleの使用フロー

基本設定

リソースのAssetBundleプロパティを指定(フォルダ名/リソース名形式)

コンパイラ拡張によるビルド

using UnityEngine;
using UnityEditor;
using System.IO;

public class AssetBundleCreator
{
    [MenuItem("Tools/Build Asset Bundles")]
    static void BuildAllAssetBundles()
    {
        string outputPath = "Resources/AssetBundles";
        if (!Directory.Exists(outputPath))
        {
            Directory.CreateDirectory(outputPath);
        }
        
        BuildPipeline.BuildAssetBundles(
            outputPath, 
            BuildAssetBundleOptions.None, 
            BuildTarget.StandaloneWindows64
        );
    }
}

AssetBundleの構造

ビルド後のフォルダ構造はリソースの設定に基づいて作成されます。manifestファイルは依存関係を管理します。

AssetBundleの読み込み方法

1. ファイルからの読み込み

using System.Collections;
using UnityEngine;

public class FileLoader : MonoBehaviour
{
    private IEnumerator Start()
    {
        // 依存関係のあるリソースを先に読み込む
        AssetBundle dependencyBundle = AssetBundle.LoadFromFile("Resources/AssetBundles/materials/shared");
        AssetBundle mainBundle = AssetBundle.LoadFromFile("Resources/AssetBundles/levels/level_01");
        
        // 特定のリソースを読み込み
        GameObject levelPrefab = mainBundle.LoadAsset<GameObject>("LevelObject");
        Instantiate(levelPrefab);
        
        yield return null;
    }
}

2. メモリからの読み込み(非同期)

using System.Collections;
using UnityEngine;

public class MemoryLoader : MonoBehaviour
{
    private IEnumerator Start()
    {
        string bundlePath = "Resources/AssetBundles/ui/main_ui";
        byte[] fileData = File.ReadAllBytes(bundlePath);
        
        // 非同期読み込み
        AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(fileData);
        yield return request;
        
        AssetBundle bundle = request.assetBundle;
        GameObject uiElement = bundle.LoadAsset<GameObject>("UIPanel");
        Instantiate(uiElement);
    }
}

3. UnityWebRequestによるリモート読み込み

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class RemoteLoader : MonoBehaviour
{
    private IEnumerator Start()
    {
        // キャッシュの準備を待つ
        while (!Caching.ready)
            yield return null;
            
        string url = "http://yourserver.com/AssetBundles/characters/character_model";
        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url);
        yield return request.SendWebRequest();
        
        if (request.result != UnityWebRequest.Success)
        {
            Debug.LogError("Error loading bundle: " + request.error);
            yield break;
        }
        
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        GameObject character = bundle.LoadAsset<GameObject>("Character");
        Instantiate(character);
    }
}

4. 依存関係のあるAssetBundleの読み込み

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class DependencyLoader : MonoBehaviour
{
    private IEnumerator LoadWithDependencies(string manifestUrl)
    {
        // マニフェストファイルの読み込み
        UnityWebRequest manifestRequest = UnityWebRequestAssetBundle.GetAssetBundle(manifestUrl);
        yield return manifestRequest.SendWebRequest();
        
        AssetBundle manifestBundle = DownloadHandlerAssetBundle.GetContent(manifestRequest);
        AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        
        // 全てのAssetBundleを取得
        string[] bundleNames = manifest.GetAllAssetBundles();
        
        foreach (string bundleName in bundleNames)
        {
            string bundleUrl = manifestUrl + "/" + bundleName;
            UnityWebRequest bundleRequest = UnityWebRequestAssetBundle.GetAssetBundle(bundleUrl);
            yield return bundleRequest.SendWebRequest();
            
            if (bundleRequest.result == UnityWebRequest.Success)
            {
                AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(bundleRequest);
                Object[] assets = bundle.LoadAllAssets();
                
                foreach (Object asset in assets)
                {
                    if (asset is GameObject go)
                    {
                        Instantiate(go);
                    }
                }
            }
        }
    }
}

AssetBundleのグループ化戦略

論理エンティティ別グループ化

  • UI関連リソースを1つのパッケージに
  • キャラクター関連リソースを1つのパッケージに
  • 共有リソースを1つのパッケージに

タイプ別グループ化

  • 全ての音声リソースを1パッケージ
  • 全てのシェーダーを1パッケージ
  • 全てのモデルを1パッケージ

使用状況別グループ化

  • 特定のレベルで使用するリソースを1パッケージ
  • 特定のシーンで使用するリソースを1パッケージ

依存関係のパッキング

モデルプレハブが使用するマテリアルやテクスチャを統合することで、メモリ使用量を最適化し、リソースの重複読み込みを防ぎます。

BuildAssetBundleのパラメータ詳細

  • BuildAssetBundleOptions.None: LZMA圧縮、小さいサイズだが読み込みに時間がかかる
  • BuildAssetBundleOptions.UncompressedAssetBundle: 非圧縮、読み込みが速いがサイズが大きい
  • BuildAssetBundleOptions.ChunkBasedCompression: LZ4圧縮、部分読み込みが可能

AssetBundleのアンロード

メモリ管理のために不要になったAssetBundleを解放します。

  • AssetBundle.Unload(true): 使用中のリソースも含めて全て解放
  • AssetBundle.Unload(false): 未使用のリソースのみ解放
  • Resources.UnloadUnusedAssets(): 未使用リソースの解放

AssetBundleファイルの検証

ファイルの整合性を確認するための検証方法:

  • CRC: 計算効率が高いが安全性は低い
  • MD5: より高い安全性を持つハッシュ値
  • SHA1: 最も高い安全性を持つハッシュ値

タグ: Unity AssetBundle リソース管理 ゲーム開発 メモリ最適化

7月24日 06:34 投稿