How to rotate the frame that is pivoted by the mouse position

  1. What do you want to achieve? Keep it simple and clear!
    Heya! I’m currently building a tetris based inventory system, currently in the process of making the front-end which is the client side. Having trouble in managing the rotation of the frames, maintaining its position relative to the mouse

  2. What is the issue? Include screenshots / videos if possible!
    Here’s currently what is doing as of right now

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    There seems to be no answer or question like this in the dev forum before, for context this is the code responsible for rotation

I took the alternative of switching the sizes of the X and Y components to “rotate” the frame, it acts completely the same with the .Rotate property just without the weird clunky problems .Rotate has

UIS.InputBegan:Connect(function(input,processed)
	if processed then return end
	if not currentlyDragging then return end
	
	if input.KeyCode==Enum.KeyCode.R then
		local size:Vector2 = currentlyDragging:GetAttribute("Size")
		local rotation:Vector2 = currentlyDragging:GetAttribute("Rotation")
		
		rotation = rotation==0 and 1 or 0
		currentlyDragging.Size = UDim2.fromOffset( (rotation==0 and size.X or size.Y)*GRID_CELL_SIZE, (rotation==0 and size.Y or size.X)*GRID_CELL_SIZE )
		currentlyDragging:SetAttribute("Rotation",rotation)
		
		local position = Vector2.new(currentlyDragging.Position.X.Offset,currentlyDragging.Position.Y.Offset)
		currentlyDragging.Position = UDim2.fromOffset(position.X,position.Y+(onDragPosition.relative.Y*GRID_CELL_SIZE))
	end
end)

Hi. If you’re still working on solutions, you could try something like this.
To test just attach directly as a LocalScript to some gui element. Once you edit and have the behavior you like, the important bits can be added to your generalized implementation (so it works with whatever is selected and not just the script parent).

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local guiElement = script.Parent -- Replace with your GUI element

local dragging
local dragInput		-- dragInput.Position holds current mouse pos as Vec3
local dragStart
local startPos

local function update(input)
	local delta = input.Position - dragStart
	guiElement.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end

guiElement.InputBegan:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		dragging = true
		dragStart = input.Position
		startPos = guiElement.Position

		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				dragging = false
			end
		end)
	end
	if input.KeyCode==Enum.KeyCode.R then
		-- hide when rotating to avoid visual artifacts
		guiElement.Visible = false
		
		-- Get position of mouse
		local mousePosition = Vector2.new(dragInput.Position.X, dragInput.Position.Y)
		
		-- Store the difference between the mouse and the gui element
		local deltaMouse = mousePosition - guiElement.AbsolutePosition
		
		-- calc the desired final position of gui element after rotation
		local desiredPos = mousePosition - Vector2.new(deltaMouse.Y, deltaMouse.X)
		
		-- rotate the gui element (flip X and Y sizes)
		guiElement.Size = UDim2.new(guiElement.Size.Y, guiElement.Size.X)
		
		-- get the difference between the actual and desired final positions
		local deltaPosition = desiredPos - guiElement.AbsolutePosition
		
		-- move startPos to desired position by adjusting the element's offset
		startPos = UDim2.new(startPos.X.Scale, startPos.X.Offset + deltaPosition.X, startPos.Y.Scale, startPos.Y.Offset + deltaPosition.Y)
		
		-- update position
		update(dragInput)
		
		-- give it a moment to resolve than unhide
		task.wait()
		guiElement.Visible = true
	end
end)

guiElement.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement then
		dragInput = input
	end
end)

RunService.RenderStepped:Connect(function()
	if dragging and dragInput then
		update(dragInput)
	end
end)




I’m currently using roblox’s native UIDragDetector feature, but I’ll try this solution nonetheless thank you!

Just implemented it and now my client-side inventory system is mostly complete now! Thanks so much!!

External Media
1 Like