Water Buoyancy Not Working

I tried to add Buoyancy to this water script however it, doesn’t work. I’ve really tried to get it to work but it doesn’t work at all and I have no idea what the issue is. Any idea? Thanks.

local Wave = {}
Wave.__index = Wave
local newCFrame      = CFrame.new
local IdentityCFrame = newCFrame()
local EmptyVector2   = Vector2.new()
local math_noise     = math.noise
local Stepped        = game:GetService("RunService").RenderStepped
local Player         = game:GetService("Players").LocalPlayer

local default = {
	WaveLength    = 85,
	Gravity       = 1.5,
	Direction     = Vector2.new(1, 0),
	PushPoint     = nil,
	Steepness     = 1,
	TimeModifier  = 4,
	MaxDistance   = 1500,
}

local function Gerstner(pos, wavelength, direction, steepness, gravity, time)
	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(pos.X, pos.Z)) - c * time
	local cosF = math.cos(f)
	return Vector3.new(
		d.X * (a * cosF),
		a * math.sin(f),
		d.Y * (a * cosF)
	)
end

local function CreateSettings(s, o)
	o = o or {}
	s = s or default
	return {
		WaveLength   = s.WaveLength   or o.WaveLength   or default.WaveLength,
		Gravity      = s.Gravity      or o.Gravity      or default.Gravity,
		Direction    = s.Direction    or o.Direction    or default.Direction,
		PushPoint    = s.PushPoint    or o.PushPoint    or default.PushPoint,
		Steepness    = s.Steepness    or o.Steepness    or default.Steepness,
		TimeModifier = s.TimeModifier or o.TimeModifier or default.TimeModifier,
		MaxDistance  = s.MaxDistance  or o.MaxDistance  or default.MaxDistance,
	}
end

local function GetDirection(settings, worldPos)
	if settings.PushPoint then
		local target = settings.PushPoint:IsA("Attachment")
			and settings.PushPoint.WorldPosition
			or settings.PushPoint.Position
		local dir3 = (target - worldPos).Unit
		return Vector2.new(dir3.X, dir3.Z)
	end
	return settings.Direction
end

function Wave.new(instance, waveSettings, bones)
	bones = bones or {}
	for _, v in ipairs(instance:GetDescendants()) do
		if v:IsA("Bone") then
			table.insert(bones, v)
		end
	end
	return setmetatable({
		_instance    = instance,
		_bones       = bones,
		_time        = 0,
		_connections = {},
		_settings    = CreateSettings(waveSettings),
	}, Wave)
end

function Wave:Update()
	local center   = self._instance.Position
	local settings = self._settings

	-- animate bones
	for _, bone in ipairs(self._bones) do
		local worldPos = bone.WorldPosition
		local dir = settings.Direction == EmptyVector2
			and Vector2.new(math_noise(worldPos.X, worldPos.Z, 1), math_noise(worldPos.X, worldPos.Z, 0))
			or GetDirection(settings, worldPos)
		local dist = (worldPos - center).Magnitude
		local minSteep, maxSteep = 0.1, 0.2
		local steepness = dist <= 100 
			and (minSteep + (maxSteep - minSteep) * (dist / 100)) 
			or settings.Steepness
		bone.Transform = newCFrame(
			Gerstner(worldPos, settings.WaveLength, dir, steepness, settings.Gravity, self._time)
		)
	end

	-- buoyancy for non-collidable parts (excluding the player)
	for _, part in ipairs(workspace:GetDescendants()) do
		if part:IsA("BasePart")
		   and not part.Anchored
		   and not part.CanCollide
		   and not (Player.Character and part:IsDescendantOf(Player.Character))
		then
			-- hand network ownership to this client so they can move it
			part:SetNetworkOwner(Player)

			local dist = (part.Position - center).Magnitude
			if dist <= settings.MaxDistance then
				local worldPos = part.Position
				local dir = settings.Direction == EmptyVector2
					and Vector2.new(math_noise(worldPos.X, worldPos.Z, 1), math_noise(worldPos.X, worldPos.Z, 0))
					or GetDirection(settings, worldPos)
				local offset = Gerstner(worldPos, settings.WaveLength, dir, settings.Steepness, settings.Gravity, self._time)
				local waveY = center.Y + offset.Y

				-- sample around for normal
				local s = 0.5
				local p1 = Gerstner(worldPos + Vector3.new(s,0,0), settings.WaveLength, dir, settings.Steepness, settings.Gravity, self._time)
				local p2 = Gerstner(worldPos - Vector3.new(s,0,0), settings.WaveLength, dir, settings.Steepness, settings.Gravity, self._time)
				local p3 = Gerstner(worldPos + Vector3.new(0,0,s), settings.WaveLength, dir, settings.Steepness, settings.Gravity, self._time)
				local p4 = Gerstner(worldPos - Vector3.new(0,0,s), settings.WaveLength, dir, settings.Steepness, settings.Gravity, self._time)
				local tx = (p1 - p2).Unit
				local tz = (p3 - p4).Unit
				local normal = tz:Cross(tx).Unit

				local targetPos = Vector3.new(worldPos.X, waveY, worldPos.Z)

				-- stronger forces on all axes so it holds shape
				local maxF = Vector3.new(part:GetMass()*workspace.Gravity*20,
										 part:GetMass()*workspace.Gravity*20,
										 part:GetMass()*workspace.Gravity*20)

				local bp = part:FindFirstChild("_WaveBP") or Instance.new("BodyPosition", part)
				bp.Name = "_WaveBP"
				bp.MaxForce = maxF
				bp.P = 2000
				bp.D = 500
				bp.Position = targetPos

				local bg = part:FindFirstChild("_WaveBG") or Instance.new("BodyGyro", part)
				bg.Name = "_WaveBG"
				bg.MaxTorque = maxF
				bg.P = 2000
				bg.D = 500
				bg.CFrame = CFrame.fromMatrix(targetPos, tx, normal, tz)
			else
				local bp = part:FindFirstChild("_WaveBP")
				if bp then bp:Destroy() end
				local bg = part:FindFirstChild("_WaveBG")
				if bg then bg:Destroy() end
			end
		end
	end
end

function Wave:Refresh()
	for _, bone in ipairs(self._bones) do
		bone.Transform = IdentityCFrame
	end
	for _, part in ipairs(workspace:GetDescendants()) do
		local bp = part:FindFirstChild("_WaveBP")
		if bp then bp:Destroy() end
		local bg = part:FindFirstChild("_WaveBG")
		if bg then bg:Destroy() end
	end
end

function Wave:UpdateSettings(waveSettings)
	self._settings = CreateSettings(waveSettings, self._settings)
end

function Wave:ConnectRenderStepped()
	local conn = Stepped:Connect(function()
		if not game:IsLoaded() then return end
		-- always update time & wave
		self._time = (DateTime.now().UnixTimestampMillis / 1000) / self._settings.TimeModifier
		self:Update()
	end)
	table.insert(self._connections, conn)
	return conn
end

function Wave:Destroy()
	self._instance = nil
	for _, conn in ipairs(self._connections) do
		pcall(conn.Disconnect, conn)
	end
	self._bones = {}
	self._settings = {}
end

return Wave

Any ideas? Thanks!

2 Likes