Hello, I would like to make a part that keeps on rotating while moving up and down.

I would like to know if this is possible, I’ve tried making a script for the part to keep moving up, down and another script for it to keep spinning/ rotating. (I used a while loop and change it’s rotation with CFrame.Angles(), which isn’t what I wanted)

I used a tweenservice for the part to move up and down, so it’s smoother. I was hoping if I can also tween the part to keep spinning to have a smooth movement.

I want to do all the above, but not the tween being reversed. I’m also thinking of firing a remote event to all the clients, so the tween looks smooth and not laggy.

Here’s a video of what I mean: (Bandi’s Land, Created by BandiRue)

1- you could interpolate the height manually every frame on a sine wave or similar (or use TweenService:GetValue) and also apply an angular offset using CFrame.Angles. This will give you more precision in terms of speed and whatnot.

local part = workspace:WaitForChild('Part')
local lowerBound = part.Position - Vector3.new(0, 3, 0)
local upperBound = part.Position + Vector3.new(0, 3, 0)
local radiansPerSecond = math.rad(90) -- a quarter turn every second (we need to do this to maintain a consistent velocity), needs to be wrapped in math.rad as CFrame.Angles takes an arg in radians not degrees
local identityRotation = CFrame.identity.Rotation -- equivalent of CFrame.Angles(0, 0, 0)
local currentRotation = identityRotation -- our starting rotation
while true do
local delta = task.wait()
local now = tick()
-- math.sin returns a value between -1 and 1 so we first need to add 1 to get a number between 0 and 2, then divide by 2 (multiply by 0.5) to get a number between 0 and 1 so it does not exceed the boundaries we set above
local position = lowerBound:Lerp(upperBound, (math.sin(now) + 1) * 0.5)
currentRotation *= CFrame.Angles(0, radiansPerSecond * delta, 0) -- delta how much time passed since the previous frame, multiplying it by degreesPerSecond gives us how much we should rotate based on time it took to render the frame
-- finally apply our current CFrame to the part's CFrame
part.CFrame = CFrame.new(position) * currentRotation
end

2- you could use AlignPosition and an AngularVelocity instance to apply a constant torque and change of position to the part which would probably be faster from a performance standpoint since physics are calculated in C which is significantly faster than in Lua.

There is basically no difference between manually interpolating every frame and tweening. Tweening just handles the interpolation for you but it is behaviourally identical to manually interpolating, it does the exact same thing. It’s also important to make sure you’re interpolating every frame to get the desired effect. If you’re using something like wait() in an infinite loop, it’ll look choppy as you’re only changing its CFrame every 1/20th of a second compared to every 1/60th or even less if the users frames are unlocked.

Physics will be smooth if the part is either cloned on the client or if the client has network ownership over the part. This is probably the way that has the least performance impact, plus Roblox has built in optimizations for physics but those are internal so I’m not too sure about the specifics.

Usually the performance impact is negligible unless you’re interpolating like thousands of parts (since interpolation is relatively simple math) but there are some things you can do to improve the speed, like use parallel for each different combination of speeds, then apply them back in serial. But with native vectors, vector math is very fast because again those calculations are done in C and not Lua.