大きな世界
このページは、画面より広いマップを持つゲームや、シミュレーションが 1 フレームに収まらないことがあるゲーム向けです。コロニーシム、タイクーン、工場ゲーム、大きなタイルマップなどが当てはまります。
画面内だけを描く
camera.sees は、ワールド座標の矩形がビューと重なるかどうかを返します。x と y は矩形の左上です。
draw.withCamera(game.camera, () => {
for (const unit of units) {
if (game.camera.sees(unit.x - 16, unit.y - 16, 32, 32)) draw.sprite(unit.frame, unit.x, unit.y);
}
});タイルマップは、カメラを渡すと自動で同じ処理をします。
draw.withCamera(game.camera, () => map.draw(draw, { camera: game.camera }));0.28 から、開発ツールがこの最適化の出番を教えてくれます。ビューの外のスプライトが 1,000 個以上あり、描いた数の半分以上を占めると、コンソールの警告、オーバーレイの perf パネルの行、game_profile の drawHint で知らせます。計測は 60 フレームに 1 回で、開発時だけ動きます。draw.record のレイヤーとレンダーターゲット内のスプライトは数えません。コピーごとのスケール、インターリーブデータ、フレームのリストを使う draw.sprites も同様です。
残りをまとめて描く
同じフレームをたくさん描くなら、Float32Array を使い回して draw.sprites を呼びます。
draw.sprites(unitFrame, positions, count);変わらない背景は一度だけ記録して、毎フレーム再生します。
const ground = draw.record((d) => {
for (const t of tiles) d.sprite(t.frame, t.x, t.y, { origin: [0, 0] });
});
// 毎フレーム:
draw.withCamera(game.camera, () => draw.replay(ground));描画も見てください。
シミュレーションが重いときもフレームレートを保つ
ステップが 1 フレームより長くかかると、時計は追いつこうとして余分にステップを実行します。するとフレームはさらに遅れ、数 fps まで落ちることがあります。0.28 からは budgetMs を指定できます。ステップがこの時間を使うと、そのフレームは追いつくのをやめます。
const game = new Game({ canvas, width: 640, height: 360, clock: { budgetMs: 8 } });ゲームは実時間より遅くなりますが、フレームレートは安定します。ステップが必要なフレームでは最低 1 ステップ実行します。game.step() は影響を受けないので、シナリオとリプレイは変わりません。
0.28 より前は、clock: { maxFrame: 1 / 30 } のように maxFrame を小さくしてください。1 フレームのステップ数を制限できますが、その値より低いリフレッシュレートではゲームが遅くなります。
重い処理をメインスレッドから外す
いちばん重くなりやすいのは経路探索と大きな群衆です。探索を複数のステップに分け、同じ目的地へ向かうエージェントで 1 つのフローフィールドを共有してください。ワーカーについてはスレッドを使うを見てください。
セーブが収まるか確かめる
Storage は localStorage を使います。容量はふつう 1 オリジンあたり約 5 MB です。入りきらない書き込みは、最後に保存できたデータをそのまま残します。0.28 から、set は書き込みがストレージに届いたかどうかを返します。
if (!save.set("world", world)) showSaveFailed();0.28 より前の set は何も返さず、書き込みの失敗を知る方法がありませんでした。もっと大きなセーブは、IndexedDB に自分で保存してください。