14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【unityプロ技】Advent Calendar 2019

Day 17

めんどくささから解放!AddressableAssetSystemの最新情報と使える小技!

Last updated at Posted at 2019-12-17

#初めに
AddressableAssetSystemは皆さん使われていますか?使っていても使っていなくても、ものすごく便利な機能だと思うので使っていない人はぜひ導入を検討してみてください!
ここではAddressableAssetSystemについての最近使えるようになった機能についての解説と個人的に便利だと思う小技について解説を行っていきます。またコード自体はパブリックドメインとしておきますのでご自由にお使いください。
#機能の名前が変更になった(1.3.2以降)
以前の機能の名称から少し変更になりました。以下にその表を記載しておくので参考にしてください

1.3.3以前 1.3.3以降
PlayMode
Fast Mode Use Asset Database
Virtual Mode Simulate Groups
Packed Mode Use Existing Build
BundledAssetGroupSchema Content Packing & Loading
ContentUpdateGroupSchema Content Update Restriction
Prepare for Content Update Tools/Check for Content Update Restriction
Build for Content Update Update a Previous Build
Profiler Event Viewer
#Addressables.PreloadDependenciesの名前の変更(0.6.6以降)
古いバージョンのAddressables.PreloadDependenciesはAddressables.DownloadDependenciesに変わりました。

#SpriteAtlasなどから個別にSpriteなどをAssetReferenceとして取り出せるようになった!(1.2.2以降)
この機能がどのように便利かというと、従来はSpriteAtlasからSpriteを取り出したいとき、GetSpriteで取り出すほかうまく動作させることが出来ませんでしたがこの機能があればAssetRefrenceにSpriteAtlasを指定するとサブアセットを取り出せるようになります。
いままで

LoadImage.cs
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.U2D;

public class LoadImage : MonoBehaviour
{
    [SerializeField] AssetReference target;
    private void Start()
    {
        Addressables.LoadAssetAsync<SpriteAtlas>(target).Completed += Loaded;
    }

    private void Loaded(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<SpriteAtlas> handle)
    {
        var atlas = handle.Result;
        var sprite = atlas.GetSprite("利用したいイメージ");
    }
}

と表記を行って、targetにはSpriteAtlasを入れてロードを行っていましたがこの新しい機能を使うとコード自体は単純な

LoadImage.cs
using UnityEngine;
using UnityEngine.AddressableAssets;

public class LoadImage : MonoBehaviour
{
    [SerializeField] AssetReference target;
    private void Start()
    {
        Addressables.LoadAssetAsync<Sprite>(target).Completed += Loaded;
    }

    private void Loaded(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<Sprite> handle)
    {
        var sprite = handle.Result;
    }
}

Spriteを読み込むScriptでよくなり
image.png
SpriteAltasを指定するとEditorの画面でSpriteAltasに内包されているアセットを参照することが可能なため文字列での参照を行わずにSpriteを取得することができます。
#UnityCloludBuildでビルドできるようになった
そのままです
image.png
CloudBuildのConfig欄にAddressableの欄が追加されここだけで完結することが可能となりました。
コンテンツだけをビルドするモードもあるので
#Taskでawaitできるようになった
文字通りですAsyncOperationHandleがTaskを持つようになったので

ImageTaskLoad.cs
using UnityEngine;
using UnityEngine.AddressableAssets;

public class ImageTaskLoad: MonoBehaviour
{
    [SerializeField] AssetReference target;
    async void Start()
    {
        Sprite image = await Addressables.LoadAssetAsync<Sprite>(target).Task;
    }
}

というUnityっぽくないモダンなコードを書くことが出来るようになりました。
またもしUniTaskを使っている場合は

ImageTaskLoad.cs
using System;
using System.Threading;
using UniRx.Async;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;

public static class AddressableGetAwaiterExtention
{
    public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> asset)
    {
        UniTaskCompletionSource<T> completionSource = new UniTaskCompletionSource<T>();
        asset.Completed += (result) =>
        {
            switch (result.Status)
            {
                case AsyncOperationStatus.None:
                    break;
                case AsyncOperationStatus.Succeeded:
                    completionSource.TrySetResult(result.Result);
                    break;
                case AsyncOperationStatus.Failed:
                    completionSource.TrySetException(result.OperationException);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(result.OperationException.ToString());
            }
           // completionSource.TrySetResult(result.Result);
        };
        return completionSource.Task.GetAwaiter();
    }
    public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> asset,CancellationToken cancellationToken)
    {
        UniTaskCompletionSource<T> completionSource = new UniTaskCompletionSource<T>();
        asset.Completed += (result) =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            switch (result.Status)
            {
                case AsyncOperationStatus.None:
                    break;
                case AsyncOperationStatus.Succeeded:
                    completionSource.TrySetResult(result.Result);
                    break;
                case AsyncOperationStatus.Failed:
                    completionSource.TrySetException(result.OperationException);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(result.OperationException.ToString());
            }
        };
        return completionSource.Task.GetAwaiter();
    }
    public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> enumerator)
    {
        return new UniTask<T>(enumerator.GetAwaiter<T>());
    }
}

を利用することで直接await Addressables.LoadAssetAsync();とさせることもできます。
#参照カウントをOnDestroy時に減らす
AddressableAssetSystemでは参照カウントを使ってリソースの管理をしています。ので基本的にはReleaseを明示して開放を行います、少しでもその手間を省くためにUniRxを導入している環境では拡張メソッドを使って以下のように書くことが可能になります。

ReleaseAssetOnDestroyExtensions.cs
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.ResourceManagement.AsyncOperations;
using UniRx;
using UnityEngine.AddressableAssets;

public static  class ReleaseAssetOnDestroyExtensions
{
    public static AsyncOperationHandle ReleaseAssetOnDestroy(this AsyncOperationHandle handle, Component component)
    {
        component.OnDestroyAsObservable().Subscribe(_ => Addressables.Release(handle));
        return handle;
    }
}

#AssetReferenceを自分で作成する
AssetreferenceはSerializeFieldなどでUnity側から取得する以外にもguidをコンストラクタに代入することで作成することが出来ます。使い道としてはシーンのguidを取得して(Assetreference.RuntimeKey.ToString()で取得できます)保存、再起動時にそのシーンから再開ということなどが考えられます。
#AssetReferenceTypeRestrictionの代替
AssetReferenceTypeRestrictionは何故か(本当に謎)廃止されてしまったのでAssetReferenceTを継承して制限するしようとなってしまいました詳しくはテラシュールブログのここにまとめてあります。

#終わりに
Addressableは個人的には外部から取得できるSerializeFieldだと思っていて、若干の手間や特殊な挙動はありますがAssetBundleよりはとても敷居が低く使えるようにチューンされています皆さんもぜひ使っていきましょう!

14
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?