
内容:
- ゲームサイズの最適化
- バンドルとダウンロード可能なリソース。 システムに何が必要ですか?
- マニフェストの差分
- コード生成の節約
MMO RTSの作成に関する赤道サイクルを経験しました。 今日の記事は最適化についてです。
ゲームサイズの最適化
モバイルネットワーク経由で100 MBを超えるアプリケーションをダウンロードしようとしているというAppStoreとGooglePlayからの警告を覚えていますか? この投稿により、コンバージョン率が大幅に低下します。 このような膨大なゲームの宣伝は非常に高価です。 調査を実施したところ、コンバージョンはほぼ20%減少しています。 無料ゲームの場合、この指標は生存の危機にあります。有料ゲームの場合、それほど重要ではありません。
iOSでは、それはまだ難しいです。 ARM64以降、ビルドは32ビットアーキテクチャと64ビットの2つの異なる実行可能ファイルを取得します。 つまり、組み込みリソース用の70 MBの代わりに、30だけが残ります。
各iOSビルドで、そのサイズの悲観的な計算を行います。 このため、xCodeアーカイブはリソースと実行可能ファイルに分割されます。 リソースは.zipで圧縮され、結果は実行可能ファイルのサイズと合計されます。 この指標は、プロジェクトのサイズがどのように変化しているかを知るのに十分です。 より詳細なガイドと公式は、UnityのWebサイトで入手できます。
すべてのグラフィックが正しく押され、メッシュが最適化され、不必要な依存関係が排除された場合、多くのソリューションが残っていません-たとえば、コンテンツをバンドルに入れてコード生成を最適化します。
バンドルとダウンロード可能なリソース。 システムに何が必要ですか?
ログインがビルドに残った後、ユーザーにUIを表示するために必要なすべての基本的なグラフィック。

エンジンの4番目のバージョンでバンドルの使用を開始しました。 5番目のバージョンでは、Unityは別のアプローチを提供しますが、すでに既製のシステムがあるため、使用しません。
要するに、システムは次のように機能します。
- Unityプロジェクトには、名前が.bundleで終わる一連のフォルダーがあります。 これらのバンドルの内容は、このリソースのファイル名によって実行時にクライアントによって要求されたリソースです。
- 開発者は特別なユーティリティを使用して、変更されたバンドルを構築し、マニフェストを形成します。 これは、クライアントが必要とする情報を含むテキストファイルです。
- 生成されたバンドルはコンテンツサーバーに投入され、マニフェストはサーバーに投入され、ログイン時にクライアントに返されます。 バンドルは、クライアントを更新せずに更新または追加できます。
- クライアントはマニフェストを解析し、コードが要求するとすぐにバンドルをロードしてキャッシュします。
その結果、マニフェストの要件を作成しました。

Unityでバンドルキャッシュを操作するには、バージョンの数値表現を使用します。 この情報はマニフェストに保存されます。 ファイルを更新する必要がある場合、コンテンツサーバー上のバンドルへのパスはバージョンから作成されます。 これにより、すべての変更が新しいファイルになります。
システムは、バンドルの相互依存関係をサポートしています。 多くの場合、異なる3Dモデルは、テクスチャを備えた共通のバンドルに依存しています。 情報はマニフェストに保存され、リソースの読み込みを優先するためにクライアントで使用されます。
バンドルをローカライズする機能を追加しました。 これは、異なる言語のテキストと音声演技ウィザードを備えたゲームバナーに必要です。
バンドルは、サポートされるすべての圧縮に対して形成されます。 クライアントは、使用している圧縮を認識し、要求されたバンドルへのパスを形成し、それに圧縮名を追加します。

本番環境では、アプリケーションのバージョンが異なる場合があります。 したがって、異なるリソースの使用が可能です。 アプリケーションのさまざまなバージョンの情報を1つのマニフェストに格納しますが、データセットのヒープの形式では格納しません。 それらはいくつかの基本的なバージョンからの差分の形式で保存されます。 クライアントでは、基本バージョンと適用されたすべての差分から、使用する最終データセットを形成します。
コード生成の節約
コード生成に関しては、.NET / MonoプラットフォームとIL2CPPの仕組みを理解する必要があります。 ジェネリック型に注意してください。 .NET / Monoの場合、各汎用特殊化は個別のタイプです。 参照タイプについては、特殊化は1つ-オブジェクトを参照します。 値型の場合、コンパイラはこの型のオブジェクトのサイズを考慮する必要があります。 次に、彼は個別の専門分野を作成します。
主な問題領域は、大規模な実装と汎用コレクションを持つクラスです。 型付き配列に加えて、列挙型列挙値をディクショナリのキー値として使用すると、ディクショナリコードの新しいコピーが生成されることになります。
そのような実装を特定するために、ReSharperとそのFind generic substitutionsオプションを使用しました。 それらを見つけたら、スペシャライゼーションの数を最小限に抑えようとします。