Not really much to say, it’s all configurable inside the script
Here is the code:
local part = script.Parent
local originalPosition = part.Position
local amplitude = 0.5
local frequency = 2
local rotationAmplitude = 0.05
local rotationFrequency = 1
while true do
local currentTime = tick()
local offset = amplitude * math.sin(currentTime * frequency)
local rotationX = rotationAmplitude * math.sin(currentTime * rotationFrequency)
local rotationY = rotationAmplitude * math.sin(currentTime * rotationFrequency)
local rotationZ = rotationAmplitude * math.sin(currentTime * rotationFrequency)
local newCFrame = CFrame.new(originalPosition + Vector3.new(0, offset, 0)) * CFrame.Angles(rotationX, rotationY, rotationZ)
part:PivotTo(newCFrame)
task.wait(0.01)
end
Open-sourced, so change it if you want and publish whatever I do not care
Just thought I’d publish this because I haven’t made a community resource yet ()
Thanks @gianmarco2712 for a more performant one, here is the code
local part = script.Parent
local originalPosition = part.Position
local amplitude = 0.5
local frequency = 2
local rotationAmplitude = 0.05
local rotationFrequency = 1
game:GetService("RunService").RenderStepped:Connect(function() -- change .RenderStepped to .Heartbeat if it is a server script
local currentTime = tick()
local sine = math.sin(currentTime * frequency)
local offset = amplitude * sine
local rotation = rotationAmplitude * sine
local newCFrame = CFrame.new(originalPosition + Vector3.new(0, offset, 0)) * CFrame.Angles(rotation, rotation, rotation)
part:PivotTo(newCFrame)
end)
Looks like an okay bobbing effect, but there are multiple ways of fixing this script. You could’ve made the sine function a variable, along with rotationX, rotationY, and rotationZ all being one variable since they do the same thing. Also, use RenderStepped (or Heartbeat if your doing this on the server) instead of a while loop. RenderStepped runs every frame.
local part = script.Parent
local originalPosition = part.Position
local amplitude = 0.5
local frequency = 2
local rotationAmplitude = 0.05
local rotationFrequency = 1
game:GetService("RunService").RenderStepped:Connect(function()
local currentTime = tick()
local sine = math.sin(currentTime * frequency)
local offset = amplitude * sine
local rotation = rotationAmplitude * sine
local newCFrame = CFrame.new(originalPosition + Vector3.new(0, offset, 0)) * CFrame.Angles(rotation, rotation, rotation)
part:PivotTo(newCFrame)
end)
One benefit to using three variables is being able to make them move at different speeds to make the bobbing look more diverse, but if all the variables are gonna be the exact same, just combine them.
Of course, this is for bobbing (not floating, which is what the above link is), but it might be interesting to try integrating semi-independent bobbing based on actual water position (i.e., bobbing motion occurs, but respects actual wave motion too, avoid edge-cases such as floating in air)