Trying to make the part not overshoot

I’m making a system where you can move, rotate or scale objects but I have a slight problem

local player = game.Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local part = workspace:WaitForChild("MovablePart")

local handles = Instance.new("Handles")
handles.Parent = playerGui
handles.Adornee = part
handles.Style = Enum.HandlesStyle.Movement

local grid = 0.2

local faceActions = {
	[Enum.NormalId.Front] = function(value) return value * -1 end,
	[Enum.NormalId.Back] = function(value) return value end,
	[Enum.NormalId.Left] = function(value) return value * -1 end,
	[Enum.NormalId.Right] = function(value) return value end,
	[Enum.NormalId.Top] = function(value) return value end,
	[Enum.NormalId.Bottom] = function(value) return value * -1 end
}

handles.MouseDrag:Connect(function(face, distance)
	local movedistance = distance * grid
	local newPos = part.Position
		if face == Enum.NormalId.Front or face == Enum.NormalId.Back then
			local moveDirection = part.CFrame:vectorToWorldSpace(Vector3.new(0, 0, faceActions[face](movedistance)))
			newPos = newPos + moveDirection
		elseif face == Enum.NormalId.Left or face == Enum.NormalId.Right then
			local moveDirection = part.CFrame:vectorToWorldSpace(Vector3.new(faceActions[face](movedistance), 0, 0))
			newPos = newPos + moveDirection
		elseif face == Enum.NormalId.Top or face == Enum.NormalId.Bottom then
			local moveDirection = part.CFrame:vectorToWorldSpace(Vector3.new(0, faceActions[face](movedistance), 0))
			newPos = newPos + moveDirection
		end
	part.Position = newPos
end)

When I move with the cursor, it sometimes “overshoots” when dragging with the Handle.
What am I doing wrong here?

2 Likes

i think vectorToWorldSpace takes into account the scale of the Part
you can check that if your scaled up your part, and then do the drag, it will overshoot now?

2 Likes

Nope it still overshoots (the part is moving faster than the cursor has dragged the handle)

1 Like

i mean you just confirmed that the part’s scale make it so.
I wanted to identify it is the situation. i didn’t offer any fix.

2 Likes

Here’s the fix

-- we rotate to the direction first, then scale by the move distance
local moveDirection = part.CFrame:vectorToWorldSpace(Vector3.new(0, 0, faceActions[face](1))).Unit * movedistance
newPos += moveDirection
1 Like

we can use Vector3.FromNormalId to simplify things

local player = game.Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local part = workspace:WaitForChild("MovablePart")

local handles = Instance.new("Handles")
handles.Parent = playerGui
handles.Adornee = part
handles.Style = Enum.HandlesStyle.Movement

local grid = 0.2

handles.MouseDrag:Connect(function(face, distance)
	local movedistance = distance * grid
	local moveDirection = part.CFrame:vectorToWorldSpace(Vector3.FromNormalId(face)).Unit * movedistance
	part.Position += moveDirection
end)
1 Like

I think I might know why it’s overshooting:
Since we are just using the distance, there will be multiple distance, which would be like applying the same distance variable multiple times, which causes the overshooting:

Secondly, this is applying on the position, when it is supposed to apply on the part’s last position
I realized the issue, thanks.

2 Likes

I managed to fix the issue. Here is the solution for anyone wondering

local player = game.Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local part = workspace:WaitForChild("MovablePart")

local handles = Instance.new("Handles")
handles.Parent = playerGui
handles.Adornee = part
handles.Style = Enum.HandlesStyle.Movement

local faceActions = {
	[Enum.NormalId.Front] = function(value) return value * -1 end,
	[Enum.NormalId.Back] = function(value) return value end,
	[Enum.NormalId.Left] = function(value) return value * -1 end,
	[Enum.NormalId.Right] = function(value) return value end,
	[Enum.NormalId.Top] = function(value) return value end,
	[Enum.NormalId.Bottom] = function(value) return value * -1 end
}

local lastPosition = nil
local lastDistance = nil
local grid = 1

handles.MouseButton1Down:Connect(function()
	lastPosition = Vector3.new(part.Position.X, part.Position.Y, part.Position.Z)  -- Store the part's position as a reference
end)

handles.MouseDrag:Connect(function(face, distance)
	local moveDistance = distance * grid  -- Scale the drag distance by grid value

	if lastDistance ~= moveDistance then
		-- Calculate the movement direction based on the face normal
		local moveDirection = part.CFrame:vectorToWorldSpace(Vector3.FromNormalId(face)).Unit * moveDistance

		-- Update part's position based on the movement
		part.Position = lastPosition + moveDirection  -- Use lastPosition as reference to calculate new position

		lastDistance = moveDistance  -- Store the moved distance for comparison
	end
end)

Minor Mistake: grid manages how much you have to drag to move it, not the snapping grid one. Sorry about that

2 Likes