Water bobbing effect (looks bouyant) - Not 100% accurate - Configurable

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 (:sob:)


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)

That’s all for now, see ya

8 Likes

Please use RunService’s Hearbeat instead of while loops

2 Likes

This wasn’t ment to be perfect, and as I said, just modify it if you need to

Send an updated code if you feel it would be better

1 Like

Can we see it in action at least? :skull:

2 Likes

Sure! It’s pretty simple, let me get a recording quickly

Is this supposed to be on a part?

Yes, or anything.

I designed it with a mesh that looks like a rock, so it might not work with a blocky part

2 Likes

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.

3 Likes

Thank you, I’ll add that onto the main post

Wanted to link this here (you may already be familiar): Sampling Terrain Water Height at Any Position

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)

2 Likes

Seen that before, I may create a version where it floats but then again it’s probably linked somewhere in the post

And this was ment to be a simple script just so people that are new to coding / maths can learn :slight_smile:

3 Likes