WKWebView + PixiJS で作っているゲームに「省電力モード」を足した。やったことは単純で、
- フレームレートを 60 → 30fps に半減
- 画面全体にかけていた水揺らぎフィルタをオフ
GPU負荷を素直に半分にする、よくある省電力策だ。…はずだった。
症状:ローディングが終わらない
省電力モードをONにして起動すると、「Now Loading」から先に進まない。OFFなら一瞬で始まる。当然、最初に疑ったのは「省電力で変えたところ」——つまり解像度だ。
省電力では解像度も下げていたので、「低解像度で描画がコケているに違いない」と決めつけ、
- 解像度を1倍→2倍に
- antialias を切ったり戻したり
- 切替方式をリロードに変えたり
…と、解像度まわりを何度もビルドし直した。が、どれもハズレ。ロードは終わらないままだった。
推測をやめて、ログを刺す
腹を決めて、実機のコンソールに log() を仕込んでどこまで進んでいるかを可視化した(xcrun devicectl ... process launch --console で標準出力が拾える)。
すると——
M: init start
G: loadAssets ok
G: bridge ok
G: emit load_state ok
(…ここで止まる。"init end" が出ない)
初期化はほぼ最後まで進んでいる。でも完了マーカーに到達しない。例外も出ていない=例外ではなく”ハング”。区間を狭めていくと、犯人はこの一行だった。
真犯人:60fps前提の「安定待ち」
ゲームは起動の最後に、フレーム間隔が安定するのを待ってから本編に入る処理を持っていた。
const threshold = 1.05; // ← これ
const onTick = (ticker) => {
recentDeltas.push(ticker.deltaTime);
// 直近20フレームが全部 threshold 未満になったら「安定」とみなす
if (allStable) resolve();
};
setTimeout(() => resolve(), 30000); // 安全網:30秒で強制続行
PixiJS の deltaTime は 60fps を 1.0 とした相対値だ。
- 60fps なら
deltaTime ≈ 1.0→1.05未満 → すぐ安定 → 即ロード完了 - 30fps なら
deltaTime ≈ 2.0→ 永遠に1.05未満にならない → 安定判定が来ない → 30秒のタイムアウトをただ待つ
つまり「ローディングが終わらない」の正体は、「ローディングに30秒かかる」だった。解像度はまったくの無罪。1.05 というハードコードされた60fps前提が、省電力の30fpsで牙を剥いただけだった。
修正
しきい値を maxFPS 相対にするだけ。
const maxFPS = app.ticker.maxFPS || 60;
const threshold = (60 / maxFPS) * 1.3; // 60fps→1.37 / 30fps→2.6
これで 30fps でも deltaTime ≈ 2.0 < 2.6 で安定判定が通り、ロードは即終わるようになった。
学んだこと
- 「フレームレートは60固定」という暗黙の前提は、可変fpsを入れた瞬間に壊れる。
deltaTimeを閾値比較するコードは要注意。 - “ローディングが終わらない”系のバグは、たいてい別の問題の症状。今回は描画ではなくタイミング前提の問題だった。
- そして何より——推測でビルドを繰り返す前に、ログを刺して事実を見る。解像度を疑って溶かした数回のビルドは、最初にログを入れていれば不要だった。