UnityでFPSを上げるためにやったこと
これ何の記事?
Unity でキャラが大量に出てきてバトルするゲームを作ってるんですが、限界まで表示させたところ FPS が 20 あたりまで下がってしまいました。
画面上にキャラが180人、お互いに当たり判定あり、ということで結構重くなっていたんですが…
これをなんやかんやして FPS 80 まで引き上げたので、その内容を残しておきたいと思います。
やったこと
CanvasをOverlayに
Canvas を Screen Space - Camera でやってたんですが、これがカメラを動かすと非常に重くなる原因になっていました。
Overlay にすると軽くなりました。
ただ台詞の吹き出しの位置がずれるようになってしまいました。そもそもそのために Camera 基準にしてたのを忘れてましたね。
仕方ないのでその部分だけ別の Canvas に分けることで解決しました。
余計な文字列の生成をやめた
Debug.Assert でログを分かりやすくするため、文字列に変数を埋め込んでたんですが、この処理が非常に多くの Alloc を走らせてるみたいでした。
Debug.Assert(hoge, $"{name} state={state}");
毎フレーム何百回と呼ばれるような箇所では、ログに何か出すのをやめました。残念。
配列を無駄に毎回生成していた
これは完全にガバですが、配列を最初だけ初期化してるつもりが、毎回新規生成していたので、クッソほど Alloc が走ってました。
protected override State[] States => new[] {a, b, c};
=> が get なのを忘れてましたね。
protected override State[] States { get; } = new[] {a, b, c};
物理計算を緩くした
物理演算がメインのゲームではないんで、設定を緩くしました。
Velocity Iterations、Position Iterations、Default Contact Offset あたりを全部1にしました。もともと単純な衝突判定しかなかったんであまり変わらない気もしたけど、Profiler でみると少し軽くなってました。ヨシ。
localPosition, localScale のアクセスを気軽にやらない
キャラの座標や大きさ取得のために transform の localPosition / localScale に頻繁にアクセスしてたんですが、これが結構重いことがわかりました。
それぞれ自前でキャッシュして、get 時は localHoge を参照しないようにしました。
private float scale = 1
float Scale {
get { return scale; }
set {
scale = value;
transform.localScale = new(value, value, 1);
}
}
いつかバグの元になりそうな気がしなくもない…と思いつつ、ヨシ!
2乗のためにMathf.Powを使わない
2乗する際に b = a * a とか書くのアホくさいなと思って Pow 使ってたんですけど、これがそこそこ重かったです。
かっこつけてしまった自分を恥じつつ、b = a * a に戻しました。
キャラの探索ロジックを見直した
これは Unity がどうこうとは関係ないのでただのメモです。
よくあるやつで、分散しているメソッドを一回一つにまとめて圧縮することで、過剰に for を回さないようにしました。
パフォーマンス改善を完走した感想
かかったタイムは4日でした!
最初から結構気を使いながら作ってきたつもりだったので、改善なんてムリなんじゃないの?とか思ってたんですが、ちゃんと調べていくと縮むもんなんですよね。
FPSが低いとゲーム作るの辛くなってくるのですが、改善できてテンション上がってきました。これはRTAとかタイムアタックの楽しさと似てる気がしますね。
細かい話だと、localPosition が遅かったのが意外でした。インスペクタに出てるくらいだから簡単に取り出せるものであってよね。
この記事が気に入ったらサポートをしてみませんか?