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)
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?
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
3 Likes