I need help making boat physics for my Gerstner Waves

Hi

I have been trying to create boat physics for my Gerstner Waves but every time i attempt to do so, the boat just falls to the ocean floor.

I have tried using the 3 waves within the formula to calculate the height of the water. I would then use that height and compare it with nodes on all 4 sides of the boat which then tells a gyro part in the middle to rotate with CFrame.

Here is some media related to my problem

Entire Boat in Explorer

image

Some Clips


This is the Gerstner Wave formula found in StarterPlayerScripts:

local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")

local speedMultiple = 0.0025	-- Smaller is faster wave movement, higher is slower
local maxDistance = 350 -- Distance in studs from character, to stop calculating bone position

local origPosTable = {}
local LocalPlayer = Players.LocalPlayer



function GerstnerWave(SamplePosition ,Wavelength, Direction, Steepness, Gravity, SampleTick)
	local k = (2 * math.pi) / Wavelength
	local a = Steepness/k
	local d = Direction.Unit
	local c = math.sqrt(Gravity / k)
	local f = k * d:Dot(Vector2.new(SamplePosition.X,SamplePosition.Z)) - c * SampleTick
	local cosF = math.cos(f)

	--Displacement Vectors
	local dX = (d.X * (a * cosF))
	local dY = a * math.sin(f)
	local dZ = ( d.Y * (a * cosF))
	return Vector3.new(dX, dY, dZ)
end

local plane = workspace:WaitForChild("Ocean"):WaitForChild("Plane")
for _, bone in pairs(plane:GetChildren()) do
	if bone:IsA("Bone") then
		origPosTable[bone] = bone.Position
	end
end

local function getNodeHeight(node, speedCounter)
	local SamplePosition = node.WorldPosition
	local Wave1 = GerstnerWave(SamplePosition, 150, Vector2.new(1, 0), .05, 1, speedCounter)
	local Wave2 = GerstnerWave(SamplePosition, 175, Vector2.new(0, .3), .2, 1.25, speedCounter)
	local Wave3 = GerstnerWave(SamplePosition, 200, Vector2.new(1, 1), .1, 1.5, speedCounter)
	local TotalDisplacement = Wave1 + Wave2 + Wave3
	return TotalDisplacement.Y
end

local function getCameraHeight(position, speedCounter)
	local Wave1 = GerstnerWave(position, 150, Vector2.new(1, 0), .05, 1, speedCounter)
	local Wave2 = GerstnerWave(position, 175, Vector2.new(0, .3), .2, 1.25, speedCounter)
	local Wave3 = GerstnerWave(position, 200, Vector2.new(1, 1), .1, 1.5, speedCounter)
	local TotalDisplacement = Wave1 + Wave2 + Wave3
	return TotalDisplacement.Y
end

local function updateCameraBlur(cameraPosition, speedCounter)
	local waveHeight = getCameraHeight(cameraPosition, speedCounter)
	local cameraUnderWater = cameraPosition.Y - 2.1 < waveHeight

	if cameraUnderWater then
		game.Lighting.Blur.Size = 15
		game.Lighting.Atmosphere.Density = 0.95
		game.Lighting.Atmosphere.Offset = 1
		Players.LocalPlayer.PlayerGui.Swells.Volume = 2.5
		workspace.Music.EqualizerSoundEffect.HighGain = -11.6
		workspace.Music.EqualizerSoundEffect.MidGain = -11.6
		Players.LocalPlayer.PlayerGui.GoUnder:Play()
	else
		game.Lighting.Blur.Size = 4
		game.Lighting.Atmosphere.Density = 0.5
		game.Lighting.Atmosphere.Offset = 0
		Players.LocalPlayer.PlayerGui.Swells.Volume = 0
		workspace.Music.EqualizerSoundEffect.HighGain = 10
		workspace.Music.EqualizerSoundEffect.MidGain = 10
		Players.LocalPlayer.PlayerGui.GoUp:Play()
	end
end

local skipCounter = 0
local speedCounter = 0
game:GetService("RunService").Heartbeat:Connect(function()
	skipCounter += 1
	speedCounter += speedMultiple
	if skipCounter >= 2 then
		skipCounter = 0

		local char = LocalPlayer.Character
		if char and char:FindFirstChild("HumanoidRootPart") then
			for _, bone in pairs(plane:GetChildren()) do
				if bone:IsA("Bone") then
					if origPosTable[bone] then
						if (char.HumanoidRootPart.Position - bone.WorldPosition).Magnitude <= maxDistance then
							local SamplePosition = bone.WorldPosition

							local Wave1 = GerstnerWave(SamplePosition, 150, Vector2.new(1, 0), .05, 1, speedCounter)
							local Wave2 = GerstnerWave(SamplePosition, 175, Vector2.new(0, .3), .2, 1.25, speedCounter)
							local Wave3 = GerstnerWave(SamplePosition, 200, Vector2.new(1, 1), .1, 1.5, speedCounter)
							local TotalDisplacement = Wave1 + Wave2 + Wave3
							bone.Position = origPosTable[bone] + TotalDisplacement
						end
					end
				end
			end
		end
		local cameraPosition = workspace.CurrentCamera.CFrame.Position
		updateCameraBlur(cameraPosition, speedCounter)
	end
end)

I am confused how people manage to make working boat physics while all I can do is implement a camera system where it changes atmosphere when I dip my camera under.

Any tips or help would be greatly appreciated because I can’t figure out exactly what to do here.

Reference - Making A Mesh Deformation Ocean

1 Like

Gerstner waves used to be a unity thing before Roblox added mesh deformation.

You can try to translate unity code to roblox code:

2 Likes