前回、第36回では、PUZFLOを実際に遊ぶ中で見つけた不具合やバグについてまとめました。
設備単体では問題なくても、設備同士を組み合わせるとワークが止まる。
そんな不具合も増えてきて、ゲームがかなり複雑になってきたことを実感しました。
そして、何度もゲームをプレイしているうちに、今度は別の問題が気になり始めます。
『 なんか、後半になると重い。』
序盤ではかなりスムーズに動いています。
ところが、
- 設備が増える
- ワークが増える
- 出荷場が増える
- 複数ラインが同時に動く
という状態になると、明らかに動作が重くなってきました。
第37回では、いきなりコードを最適化するのではなく、
「そもそも何が原因で重くなっているのか?」
をChatGPTと一緒に調べていきます。
実際の最適化は、次回第38回で行う予定です。
最初のきっかけは「同じSeedなのに結果が変わる」

今回、最適化を意識するきっかけになったのは、単純に画面がカクついたからではありません。
PUZFLOでは、投入機からワークをランダムな間隔で流しています。
ただし完全ランダムではなく、
Seedを固定した、再現性のあるランダム投入です。
つまり同じSeedなら、毎回ほぼ同じタイミングでワークが投入される。
そうすることで、
を同じ条件で比較できるようにしていました。

ところが、ゲームが重くなってくると、
同じSeed・同じ設備配置なのに、NGになる場合とならない場合がある。
ということに気付きました。
これはゲームとして致命的です。
「ランダムは同じなのに、なぜ結果が変わる?」
そこでChatGPTに聞いてみました。

現状、再現性のあるランダム投入をしていますが、
処理が重くなるとNGが出る場合と出ない場合があります。
これはどうしようもありませんか?
すると返ってきたのが、

ランダム値そのものは再現できていても、シミュレーションの時間進行が
フレームレート依存になっている可能性がある
という話でした。
例えば同じSeedで、
- 0.63秒。
- 1.12秒。
- 0.48秒。
という投入間隔が毎回同じでも、
処理が重くなる。
↓
ワーク到着が1フレーム遅れる。
↓
ストッパが閉じるタイミングとズレる。
↓
前後のワーク間隔が変わる。
↓
渋滞状態が変わる。
↓
最終的にNGになる。
ということが起こる可能性があります。
これはPUZFLOではかなり重要な問題です。
PUZFLOでは「昨日クリアしたラインが今日はNG」は困る
PUZFLOは、反射神経で遊ぶゲームではありません。
プレイヤーがラインを設計して、
生産開始。
↓
問題を確認。
↓
設備や能力を調整。
↓
再び生産。
というゲームです。
つまり、同じ設備配置・同じ条件なら、基本的には同じ結果になってほしい。
昨日はクリアできた配置なのに、今日は処理落ちしたからNG。
では、パズルゲームとしてかなり困ります。
そこでChatGPTから、ゲーム内部の判定を固定時間刻みにする
という方法を教えてもらいました。
「Simulation Tick」という考え方

例えばゲーム内部では、1tick = 0.02秒として、
50tickで1秒。という基準を作る。
そして、
- ワーク投入
- ストッパ開閉
- 加工開始
- 加工完了
- 分岐判定
- 出荷場到着
- 生産能力計測
などを、画面のFPSではなくtick基準で処理するという考え方です。
そうすると、PCが軽いときは、50tickを約1秒で処理。
PCが重いときは、同じ50tickを処理するのに1.2秒かかる。
でも、50tick後のゲーム内部の状態は同じ。
という状態を狙えます。
これはかなりPUZFLOと相性が良さそうです。
でも、全部tick化すると挙動が変わらない?
ここで自分が気になったのが、

そんな大きな変更をすると、ワークの動きがおかしくならない?
ということです。
今のPUZFLOは、かなり長い期間をかけてワーク移動や設備タイミングを調整してきました。
全部を固定tickへ変更して、ワークがカクカクしたり、
今まで成立していたラインが成立しなくなるのは困ります。
そこでChatGPTから出てきたのが、
シミュレーションと見た目を分けるという考え方でした。
内部では固定時間で、
「このワークはここにいる」
「加工が完了した」
と状態を確定。
一方、画面上では、
その状態と次の状態の間を滑らかに表示する。
つまり、
という二層構造です。
いきなり全部変える必要はない
ただし、現段階では、

PUZFLO全体をいきなり独自tickへ作り直すのは危険
という話にもなりました。
そこで、まずは、
- ランダム投入
- ストッパタイマー
- 加工時間
- 分岐判定
- 出荷判定
など、勝敗に影響しやすい部分から固定時間化するという方法が良さそうです。
一方、
- ワークの見た目
- ランプ
- UI
- エフェクト
- ロボットアーム
などは、今まで通り滑らかに動かす。
この方が既存の挙動を壊すリスクを減らせます。
そもそもFPSって関係あるの?

ここで、自分はかなり基本的なことを聞きました。

fpsと関係する?
わかりやすく教えて
正直、ゲーム制作を始める前の自分なら、
FPS=画面の滑らかさ。くらいの認識でした。
でもPUZFLOでは、

FPSがゲーム結果に影響する可能性があります。
例えば60FPSなら、1フレーム約0.0167秒。
30FPSなら、約0.033秒。
単純に考えると、30FPSでは60FPSより、
判定する間隔が粗くなる可能性があります。
ストッパで考えると分かりやすい
例えば、ワークがストッパへ近づいている。
60FPSなら、細かい間隔で位置を確認できます。
ところが30FPSになると、
次のフレームで少し大きく進んでしまう。
すると、60FPSではストッパ閉鎖直前に通過。
30FPSでは次フレームでストッパへ接触。
という差が出る可能性があります。
PUZFLOでは、ほんの少しのタイミング差が、
その後の渋滞全体へ影響することがあります。
なので、FPSは単なる見た目だけの問題ではなさそうです。
理想は「FPS」と「ゲーム判定」を分ける
ChatGPTとの話で、かなり分かりやすかったのが、
FPS
→ 画面の滑らかさ。
Simulation Tick
→ ゲーム結果。
という分け方です。
例えば、内部では常に0.02秒単位でゲームを計算。
でも画面は、
60FPSなら滑らか。
30FPSなら少し粗い。
それでも、30秒後のゲーム結果は同じ。
これが理想です。
PUZFLOは、FPSゲームのように複雑な物理演算を多用するゲームではなく、
グリッド+設備+ワークが中心です。
なので、こうした固定シミュレーション方式との相性は比較的良さそうです。
その前に、今のFPSを確認してみる
ただ、「FPSが影響しているかもしれない」と言っても、
そもそも現状何FPSなのか分かっていませんでした。
そこでまず、ゲーム中のFPSを確認することにしました。
UnityならGameビューのStatsから確認できます。
さらに、デバッグ用として、
- FPS
- Simulation速度
- ワーク数
などを画面へ表示しても良さそうです。
- 通常時
- ワーク大量時
- NG発生時
のFPSを比較できます。
FPSを最初から60に固定したらどう?
次に考えたのが、FPSを最初から低めに制限する方法です。
例えば、
- 120FPS
- 144FPS
- 240FPS
とPCによってバラバラに動くより、
最大60FPSにしてしまう。
これなら、余計な描画も減る。GPU負荷も下がる。発熱も減る。
ゲーム側のタイミング差も少し小さくなる。というメリットがあります。
PUZFLOのようなゲームなら、60FPSあれば見た目として十分滑らかです。
FPSを下げれば軽くなる?
ここでも素朴な疑問です。

「FPSを下げれば軽くなる?」
答えは、

基本的にはYES。
例えば120FPSで描画しているものを60FPSにすれば、
描画回数は単純には半分になります。
なので、
- Sprite描画
- UI描画
- エフェクト
- GPU使用率
- 消費電力
などは軽くなる可能性があります。
ただし、ゲーム全体が半分の負荷になるわけではないとのこと。
物理処理やFixedUpdateなど、FPSとは別に一定回数処理されるものは、
FPSを下げてもあまり減りません。
そして実際のFPSを確認してみた
ここからが本題です。
実際にPUZFLOを動かしてFPSを確認してみました。
まず、ゲーム序盤。
ステージ1:約170FPS
かなり余裕があります。
普通に遊んでいる限り、重いという感覚はほとんどありません。
ところがゲームをかなり進めて、出荷場20まで到達。
この状態では、約30FPS前後まで落ちていました。
170FPS → 30FPS
これはかなり大きな差です。
フレーム時間にすると、
170FPSなら、約5.9ms/フレーム。
30FPSなら、約33.3ms/フレーム。
ゲームが大きくなることで、
1フレームあたりの処理時間がかなり増えています。
もちろん、設備もワークも大幅に増えているので、
重くなること自体は当然です。
ただ、何かがゲーム規模に応じて大きく増えている可能性もありそうです。
ChatGPTに怪しいところを聞いてみる

現状のPUZFLOで怪しそうなところとして、いくつか候補が出ました。
大量のWorkpieceがUpdateしている
ワーク数が増えるほど、各ワークが毎フレーム処理を行っていれば、当然負荷は増えます。
WorkpieceTrafficController
PUZFLOでは、ワーク同士を重ねず、
列として渋滞させています。
そのため、
前方ワークとの距離を確認する処理があります。
もし内部で、すべてのワーク × すべてのワークのような比較をしていた場合、
ワーク数が増えるほど負荷が急激に増える可能性があります。
例えばワーク数が2倍になったら、処理量が約4倍になるようなケースです。
ここはかなり怪しそうです。
出荷場20個のUI
出荷場には、
- 生産能力
- ゲージ
- 状態表示
などがあります。
もし20個の出荷場UIを、毎フレーム更新しているなら、
必要以上にCanvasを更新している可能性があります。
生産能力の数字なんて、1秒間に60回更新しなくても、
5~10回程度でもほぼ違和感はありません。
ここも最適化できそうです。
最大ズームアウト
工場が広くなってきたので、カメラもかなりズームアウトできます。
つまり、画面内にほぼすべての設備とワークが表示される状態になります。
これは描画側の負荷にもなりそうです。
ここで自分のPCスペックも確認してみる
ただし、そもそも自分のPCがどの程度の性能なのか。という話もあります。
現在使っているPCは、
| パーツ | 構成 |
|---|---|
| CPU | Ryzen 5 3400G |
| メモリ | DDR4 32GB |
| SSD | WD Blue SN550 NVMe 1TB |
| 電源 | 500W |
| GPU | 非搭載 |
という構成です。
つまり、グラフィックボードなし。
Ryzen 5 3400Gの内蔵GPUを使っています。
このPCで最大規模30FPSなら、そこまで悪くない?
ChatGPTからは、この条件なら、
最大規模で約30FPSという数字自体は、
そこまで悲観する必要はないという話でした。
- 専用グラフィックボードなし。
- かなり大きな工場。
- 大量の設備。
- 大量のワーク。
- 出荷場20。
- 最大ズームアウト。
この条件なら、30FPS程度まで落ちること自体は、
そこまで不自然ではないようです。
むしろ、このPCを低~中スペック環境の検証機として使えるという考え方もできそうです。
PCを買い替えて解決するのは違う気がする
もちろん、もっと新しいCPU。専用GPU。にすれば、
今よりFPSはかなり上がると思います。
でも、それでは問題が見えなくなるだけかもしれません。
Steamで販売すれば、全員が高性能PCを使っているわけではありません。
自分のPCで重い部分を見つけて、そこを改善できれば、
より幅広い環境で遊べるゲームになります。
なので、PCを買い替える前に、まずゲーム側を調べることにしました。
ステージ1で170FPS出るのはかなり重要
もう一つ重要なのが、ステージ1では約170FPS出ているという点です。
もしゲームの基本描画やUIそのものが極端に重いなら、
ステージ1の段階からFPSは低いはずです。
でも実際は170FPS。
つまり、基本部分が致命的に重いというより、
ゲーム規模が大きくなったときに増える処理の中に、
負荷の原因がありそうです。
これは逆に言えば、ボトルネックを見つければ
かなり改善できる可能性があるということです。
60FPS制限と「最適化」は別問題
ここも今回かなり勉強になりました。
ステージ1。
170FPS。
ここを60FPSに制限する。
これは、無駄な描画を減らす省負荷対策になります。
一方、ステージ20。
30FPS。
こちらはそもそも60FPSへ届いていません。
なので、FPS上限を60にしても、
30FPSが60FPSになるわけではありません。
つまり、60FPS制限と、後半ステージの最適化は別の話です。
今回はいきなり直さず「原因を探す」

最初は、
FPSが低い。
↓
じゃあコードを軽くしよう。
と考えていました。
でもChatGPTからは、いきなり最適化しない方がいいと言われました。
まずはUnity Profilerなどを使って、
など、どこに時間を使っているのか確認する。
そのあと、負荷の大きいところから順番に直す。
この方が安全です。
Codexにも、まずは「直さず調べて」と頼む
ここも今までのバグ修正と似ています。
いきなり、「FPSを60まで上げて」ではなく、
まず、ChatGPTに相談して指示文を作成してもらいます。
現在、出荷場20・設備/ワークが多い状態でFPSが約30まで低下します。
CPU / GPUのボトルネック、Update負荷、TrafficController、UI更新、Canvas Rebuild、Instantiate / Destroy、GC Allocなどを確認し、負荷の大きい処理を報告してください。
まだゲーム挙動は変更しないでください。
と依頼する。
まず、何が重いのかを知る。
そこからです。
第37回では「重い原因を疑うところ」まで
今回、第37回では、PUZFLOを長く遊ぶ中で、
ゲーム後半になるほどFPSが大きく低下する問題が見えてきました。
ステージ1では、約170FPS。
しかし、出荷場20まで進むと、約30FPS。
さらに処理落ちによって、同じSeed・同じ設備配置でも、
結果が変わる可能性まで見えてきました。
単純に、「30FPSならまだ遊べるからOK」
では済ませない方が良さそうです。
特にPUZFLOでは、ゲームの重さがシミュレーション結果
そのものへ影響する可能性があります。
次回は、実際にどこを軽くできるか調べる
ただし、今回の段階ではまだ、
「ここを直せば軽くなる」と決めつけません。
次回、第38回では、実際にPUZFLOの処理を確認しながら、
どこが重いのかを特定して、実際に最適化していきます。
Workpiece。
TrafficController。
Spawner。
大量のログ。
出荷場UI。
オブジェクト生成。
このあたりを一つずつ確認して、
ゲームの挙動を変えずに、どこまで軽くできるのか。
そして、30FPSだった最大規模の工場が、
どこまで改善するのか。を実際に試していきます。
次回は、「重いことに気付いた」から「実際に軽くしてみる」へ。
PUZFLOの最適化編、後半です。




コメント