What math is particularly required to achieve being able to resize BaseParts using Handles?

What do you want to achieve?
I want to find a way, mathematically, that a Part will remain in the same position as it started when resizing it using Handles. I have half achieved this, but I’m still missing how to do the other half, demonstrated in this video:

What is the issue?
https://i.gyazo.com/d4e53d4ef2e6304273b4ab781b632b2f.mp4
As seen in the video, resizing works perfectly and the Y position remains 1/2 of the new size to maintain position. However, when I release my mouse and try resizing again from where the Part’s size left off, it resets back to it’s original size AND position and the handles go with it but the mouse is still able to adjust the size, at the top of the screen and not even where the handles are. I’m not referring to the cosmetic issue that the mouse is at the top of the screen, but just that the Size and Position of the part literally reset to what they were to begin with when I try redragging the handle. That’s my best explanation but if I need to elaborate further I can.

What solutions have you tried so far?
I’ve tried changing the equation that sets both the Size and Position but I’m unable to get it to maintain it’s position and size that it was left off as. I’ve also dug a bit into the Developer Forum to find similar questions but I couldn’t find anything related to it. There’s also a lack of documentation for Handles, especially with it’s events. Would’ve helped if there were even small code snippets in the documentation.

I’m not asking for a whole script, just the (hopefully) single line of math code that I’m missing in my script.

LocalScript code:

script.Parent.Handles.MouseDrag:Connect(function(face, distance)
	if script.Parent.Handles.Style == Enum.HandlesStyle.Resize then
		game.ReplicatedStorage.Resize:FireServer(face, distance)
	end
end)

ServerScript code:

game.ReplicatedStorage.Resize.OnServerEvent:Connect(function(Player, Face, Distance)
	if SelectedPart ~= nil then -- checks if there is a selected part
		if math.floor(Distance+0.5) > 50 then -- just a size constraint for when the Distance is over 50 studs
			Distance = 50
		else
			Distance = math.floor(Distance+0.5)
		end
		if Distance == 0 then
			Distance = 1
		end

		local px = SelectedPart.Position.X
		local py = SelectedPart.Position.Y
		local pz = SelectedPart.Position.Z
		local sx = SelectedPart.Size.X
		local sy = SelectedPart.Size.Y
		local sz = SelectedPart.Size.Z

		if Face == Enum.NormalId.Top then
			-- these two lines are what I'm struggling with
			SelectedPart.Size = Vector3.new(sx, Distance, sz)
			SelectedPart.Position = Vector3.new(px, Distance/2, pz)
		end
	end
end)

This is the working version of the Server Script. I’ve made nearly hundreds of variants changing the code for just those 2 lines I labeled, but nothing pulled off what I am trying to achieve. All I’m asking for is the mathematical equation in the Y vector or what I’m missing from the entirety of the script to make it so letting go and redragging a handle doesn’t reset the SelectedPart’s size and position.

1 Like

Here’s a working “local resize” tool: ResizeTool.rbxm (2.1 KB)

Drag-and-drop into an open place in Studio to insert it.

The relevant code is this:

handles.MouseButton1Down:Connect(function()
	local dragC, mouseUpC
	
	local prevDist = 0 --The distance from last time handles.MouseDrag fired
	
	dragC = handles.MouseDrag:Connect(function(face, distance)
		local deltaDist = (distance - prevDist) --How far the handle was dragged
		
		local resizeDir = Vector3.FromNormalId(face)
		if resizeDir.X == -1 or resizeDir.Y == -1 or resizeDir.Z == -1 then
			handles.Adornee.Size += -1 * resizeDir * deltaDist
		else
			handles.Adornee.Size += resizeDir * deltaDist
		end
		handles.Adornee.Position += resizeDir * deltaDist / 2
		
		prevDist = distance --Update for next time handle is dragged
	end)
	
	mouseUpC = handles.MouseButton1Up:Connect(function()
		dragC:Disconnect()
		mouseUpC:Disconnect()
	end)
end)

The important thing is that it doesn’t use the distance variable to compute the size or position directly, but keeps track of how it changes and uses that to increment the size and position.

2 Likes

Thanks! It took me a minute to figure how to turn this to be server-sided but I got it working and it’s great. I figured that I had to reset the prevDist variable to 0 by firing a remote to the server every time the user reclicked a handle.

1 Like