ブロック崩しの Web ビルドが約10MB ありました。スマホで開くと重い。
削りにいったところ、設定を2つ変えるだけで 21.7%、さらに使っていないパッケージを外して合計 27.3% 小さくなりました。ビルド時間まで短くなっています。
−27.9%
合計サイズ
10,143,315 → 7,311,364 バイト
−38%
展開後の wasm
38.3MB → 23.7MB
3:52
ビルド時間
最初は 8分33秒
0行
書いたコード
設定と削除だけ
結果(2段階)
| 最初 | 第1弾のあと | 第2弾のあと | |
|---|---|---|---|
| 合計 | 10,143,315 バイト | 7,945,839 | 7,311,364(−27.9%・第3弾まで) |
wasm.br(エンジンとコード) | 7,333,280 | 6,006,738 | 5,635,795 |
data.br(アセット) | 2,689,477 | 1,819,159 | 1,618,640 |
framework.js.br | 72,396 | 71,725 | 71,551 |
| ビルド時間 | 8分33秒 | 5分26秒 | 3分52秒 |
- 最初10,143,315 バイト
- 第1弾7,945,839 バイト
- 第2弾7,374,207 バイト
圧縮(Brotli)後のサイズ。ブラウザが実際にダウンロードする量です。
第1弾は設定を2つ変えただけ。第2弾は使っていないものを外しただけです。コードは1行も書いていません。
変えた設定は2つだけ
1. Managed Stripping Level:Minimal → High
C# のコードのうち、使っていない部分を削る強さです。Minimal は最小限しか削りません。High にすると、到達しないコードをかなり積極的に削ります。
これが wasm.br に効きました。
2. IL2CPP Code Generation:速度優先 → サイズ優先
IL2CPP が C# を C++ に変換するときの方針です。既定は実行速度を優先しますが、サイズ優先に切り替えられます。
ブロック崩し程度の処理では、速度の差を体感できませんでした。60fps は維持しています。
設定はコマンドからも変えられる
エディターの画面を開かなくても、Unity CLI から変更できます。AI に任せるときはこちらが確実です。
UnityEditor.PlayerSettings.SetManagedStrippingLevel(wt, UnityEditor.ManagedStrippingLevel.High);
UnityEditor.PlayerSettings.SetIl2CppCodeGeneration(wt, UnityEditor.Build.Il2CppCodeGeneration.OptimizeSize);
変えなかった設定と、その理由
| 設定 | 判断 |
|---|---|
| 例外サポート(Explicitly Thrown → None) | 変えない。 さらに小さくなるが、try / catch が効かなくなり、障害の原因を追えなくなる |
| Decompression Fallback | 無効のまま。 サーバー側で Content-Encoding を返せるので不要。有効にするとコードが増える |
| 圧縮形式 | Brotli のまま。 gzip より小さい |
| デバッグシンボル | Off のまま(もともと Off) |
| Strip Engine Code | 有効のまま(もともと有効) |
削ったあとが本番:壊れていないかを確認する
Managed Stripping の High には副作用があります。使っていないと判断されたコードが削られるので、リフレクション経由で呼んでいる処理や、JsonUtility、Addressables から参照している型が消えることがあります。
やっかいなのは、エディターでは動くのにビルドしたものだけ壊れる点です。自動テストも通ってしまいます。
なので、ビルド後は必ずブラウザで確認しました。
ビルド後にブラウザで見ること
今回はすべて問題なしでした。もし壊れていたら、link.xml で「この型は残す」と指定して作り直すことになります。
ついでに直したこと
ブラウザのタブに Unity Web Player | breakout と出ていました。Player Settings の Product Name が既定のままだったからです。ゲーム名と運営名を設定して、ブロック崩し に変わりました。
小さいことですが、共有されたときに目に入る場所です。
第2弾:何が入っているかを数えてから削る(2026-09-16 追記)
7.9MB のうち何がどれだけ占めているのか。当てずっぽうで設定をいじる前に、ビルドレポートを数えました。
Unity は毎回 Library/LastBuild.buildreport にビルドの内訳を残しています。これを読むと、アセット1つずつのサイズが出ます。
UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEditor.Build.Reporting.BuildReport>(path)
→ report.packedAssets[].contents[] に packedSize と sourceAssetPath
数えた結果はこうでした。
| 種類 | 圧縮前のサイズ | 割合 |
|---|---|---|
| Texture2D | 3,099,472 | 80.0% |
| Shader | 426,632 | 11.0% |
| MonoScript | 256,276 | 6.6% |
| ComputeShader | 67,428 | 1.7% |
| その他 | 23,564 | 0.6% |
| 合計 | 3,873,372 |
- Unity のロゴ(スプラッシュ画面)2,796,376
- シェーダー426,632
- URP の SMAA 用テクスチャ268,920
- スクリプト256,276
- コンピュートシェーダー67,428
ロゴ1枚が飛び抜けている。ただしこれは圧縮前の数字です(次の節)。
そして Texture2D の中身の内訳が、これです。
| アセット | サイズ |
|---|---|
| Built-in Texture2D: Splash Screen Unity Logo | 2,796,376 |
| URP の SMAA 用テクスチャ(AreaTex.tga) | 268,920 |
| URP のデバッグ用フォント | 16,508 |
Unity のロゴ1枚で、アセット全体の72%。
2Dのブロック崩しに画像素材は1つも入れていないので、入っているのはテンプレートとエンジンのものだけです。
効かなかった:スプラッシュ画面の停止
Unity 6 では Personal でもスプラッシュ画面を止められます。手元で確かめました。
UnityEditor.PlayerSettings.SplashScreen.show = false;
止めてビルドし直した結果がこれです。
| 止める前 | 止めたあと | |
|---|---|---|
data.br | 1,819,159 | 1,820,458 |
| 合計 | 7,945,839 | 7,947,158 |
1バイトも減っていない。むしろ 1,319 バイト増えた。
理由は単純で、ロゴのような画像は Brotli でほとんど消えるからです。ビルドレポートが出すのは圧縮前のサイズなので、「大きい順に並べて上から潰す」をやると、こういう空振りをします。
⚠️ ビルドレポートの数字は圧縮前
ダウンロード量に効くのは圧縮後です。圧縮で消えるもの(ロゴ・単色の画像・繰り返しの多いデータ)は、レポート上どれだけ大きくても効果が薄い。 逆に、コードやシェーダーは圧縮しても残るので、削ると素直に効きます。
なお、スプラッシュ自体はそのまま止めています。サイズではなく、起動してから遊べるまでの時間が短くなるためです。
効いた:使っていないパッケージを外す
残るのは wasm(コード)とシェーダーです。ここに効くのは、そもそもプロジェクトに入れているものを減らすことでした。
Packages/manifest.json を開くと、テンプレートが入れた依存が 55件ありました。2Dのブロック崩しに必要ないものが並んでいます。
外したのは 39件です。
| 外したもの | 例 |
|---|---|
| 2D 系のインポーター・ツール | Aseprite / PSD Importer / SpriteShape / Tilemap Extras |
| 使っていない機能パッケージ | Timeline / Visual Scripting / バージョン管理 / チュートリアル基盤 |
| 3D 向けのモジュール | 物理(3D)/ 地形 / 布 / 車両 / 風 / ナビメッシュ |
| 使っていない表現のモジュール | パーティクル / 動画 / XR / ベクターグラフィックス |
| その他 | アナリティクス / アセットバンドル / 画面キャプチャ / Android JNI |
残したのは16件だけ。URP・Input System・uGUI・2D 物理・オーディオ・Test Framework・CLI の Pipeline などです。
あわせて、テンプレートが置いていった Assets/Welcome(チュートリアル用の画面)とサンプルシーン2つも消しました。
結果
| 外す前 | 外したあと | 差 | |
|---|---|---|---|
| 合計 | 7,945,839 | 7,374,207 | −571,632(−7.2%) |
wasm.br | 6,006,738 | 5,635,795 | −370,943(−6.2%) |
data.br | 1,819,159 | 1,618,640 | −200,519(−11.0%) |
| ビルド時間 | 5分26秒 | 3分52秒 | −29% |
ビルドレポート側でも、シェーダーが 426,632 → 356,420、スクリプトが 256,276 → 145,760 に減っていました。パッケージが持ち込んでいた分です。
ビルド時間の条件
第2弾のビルドは、パッケージを外したあとエディターを開き直した状態で測っています。キャッシュの条件がまったく同じではないので、時間は目安として見てください。サイズのほうは条件に関係ありません。
壊れていないかの確認(第2弾)
パッケージを消すのは、設定を変えるより乱暴です。確認はこの順でやりました。
- 1
エディターを開き直す
コンパイルエラー0・警告0 - 2
EditMode テスト
44/44 合格 - 3
PlayMode テスト
5/5 合格(ビルド対象は WebGL のまま) - 4
ローカルで遊ぶ
タイトル → 開始 → 発射 → ボールが動くまで - 5
コンソールを見る
ブラウザのエラー0 - 6
本番に差し替えて同じ確認
公開 URL でもう一度
消しすぎていれば、たいていはコンパイルか起動で落ちます。今回は落ちませんでした。
で、どれだけ速くなったのか
測りました。起動が 約705ms → 約569ms(−19%)、本番の回線ではダウンロード 0.76秒+起動 0.62秒で遊べます。展開後の wasm が 38.3MB → 23.7MB(−38%)と、ダウンロード量より大きく減っていたのが効いています。
計測の方法とつまずいた点はUnityのWebゲームの読み込み時間を測るにまとめました。
第3弾:使っていないシェーダーを落とす(2026-09-18 追記)
パッケージを39件外しても、URP 本体が持っているシェーダーは残ります。ビルドレポートで圧縮前の大きい順に並べると、2D のブロック崩しでは1回も使わないものが並んでいました。
| シェーダー | 圧縮前 |
|---|---|
| 画面空間反射(ComputeScreenSpaceReflection) | 28,368 バイト |
| レンズフレア(LensFlareDataDriven) | 27,712 バイト |
| テンポラル AA(TemporalAA) | 24,020 バイト |
| レンズフレア・画面空間(LensFlareScreenSpace) | 18,516 バイト |
| SMAA(SubpixelMorphologicalAntialiasing) | 14,152 バイト |
IPreprocessShaders で、これらを含む9本の変種を全部落としました。
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data)
{
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL) return;
if (!Drop.Contains(shader.name)) return;
data.Clear(); // この shader の変種を全部落とす
}- 第2弾7,374,207 バイト
- 第3弾7,311,364 バイト
−62,843 バイト(−0.85%)。減ったのはほぼ data.br(1,618,640 → 1,576,343・−2.6%)で、wasm.br は変わりません。
圧縮前で 130KB 以上あったものが、圧縮後では 63KB の差にしかなりません。シェーダーはテキストに近く、Brotli がよく効くためです。第1弾・第2弾に比べると小さい効果ですが、ビルド時間も 109秒まで下がりました。
⚠️ 削りすぎると、その場では気づきにくい形で壊れる
使っている効果のシェーダーを落とすと、画面が真っ黒やピンクになります。落としたあとは必ずビルドしてブラウザで通しで遊び、コンソールにエラーが出ないことまで確認します。私はタイトル→プレイ→スコア加算まで見て、エラー0を確認しました。
次に残っている手
- 例外サポートを None にする:数十KB。障害調査とのトレードオフなので保留
- スマホ実機での計測:PC(60Hz)では 60.1fps で上限に張り付いています。エディターで垂直同期を切って測ると 1フレーム 2.03ミリ秒(60Hz の 16.67ミリ秒に対して 14.64ミリ秒の余裕)でした。実機での数字は別に測ります
ここまでで 10,143,315 → 7,311,364 バイト(−27.9%)。コードはゲーム側に1行も書いていません(足したのはビルド時に効くエディター用のスクリプトだけです)。
ビルドしたものを自分のサーバーで配る手順はUnityのWebゲームを自前サーバーで公開するに、ビルドを AI に回させる手順はAIにUnityのテスト・動作確認・ビルドまで回させる手順にあります。検証に使ったゲームの公開は終了しましたが、当時の実測値と画面はこの記事に残しています。