✓ Accepted answer
The solution that I came up with doesn't deal with a delay, but rather by giving the GUI a minimum and maximum rotation speed. The speed of the GUI is calculated by a ratio of how much rotation is needed to get to the desired angle. The speed is then multiplied by the elapsed time since the last update to calculate the distance the GUI needs to rotate. The formula for this is as follows:
maxSpeed*(dist + minSpeed)/(180 + minSpeed)
Everytime the mouse is moved, I update the desired angle. The infinite while loop is in charge of updating the GUI. It works using a delta time loop, updating every render frame. In order to rotate to the desired angle, we need to determine if we should rotate clockwise (negative) or counter-clockwise (positive). Once the direction is known, we find the distance we need to rotate this render frame and apply it to the GUI.
When the desired Rotation is reached, we wait for the mouse to move before trying any more updates. This is so we don't waste any computations.
Full Code:
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local frame = script.Parent
local maxSpeed = 360
local minSpeed = 15
local desiredAngle = 0
mouse.Move:connect(function()
local center = frame.AbsolutePosition + frame.AbsoluteSize/2
local x = mouse.X - center.X
local y = center.Y - mouse.Y
desiredAngle = 90 - math.deg(math.atan2(y, x))
end)
while true do
local lastTick = tick()
repeat
RunService.RenderStepped:Wait()
local elapsed = tick() - lastTick
local cw = (frame.Rotation - desiredAngle)%360
local ccw = ((desiredAngle + 360) - frame.Rotation)%360
if cw < ccw then
frame.Rotation = frame.Rotation - math.min(maxSpeed*((cw + minSpeed)/(180 + minSpeed))*elapsed, cw)
else
frame.Rotation = frame.Rotation + math.min(maxSpeed*((ccw + minSpeed)/(180 + minSpeed))*elapsed, ccw)
end
lastTick = tick()
until math.abs(frame.Rotation%360 - desiredAngle%360) < 0.01
mouse.Move:wait()
end