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!