ゲーム一覧へスキップ
Hadukis

ブログ

砦がひとりでに崩れていた理由

· 約4分で読めます

物理演算で壊すゲームには、ほかの何よりも先に守るべき約束があります。これから壊すものが、ちゃんと立っていることです。ScaleSling の初期のビルドでは、ステージを読み込むと震える砦があり、プレイヤーが1発目の狙いを定めているあいだに勝手に倒れてしまうものもいくつかありました。

これを物理エンジンのせいにして、揺れが止まるまで摩擦や密度をいじり始めるのは、ついやりがちなことです。私たちも危うくそうするところでした。でも、原因はどれもエンジンではありませんでした。

重なって生まれた24組のブロック

どのステージも、位置とサイズを持つブロックのリストで、その数値はすべて手で入力したものです。幅42ピクセルの板を隣のブロックから32ピクセルの位置に置くと、10ピクセル重なります。画面上では10ピクセルの重なりは見えません。スプライト同士が接しているように見えるだけです。

2つの剛体は同じ空間を占められません。シミュレーションの最初のステップで、エンジンは重なりを見つけて、強い力で押し離します。プレイヤーが震えとして見ていたのはこの押し出しで、高く積んだ塔ならそれだけで全体が崩れました。

全ステージを読み込むスクリプトで調べると、24ステージのうち16ステージで、重なったペアが24組見つかりました。重なりは3〜11ピクセルです。2つ目のスクリプトで、各ペアを重なりがいちばん小さい軸の方向に(ほぼ必ず、ステージ作者が接するつもりだった軸です)、それぞれ距離の半分ずつ動かして離します。1組を直したせいで別の組が重ならないよう、何回かに分けて処理します。回転したブロックには手を付けません。傾いた板が実際に占める範囲は、幅と高さでは表せないからです。

柱が1本足りない柵

5つのステージが、コピーで受け継がれた同じ柵を使っていました。長さ130ピクセルの梁が、柱1本の上に乗っているものです。重心は支点から39ピクセル外側にありました。毎回必ず傾いて、誰も触れないうちに48ピクセル落ちていました。

最初は梁を柱の上までずらす案を試しました。すると梁が隣の長い梁にめり込み、かえって悪くなりました。梁が長すぎたわけではありません。柵の奥側の端に、柱が1本足りなかったのです。柱を足したら、5ステージがまとめて直りました。

直ったとどうしてわかるか

ステージを遊んでみて大丈夫そうだと判断する代わりに、安定性チェックを追加しました。各ステージを本物の物理エンジンに読み込み、何も撃たずにシミュレーション上で4秒待ち、すべてのブロックがどれだけ動いたかを測ります。

修正前は6ステージがひとりでに崩れ、いちばん動いたブロックは48ピクセル移動していました。修正後は崩れるステージはなく、どこを見ても最大の移動量は10ピクセルです。積み上げたものが落ち着くときの、普通の沈み込みです。このチェックはブラウザなしで動くので、ステージを変更するたびに実行されます。

1.5倍の高さで出てきたブロック

原因の1つは、ステージのデータとはまったく別のところにありました。26×88ピクセルで指定した板が、ゲーム内には26×131で現れていました。当たり判定の半径を27にしたトロールは、半径20になっていました。

ゲームが使っているフレームワークは、物体の物理ボディを画像と一緒に拡大縮小します。ボディを正しいサイズで宣言してから、スプライトを合わせるためにリサイズすると、ボディが2回目のスケールを受けます。倍率は、画像ファイルと指定サイズの比です。エラーは何も出ません。タワーは地面から20ピクセル浮いた状態で止まり、弾は固そうに見えるものをすり抜けていました。

修正方法は、先に画像のサイズを決めてから、ボディを正確なものに差し替えることです。コードは正しく見えたので、読んでいても見つからず、ボディを直接測ってようやく見つかりました。いまでは、新しい種類の物体はすべてこの方法で確認しています。

もう1つの落とし穴:星

各ステージでは、盤面にある合計得点の95%で星3つになります。この目標値はステージ生成時にステージファイルへ書き込まれるもので、ゲーム起動時に計算されるわけではありません。

6つのステージから飛行船を取り除いたとき、どのステージも壊せるものが900点分減りました。ところが星3つの目標値は、その900点を含んだままでした。満点でクリアできた6ステージが、満点を取れないステージに変わってしまったのです。しかも変更自体は、物体を1つ消しただけに見えました。いまでは、ステージの盤面に置くものを変更したら、同じ変更の中で星の基準も計算し直しています。

ほかのゲームにも言えること

建物が崩れると物理の問題に見えるので、物理での修正に手が伸びます。摩擦を増やす、ブロックを重くする、シミュレーションを遅くする。どれを選んでも本当の欠陥は隠れてしまい、当てたときの手ごたえも悪くなっていたはずです。原因はデータの中にありました(手で入力した座標、コピーされた柵、古いままの数値)。それを見つけたのは調整ではなく、測定でした。

ScaleSling の砦は、いまでは壊されるまで立っています。 1つ壊してみてください。