UIにおいてSetActiveが大量に使用される問題

今回の話題：
1）UIにおいてSetActiveが大量に使用されるなら、どのように最適化するか
2）ASTC圧縮とETC2圧縮によって生成されたAPKパッケージの問題
3）PNG画像形式とTGA画像形式の問題
4）ゲーム実行のクラッシュの問題
5）AssetBundleの読み込み方法に適用できる環境

---

##UI

**Q：UIの日常開発では、特定のGOを表示または非表示にするために、多くのSetActive（true）/（false）コードが使用されます。しかし、SetActiveのコストが大きすぎるので、SetActiveを使用したくありません。他の解決策はありますか？**
>A1：この状況には、Active/Deactiveのコストには主にいくつかの側面があります。
1.C＃層からNative層へのシャトルコール速度は、C＃層よりも遅くなります。
2.UI要素を変更すると、所属Canvasが変更され、関数Canvas.SendWillRenderCanvases（）およびCanvas.BuildBatch（）がトリガーされ、高い時間コストを引き起こします。
3.UI要素のメッシュ頂点配列を変更すると、MONOメモリの割り当てが発生し、GCがトリガーされ、高い時間コストを引き起こします。（ただし、UI要素の位置を移動したらMONOメモリの割り当ては発生しません）。
したがって、最適化は次の点からも考慮することができます。
1.C＃層で変数を設定して、対応するGOがActive状態かDeactive状態かをマークし、ActiveオブジェクトではSetActive（true）を回避し、非activeオブジェクトではSetActive（false）を回避します。ActiveでSetActive（true）を実行すると、「最下層」が判断を下しますが、コールした際、最下層はすでにC＃層からコールされているため、コストが高くなります。 C＃層で適切に判断することで、最下層に判断させることを回避できます。
2.頻繁に変更されるUI要素とまれに変更されるUI要素を別のCanvasに配置して、UI要素の変更による時間コストを減らします。
3.UI要素の座標をCanvasの範囲外に移動して表示および非表示にし、SetActiveの時間とSendWillRenderCanvasesの時間を回避します。
4.テスト後、Componentにenabled = falseの操作を行うことは、GOにSetActive（false）の操作を行うことより時間が少なくかかりません。
5.CanvasGroupコンポーネントを追加して透明度を設定することにより、表示と非表示を表します。

>---
>A2：最近最適化を行い、この問題も気づきました。特に、ImageとTMPTextがハングアップされている時にSetActive場合、時間コストがもっと長くなります。そして、次の側面から最適化しようと思います。
1.UICanvasをハングアップものに対し、Layer層を直接変更します。
2.UICanvasをハングアップしないものに対し、CanvasGroupをハングアップしてAlphaを制御するように変更します。ここにはやや面倒なところがあります。こちらのプロジェクトは長い間開発されたため、インターフェイスの方に、制御が必要なノードにCanvasGroupをハングアップさせることは現実的ではありません。実行時にコンポーネントを動的にハングアップことには、パフォーマンスに関するいくつかの懸念があります。そのため、実行時にActiveの変更が発生するノードに見たら、対応するPrefabにCanvasGroupコントロールを追加することで、PrefabがCanvasGroupコントロールをうまく補足するようになります。正式なリリース後、欠落がない場合は、SetActiveを直接使用してください。
3.CanvasGroup方法は欠点があります。つまり、Alphaだけが変更され、レイアウトは引き続き使用されるため、親インターフェイスはLayoutであり、CanvasGroupは使用できません。最初の計画は、SetScale0とSetActiveの時間コストを比較することです。どちらも、再描画を引き起こすはずです。

---
##Texture

**Q：空のプロジェクトで、2048 * 2048の大きな画像をいくつか入れました。ETC24bitsで圧縮した場合、1枚のシートのサイズは2MBで、ASTC6X6で圧縮した場合、1枚のシートのサイズは1.8MBです。
個人的な理解によると、ASTC圧縮形式で生成されたAPKは小さいはずですが、まさか予想と正反対とは思いませんでした。ETC2圧縮で作成されたAPKは21.1MB、ASTC圧縮で作成されたAPKは25.7MBです。**
 
**ETC2で圧縮されたパッケージが小さいのはなぜでしょう、ASTCによって作成されたAPKは大きいのはなぜでしょうか？**
>A：占有されているパッケージのサイズと、EditorのPreviewインターフェイスに表示されるサイズは異なるものです。
Previewインターフェイスに表示されるサイズは、ASTCまたはETC2のアセットのサイズであり、パッケージ化後、そのアセットはさらに圧縮されます（LZ4またはLZMA）。 LZ4に圧縮されたETC2が占めるパケットのサイズは、LZ4に圧縮されたASTCが占めるサイズよりも実際に小さいとしか説明できません。理由は、特定の圧縮アルゴリズムの実装によって異なります。
AssetBundleを使用して確認できます。AssetBundleパッケージ化時にNoCompressionが選択されている場合、確かにASTC形式はETC2形式のAssetBundleパッケージよりも小さくなります。 LZ4またはLZMA圧縮を選択した場合、ETC2形式のAssetBundleはASTC形式のAssetBundleよりも小さくなります。

---
##Texture
**Q：アーテイストによると、透過なチャンネルの画像があり、TGA形式である必要がありますが、透過なチャンネルがないため、PNG形式にすることはできません。Unityで透過なチャネルがあるPNG形式があるのは、なぜですか？どのようにしてアーテイストにPhotoShopでPNG形式の画像を作成させ、それでも効果を満足させますか？ Unityの2つの図の違いの原理について詳しく説明していただけますか？**
>A1：PhotoShopにはPNG用の透過なチャンネルはありません。エクスポートしても、RGB3チャネルのみをエクスポートできます。PNGピクセルの透過度情報を変更するには、マスクを使用する必要があります。
アーテイストに、「この情報はマスクに描かれています。黒――透過、白――不透過であるように」のように伝えたら、理解してくれたと思います。

>--- 
>A2：TGAアーテイストを選んだ方が容易く処理もらえます。PNG形式の違いを気にする必要はありませんから。PhotoShopでAlphaを扱う必要もありません。結局のところ、エンジンはさまざまなプラットフォームに従って圧縮する必要があります。プロジェクトの規模に気にならない場合、より便利なプロセスが鍵となります。

---
##Android
**Q：ゲームを一定時間実行すると、以下のように一部のマシンがクラッシュします。皆もこのような状況に置かれることがありますか。**
JNI ERROR (app bug): global reference table overflow (max=51200)

**Unity 2018.3には関連するコンテンツがあると気付いたのです。今使用しているバージョンは2019.4.10で、修正されているはずですが、解答お願いいたします。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/fe63cca6-7bed-615a-e34a-aaedaaaef420.png)

 >A1：JNIのコール回数が多すぎませんか？以前に試しましたが、Tencent Voice のAPI JNIを呼び出し続け、一定時間実行するとクラッシュします。問題主のおっしゃったのと同じようです。

>---
>A2：AndroidJavaClassとAndroidJavaObjectが頻繁にNewだけで、Disposeを呼び出さずにが発生するはずです。

>---
A3：次の情報を参照してください。
2019.4.21f1 Release Notes
Fixes
Android: Fixed Java local reference leaking when using AndroidJavaClass/Object. (1283209)
 https://unity3d.com/unity/whats-new/2019.4.21 のFixesに載っています。

---
##AssetBundle
**Q：AssetBundleロード方式の適用可能な環境に関して、AssetBundle.LoadFromMemoryおよびAssetBundle.LoadFromStreamの適用可能な環境は何ですか？**
>A1：AssetBundle.LoadFromMemory
UnityWebRequestによってダウンロードされたAssetBundleアセットを使用し、使用後にローカルに保存しないでください。
暗号化要件のあるAssetBundleアセット。
AssetBundle.LoadFromStream
暗号化要件のあるAssetBundleアセット（メモリ値は理論的にはAssetBundle.LoadFromMemoryよりも小さいです）。
Androidでは、StreamingAssetsディレクトリからコピーしてストリームを作成する必要があります。

>---

>A2：アセットを暗号化する必要がある場合は、最初にAssetBundleをメモリに読み込み、復号化してから、AssetBundle.LoadFromMemoryを呼び出してロードすることができます。この方法のメモリの最大使用量は、少なくともAssetBundleの2倍になります。「AssetBundleの原則とベストプラクティス」（中国語注意）を参照してください。
AssetBundle.LoadFromStreamはストリーミングモードでロードできます。すべてのAssetBundleをメモリに読み込んでから復号化してロードする必要はありません。代わりに、Bufferのようにその中で一部を読み取り、復号化することでロードできます。その方法はあまり大きなメモリを使用しませんから。このインターフェイスを使用する場合は、継承されたFileStreamクラスをカスタマイズしてから、ReadとWriteの方法でByte配列に対して、暗号化および復号化処理を実行する必要があります。
具体的な使用法については、https://www.xuanyusong.com/archives/4607を参照してください。

---
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