ひとことで
水に沈んだ部分の体積に応じて、物体に上向きの力(浮力)を加える仕組みです。「押しのけた水の重さだけ浮かされる」というアルキメデスの原理そのものですが、ゲームでは物体の中にいくつかの測定点を置き、点ごとに別の場所で力を加えることで、浮き沈みだけでなく、傾いた物が起き上がり、波に合わせて揺れる動きまで作ります。
ゲームでの使いどころ
- 船やボート:波に合わせて上下し、船首と船尾が交互に持ち上がる。荷物を積むと沈み込み、偏って積むと傾く。
- 浮かぶ物・沈む物:木箱や樽は浮き、鉄の箱は沈む。水に落とした物がしぶきを上げて一度沈み、浮かび上がってくる。
- 泳ぎやダイビング:キャラクターの浮き具合、水中で重い装備を持つと沈む、といったゲーム性にも使えます。
- パズル:浮き輪で荷物を浮かせる、水位を上げて足場を浮かせる、など。
しくみ
アルキメデスの原理:水中の物体は、押しのけた水の重さと同じ大きさの上向きの力を受けます。
物体の密度が水(1000 kg/m³)より小さければ、一部だけ沈んだ所で重力と釣り合って浮きます。例えば密度 600 kg/m³ の木箱は、体積の 60% が沈んだ所で止まります。水より重ければ、全部沈んでも浮力が重力に勝てず、沈んでいきます。
ゲームでは、物体の沈んだ体積を正確に求める代わりに、次のように近似します。
- 物体を小さな区画に分ける:例えば直方体を に分け、各区画の中心に測定点を置きます。
- 点ごとに水面と比べる:その点の真上の水面の高さ(波の式から求める)と比べ、どれだけ沈んでいるかを 0〜1 の割合にします。
- 点ごとに力を加える:各点に「区画の体積 × 沈んだ割合」ぶんの浮力を、その点の位置に加えます。重心からずれた位置に力がかかるので、回転させる力(トルク)も生まれます。
片側が沈むとその側の浮力が強くなるので、物体は水平に戻ろうとします。波の斜面では、斜面の高い側の点ほど深く沈むので、物体が波に沿って傾きます。
- 水の抵抗を加える:水中の点には、その点の速度と逆向きの抵抗を加えます。これがないと、物体はばねのように上下に揺れ続けます。回転による点の速度()も含めると、横揺れも自然に収まります。
実装のポイント
- 物理エンジンと組み合わせる:Unity や Unreal なら、各点で
AddForceAtPositionを呼ぶだけで、回転は物理エンジンが計算してくれます。 - 水面の高さは描画と同じ式で:ゲルストナー波なら CPU で同じ式を評価します。GPU の FFT 海洋を使う場合は、高さの画像を CPU に読み戻すか、同じ計算を CPU 側でも低解像度で行います。
- 時間刻みを細かく:浮力はばねのように働くので、軽い物体ほど固い「ばね」になります。固定タイムステップで 1 フレームを数ステップに分けると安定します。
- 測定点の数:大きな船は船体の形に沿って 10〜数十点、小さな物は 4〜8 点程度で十分です。
つまずきやすい点
- 点が 1 つだけ:重心の 1 点だけで浮力を測ると、浮き沈みはしますがトルクが生まれず、傾きも起き上がりもしません。
- 沈んだ割合が 0 か 1 か:点が水面の上か下かの 2 択にすると、点が水面を横切るたびに力が急に変わり、物体ががたがた震えます。区画の高さの中で割合をなめらかに変えます。
- 抵抗がない、または強すぎる:抵抗がないと延々と揺れ、強すぎると水あめの中のように動きが鈍くなります。重い物ほど抵抗の効きが弱くなるよう、区画の体積に比例させます。
デモで試すこと
- 左下の数値は、それぞれの物体が体積の何割沈んでいるかです。密度 320 の小舟は約 3 割、600 の木箱は約 6 割沈み、2400 の鉄の箱は完全に沈みます。
- 「空から落とす」を押すと、傾いた姿勢で落ちた物体が一度深く沈んでから浮かび上がり、水平に起き上がる様子が見られます。
- 「浮力を測る点」を「中心の 1 点」にすると、物体は波に合わせて上下はしますが、傾きが変わらなくなります。3×3×3 点に戻すと、波の斜面に沿って揺れます。
- 「水の抵抗」を 0 にすると、いつまでも上下に揺れ続けます。「波の高さ」を上げると、小舟が波の斜面で大きく傾きます。