Addressableについての疑問

1) Addressableについての疑問

2) AddressableはどのようにHot Updateを行うか

3)どのようにSceneViewカメラのShader変数を設定するか

4) ActivityのデフォルトはSingleTaskである原因

5) Resources.UnloadUnusedAssetsのコール時間が長い問題

---
##Addressable
**Q：最近Addressableについて学びました、完全に理解していないけれども、AssetBundleより容易く使えると感じます。公式ドキュメントAddressables 1.6.2を参考する時、疑問を持っているところはいくつかあります。**

**１．AssetBundleに比べて、Addressableのパッケージの粒度はどのように制御しますか？例えば、AssetBundleなら、複数のアセットを一つのAssetBundleにパッケージします。**

**２．自動的にAddressableの名及びLabelを設定するスクリプトはありますか？ちょっと規模があるプロジェクトでも、アセットの量は少なくないから、手動的に設定するのはあまり科学的ではないと思います。**

**３．Check for Content Update Restrictionsに関しては、公式ドキュメントにはNote:This command will do nothing if all your changes are confined to non-static groupsと書かれています。つまり、このチェックは非静的なGroupに対して効きません。問題は、どこかでこのGroupを定義しますか？どこからそれをnon-staticに定義するかstaticに定義するかを知りますか？**

**４．Unique Bundle IDsに関しても、公式ドキュメントにはTurn on“Unique Bundle IDs”within the AddressableAssetSettings Inspectorと書かれたが、見つかりませんでした。**
>A1：一番目の問題：

>Addressableは最終的にAssetBundleにパッケージするから、パッケージのストレージディレクトリは、各GroupのBundledAssetGroupSchemaが設定するBudle Modeによって決められます。同じGroupのアセットが一つのBundleにパッケージするかどうかも、BundledAssetGroupSchemaのBundle Modeによっても決定されます。Pack Togetherなら、一つのBundleにパッケージします。Pack Separatelyなら、各Entryを同じBundleにパッケージします。粒度の問題について、Asset Bundleの使用に似ていて、AddressableはBundleパッケージの依存関係を自動的に管理し、もし依存アセットが他のBundleパッケージにない場合、それらは自動的に独自のBundleにパッケージします。

>二番目の問題は下図の方法を参考できます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/53cfc661-338a-b4e2-e0c1-d24891a3f46f.png)

>A2：三番目の問題：
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/e120cc2c-77f4-ed29-c387-64705e582665.png)
>Cannot Change Post Release == static

>Can Change Post Release == non-static


>四番目の問題：
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/3a182d16-5d8d-c83d-7c31-0bab5262f51c.png)

---
##Addressable
**Q ：AdressableはどのようにHot updateを行うか教えていただけませんか。この前のプロジェクトには、全てのアセットをAssetBundleにパッケージしてStreamingAssetsに置いてから、更新されたAssetBundleがあるなら書き込み可能のディレクトリにダウンロードされます。それで、ゲームのロード時に、書き込み可能のディレクトリのAssetBundleを優先的にロードします。**


**では、Addressableでどのようにこのその機能を実装しますか？優先な読み取りのディレクトリを設定できますか？**
>A：問題主の「優先な読み取りのディレクトリを設定する」の意味はよく分からないが、一応自分の理解から説明しておきますね。Addressableのアセット更新機能はEditorとRuntimeの両方から処理する必要があります。

>Editorには、SettingにBuild Remote Catalogを選択します。

>初めてNew Buildを使用する時、Catalogファイル（.hashと.jsonファイル）、この二つのCatalogファイル及びパッケージされたBundleはサービサーに置くべきです。それからアセットの更新をしたいと、Update a Previous Buildをしてからパッケージします。こういう時、Editorは元のCatalogファイル（.hashと.jsonファイル）、同時に新しいBundleファイルは生成し、新しく生成されたファイルをサービサーの元のファイルに置き換えるだけで済みです。

>Runtimeには、CheckForCatalogUpdatesとUpdateCatalogsを呼び出してアセットを更新する必要があります。アセットはローカルに更新されたから、Addressable.LoadAssetAsyncを呼び出すとローカルのディレクトリからロードします。ここのローカルアセットは問題主おっしゃた優先アセットでしょうか。

>具体的なコードは以下を参照してください。

>https://answer.uwa4d.com/question/5e3b7fe686a39548919837e1

---
##Camera
**Q：エフェクトを作成するには、WorldToViewマトリックスを設定し、スクリプトをハングアップしてメインカメラにグローバル変数を設定する必要がありますが、メインカメラのWorldToViewマトリックスはSceneViewで引き続き使用されます。SceneViewがレンダリングされたときSceneViewのCamera属性を設定する方法はありますか？**

>A：GameViewカメラをSceneViewに同期する場合は、次の方法を試すことができます。

```
[InitializeOnLoad]
public static class SyncSceneViewMenuItem {
    private const string MenuName = "Tools/GameView カメラをSceneViewに同期する";
    private static bool enabled;

    static SyncSceneViewMenuItem() {
        SyncSceneViewMenuItem.enabled = EditorPrefs.GetBool(MenuName, false);
    this.Apply();
    }

    [MenuItem(MenuName)]
    public static void ToggleSync() {
        SyncSceneViewMenuItem.enabled = !SyncSceneViewMenuItem.enabled;
        EditorPrefs.SetBool(MenuName, SyncSceneViewMenuItem.enabled);
        this.Apply();
    }

    private void Apply() {
    Menu.SetChecked(MenuName, SyncSceneViewMenuItem.enabled);
        SyncSceneViewCamera.enabled= SyncSceneViewMenuItem.enabled;
    }
}
```
```
public class SyncSceneViewCamera : MonoBehaviour {
#if UNITY_EDITOR
    public static bool enabled;
    private Camera camera;
    private void Update() {
        if (SyncSceneViewCamera.enabled) {
            if (this.camera == null){
                this.camera = Camera.main;
            }
            UnityEditor.SceneView.lastActiveSceneView?.AlignViewToObject(this.camera.transform);
        }
    }
#endif
}
```
---
##Android
**Q： UnityによってエクスポートされたGradleプロジェクトは、デフォルトでUnityPlayerActivityをSingleTaskに配置します。ただし、実際のテストでは、多くのサードパーティSDKがSingleTaskの配置と競合します。**

**Unityがこのデフォルト設定を使用するのは、何か設計上の理由はありますか？Standardに変更したら、何か落とし穴は在りますか？**
>A1：主な目的は、ゲームが起動して2回目のクラッシュが発生するのを防ぐことですが、LaunchModeをSingleTaskとして信頼するだけでは不十分です。実際、サードパーティのSDKがあり、要件に従うように強制されます。たとえば、[Tencent](https://wikinew.open.qq.com/index.html#/home)チャネルにはSingleTopが必要です。

>ゲームのActivityのLaunchModeをSingleTopに設定する必要があります。SingleTopに設定した後、プラットフォームでゲームをプルアップすると、ゲームActivityが2つプルアップされる可能性があるため、ゲームActivityのonCreateで現在のActivityは重複なゲームActivityであるかどうかを確認する必要があります。重複している場合は、現在のゲームActivityを終了させます。

>だから、両手での準備がより万全だと思います。SingleTaskを使用できる場合は、SingleTaskを使用します。使用できない場合は、静的変数を使用して判断します。

>A2：これは、ダウンタイム数の統計を減らすのに一定の貢献があります。多くの場合、ゲームはSingleTaskに設定してからゲームに戻ったら、再びプルアップされる可能性があります。これはダウンタイム統計が増加させ、ダウンタイム率に大きな影響を与えます。

---

##Resource
Q：ゲームには、Prefabを表示するためのスキン、マウント、ウィングなどの外観が何百もあります。これらのPrefabはAssetBundleを介してロードされます。Prefabが作成されると、AssetBundle.Unload（false）が呼び出されてAssetBundleがアンロードされますが、GameObjectと対応するアセットもメモリに保持されます。

今の問題は、スマホでこれらすべての外観モデルをクリックした後、Resources.UnloadUnusedAssetsが初めて呼び出されたときに、20秒のフリーズが発生する可能性があります。もしGameObjectがDestroyされ、且つメモリ内の対応するアセットがすべてゴミになってリサイクルされる場合、Resources.UnloadUnusedAssetsの呼び出しが長時間スタックすることは理解できますが、今の問題は、これらのアセットが引き続き参照され、APIにクリアされませんか？他のアセットが原因ではないかと確認したら、AssetBundle.Unload（false）インターフェースをブロックすることさえも試したら、同じ操作では同じくフリーズが発生します。

この長い凍結の考えられる理由は何ですか？ Unityのバージョンは2017.4.30f1です。

更新：単一のPrefabアセットをロードしてみたら（AssetBundle.LoadAssetを呼び出した後）、他のリリースされたインターフェイスを呼び出さずに、cを直接呼び出すと、デバッグログの関連する表示は次のようになります。

27個の未使用のアセットをアンロードしてメモリ使用量を削減します。ロードされたオブジェクトは6777になりました。

Unloading 27 unused Assets to reduce memory usage. Loaded Objects now：6777.
Total: 20.391873 ms（FindLiveObjects: 1.497475 ms CreateObjectMapping：0.186901 ms MarkObjects: 15.905487 ms DeleteObjects: 2.801631 ms）

今の最大の問題は、この「27」はどこからなのか？どのアセットがゴミにマークされて削除されますか？
>A：20秒の場合、対応するログはありますか？ 4つのステップには、時間がかかるのはどのステップですか？およびObjectsの大きさを確認してください。

>テストコードは、次のように変更してみてください。

```
yield return Resources.UnloadUnusedAssets();
yield return Resources.UnloadUnusedAssets();  // この項のエクスポートはUnload 0 を確保する
var info0 = CreateIDToInfoMap(Resources.FindObjectsOfTypeAll<Object>()); // ディクショナリーを作成し、KeyはInstanceID，Valueはオブジェクトへの記述である

ab.LoadAsset();

yield return Resources.UnloadUnusedAssets();  
var info1 = CreateIDToInfoMap(Resources.FindObjectsOfTypeAll<Object>());


// info0とinfo1 を比較してプリントしてから、欠けるObjectを明確にする
```

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

今なら、UWA GOTローカルツールが**15日間に無償試用**できます！！
よければ、ぜひ！

UWA公式サイト：https://jp.uwa4d.com
UWA GOT OnlineレポートDemo：https://jp.uwa4d.com/u/got/demo.html
UWA公式ブログ：https://blog.jp.uwa4d.com