it doesn`t rotate exactly where the mouse is, its slightly offset and it gets worse the closer it get to being horizontal
it keeps rotating even after MouseButton1Up event fires
the current code
local render = game:GetService("RunService")
local uis = game:GetService("UserInputService")
local players = game:GetService("Players")
-----------------------------------------------------
local player = players.LocalPlayer
local plyrgui = player:WaitForChild("PlayerGui")
local mouse = player:GetMouse()
-----------------------------------------------------
local button = script.Parent
local root = button.Parent.Parent
local toggle = false
button.MouseButton1:Connect(function()
toggle = true
end)
button.MouseButton1Up:Connect(function()
toggle = false
end)
render.RenderStepped:Connect(function()
if uis:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) and toggle then
local rootpos = root.AbsolutePosition - (root.AbsoluteSize/2)
local angle = math.deg(math.atan2(mouse.Y - rootpos.Y, mouse.X - rootpos.X))
root.Rotation = angle + 90
end
end)
Phew. This took me longer than I am comfortable to admit.
Anyways, you should ADD half of the size to the rootpos and not substract, as AbsolutePosition points to the left corner of the GUI object. This was the cause of the weird behaviour. I also suggest to to put this calculation outside the function, as rotating the thing will likely affect this value.
To prevent image from rotating more than 180 degree, you would normally use math.clamp. However, atan2 automatically rolls over from -179 to +180. Therefore I manually remove 360 in such cases, before using math.clamp().
I have also took the liberty of optimising your code a bit. There is no need to run RenderStepped when player is not actively pressing the button.
Here is the code:
local render = game:GetService("RunService")
local uis = game:GetService("UserInputService")
local players = game:GetService("Players")
-----------------------------------------------------
local player = players.LocalPlayer
local plyrgui = player:WaitForChild("PlayerGui")
local mouse = player:GetMouse()
-----------------------------------------------------
local button = script.Parent
local root = button.Parent.Parent
local connnection = nil
local rootpos = root.AbsolutePosition + (root.AbsoluteSize/2) --the bug was here
local function OnRenderStepped()
local angle = math.deg(math.atan2(mouse.Y - rootpos.Y,mouse.X - rootpos.X))
if angle > 90 then angle -= 360 end
root.Rotation = math.clamp(angle+90,-90,90)
end
button.MouseButton1Down:Connect(function()
if not connnection then
connnection = render.RenderStepped:Connect(OnRenderStepped)
end
end)
local function OnMouseButtonUp()
if connnection then
connnection:Disconnect()
connnection = nil
end
end
button.MouseButton1Up:Connect(OnMouseButtonUp)
uis.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
OnMouseButtonUp()
end
end)
This is mostly to prevent having multiple connection active. You could probably skip putting 'nil` into this variable, but there might be an off chance that player clicks the button twice in quick succession, due to, for example, a worn out button on the mouse.
I just like to have everything double checked.
Each time a connection is made, I double check if there is not a connection active already. The easiest way is to do it is to put nil into the connection variable, after a disconnect.
As for the reason why you should do it this way, it comes down to performance. You do not want to have the script checking for toggle 60 times per second, when player is not actively interacting with the button. You may get away with this this time, but once your game grows, each script with RunService connection will slowly, but surely, eat away available resources.