Robloxの標準地形水面は基本的な遊泳には適していますが、高速ボートや帆船、リアルな海戦ゲームに必要な流体力学や高精度の波面挙動を提供できません。
船体の四隅に多地点アルキメデス浮力システムを配置し、Luauでゲルストナー波の数式計算を行うことで、荒れ狂う波浪の中でも自然なピッチ・ロール姿勢を維持する堅牢な船を構築できます。
1. デフォルト水面の限界とカスタム船舶物理の必要性
標準の地形水面が複雑な乗り物で破綻する技術的理由:
- 均一なバウンディングボックス浮力:船体全体に一様な浮力がかかるため、船首の上昇や傾きを表現できません。
- 平坦な水面前提:標準水面は立体的な波浪として変形しないため、ダイナミックな波乗りが不可能です。
- 高速時の衝突バグ(物理打ち上げ):高速走行時に離散衝突判定の突き抜けが発生し、船が空中へ吹き飛びます。
- ロール減衰の欠如:急旋回時に船体を元に戻す復元トルクが存在せず、簡単に転覆します。
2. 多地点アルキメデス浮力 & ゲルストナー波サンプリング
船体の各ポイントにおける浮力の精密計算:
- 船体4隅サンプリング:船首・船尾の左右にAttachmentを配置し、水深を個別に計測します。
- 解析的ゲルストナー波の計算:メッシュの送受信なしに、任意の座標 `(X, Z)` の水面高さを数式で即座に算出します。
- 浸水体積に基づく浮力算出:`F = (水深 * 体積 * 重力 * 密度) - (鉛直速度 * 減衰)`。
- 自然な復元力(メタセンタ):傾いた側の沈んだポイントの浮力が増加し、自律的に水平姿勢へと復帰します。
Luau 多地点ゲルストナー波浮力および流体抵抗コントローラー
--!strict
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local BoatPhysics = {}
local WAVES = {
{Dir = Vector2.new(1, 0).Unit, Steepness = 0.4, Length = 60, Speed = 12},
{Dir = Vector2.new(0.7, 0.7).Unit, Steepness = 0.25, Length = 35, Speed = 9}
}
local GRAVITY = Workspace.Gravity
local WATER_DENSITY = 1.025
local POINT_SUBMERGED_VOLUME = 850
local DAMPING = 280
function BoatPhysics.GetWaveHeight(worldX: number, worldZ: number, timeVal: number): number
local elevation = 0
for _, wave in ipairs(WAVES) do
local k = (2 * math.pi) / wave.Length
local c = wave.Speed
local dot = wave.Dir.X * worldX + wave.Dir.Y * worldZ
local phase = k * (dot - c * timeVal)
elevation += math.sin(phase) * (wave.Steepness / k)
end
return elevation
end
function BoatPhysics.UpdateBuoyancy(hullRoot: BasePart, sampleAttachments: {Attachment}, vectorForces: {VectorForce})
local t = Workspace:GetServerTimeNow()
for i, attach in ipairs(sampleAttachments) do
local pos = attach.WorldPosition
local waterY = BoatPhysics.GetWaveHeight(pos.X, pos.Z, t)
local depth = waterY - pos.Y
local vf = vectorForces[i]
if depth > 0 then
local vel = hullRoot:GetVelocityAtPosition(pos)
local upwardForce = math.clamp((depth * POINT_SUBMERGED_VOLUME * GRAVITY * WATER_DENSITY) - (vel.Y * DAMPING), 0, 80000)
local lateralDrag = -Vector3.new(vel.X, 0, vel.Z) * 45
vf.Force = Vector3.new(lateralDrag.X, upwardForce, lateralDrag.Z)
else
vf.Force = Vector3.zero
end
end
end
return BoatPhysics
3. 異方性流体抵抗テンソルと船体流体力学
船体形状に応じた水流抵抗の数学的モデリング:
- 異方性2次抵抗:前進方向の抵抗係数は低く(~0.05)、横滑り抵抗係数は極めて高く(~1.2)設定し、レール上を進むような挙動を実現。
- 滑走(プレーニング)への移行:高速加速時に動的揚力によって船体が持ち上がり、抵抗が減少。
- 角速度減衰:ピッチやロール軸の微小振動を抑えるトルク制動。
- 船尾推進力と舵角ベクトル:旋回時に内側へと自然に傾くリアルなバンク挙動。
4. ネットワーク所有権とマルチプレイ同期
遅延のない滑らかなマルチプレイ物理アーキテクチャ:
- 操縦者へのNetwork Ownership委譲:`SetNetworkOwner(player)`により操作遅延ゼロを実現。
- サーバー時刻に基づく波の決定論的同期:パケットを一切送信することなく、全員が完全に同じ波浪を共有。
- 同乗者の姿勢固定:激しい跳躍時にアバターが船外へ飛び出すバグを防止。
- 無人船のスリープモード:乗員がいない船は計算頻度を落としサーバー負荷を軽減。
5. プロダクションチェックリスト
商用クオリティの船舶システムを構築するためのルール:
- 重心(Center of Mass)を喫水線より下に配置し、転覆を防止。
- 衝突判定パーツを摩擦ゼロのシンプルなウェッジに簡素化。
- 船速と水面衝撃に応じた航跡パーティクルと水しぶき音の連動。
- 視覚的な水面メッシュの変形をゲルストナー波の計算式と100%一致させる。
Frequently Asked Questions
なぜ標準水面ではなくゲルストナー波を使用するのですか?
標準水面は平坦で動的な波がないためです。数式によるゲルストナー波なら、ネットワーク負荷ゼロで同期した大海原を再現できます。
浮力サンプリングポイントは何個が適切ですか?
ボートなら四隅の4ポイントで十分です。大型船なら6〜8ポイントを配置して複数の波に乗る挙動を再現します。
波に突っ込んだ時に船が空へ飛び上がるバグはどう直しますか?
1フレームあたりに加える最大上向き浮力をクランプし、空気抵抗を設定することで解決します。