Limiting a Handle Range

Howdy developers!

Today I come to you seeking math assistance. Long story short, I am allowing players in my game to use Handles to move certain objects. BUT - I need for the object they’re dragging to never be more than Y studs away from the ‘center’, which is PartX in this case.

I’m using the code below, which works fine for now. But it has no way of stopping players from dragging an object beyond a my desired range Y from PartX. I figure it has something to do with .magnitude, but I have no idea here.

I appreciate any and all responses!

handle_Z.MouseDrag:Connect(function(face, distance)
	local adornee = handle_Z.Adornee
	local direction = 1
	if face == Enum.NormalId.Left then
		direction = -1
	end
	adornee.CFrame = adornee.OriginalCFrame.Value * CFrame.new(distance * direction, 0, 0)
end)

I think you could use math.clamp for this. Only problem is that the boundary would be quadratic, not spherical. I haven’t really dabbled in adornments yet but I think something like this should work:

local maxDistance = 10
local partX = workspace.Part

-- inside of your MouseDrag connection

local partPosX = partX.Position.X
adornee.CFrame = adornee.OriginalCFrame.Value * CFrame.new(distance * direction, 0, 0)
local clampedPos = math.clamp(adornee.Position.X, partPosX - 10, partPosX + 10)
adornee.Position = Vector3.new(clampedPos, adornee.Position.Y, adornee.Position.Z)
1 Like

Oh sweet! Thanks for the response. Unfortunately, this doesn’t seem to successfully clamp the part inside the quadratic range box. I’m able to drag the part beyond the range

Weird, do you have your axes mixed up? I see in your OP that you’re using handle_Z but you’re modifying the X axis.

Good catch! I’m not sure how I missed that. Oddly enough, the issue still persists after fixing it.

    local adornee = module.gui.Handle_Z.Adornee
	local direction = 1
	if face == Enum.NormalId.Left then
		direction = -1
	end
	local pos = adornee.Position.Z
	adornee.CFrame = adornee.OriginalCFrame.Value * CFrame.new(distance * direction, 0, 0)
	local clampedPos = math.clamp(adornee.Position.Z, pos - 3, pos + 3)
	adornee.Position = Vector3.new(adornee.Position.X, adornee.Position.Y, clampedPos)

*I’m assuming I modified this correctly, though I could be wrong

Weird, give me a few and I’ll try to reproduce the issue in Studio.

1 Like

Alrighty, I took a look and I am not sure what is going on. Might be due to the type of handle adornments you are using, if what I am going to write doesn’t help, could you provide the type of adornment you are using?

I wrote this up quickly (and very poorly), it generally moves in the same direction if using right, top or back but it’s a bit weird when using the other 3 axes but note the part doesn’t move past the clamp.

local handles = script.Parent.Handles
local initPart = workspace.InitPart

local maxDistance = 10

handles.Adornee = workspace.MovePart
handles.MouseDrag:Connect(function(normal, distance)
	if normal == Enum.NormalId.Right or normal == Enum.NormalId.Left then -- right is X axis
		local adornee = handles.Adornee
		adornee.CFrame *= CFrame.new(distance,0,0)
		local clamped = math.clamp(adornee.Position.X, initPart.Position.X - 10, initPart.Position.X + 10)
		if normal == Enum.NormalId.Left then -- invert the distance to be consistent with the mouse's direction
			clamped *= -1
		end
		adornee.Position = Vector3.new(clamped,adornee.Position.Y, adornee.Position.Z)
	elseif normal == Enum.NormalId.Top or normal == Enum.NormalId.Bottom then -- top is Y axis
		local adornee = handles.Adornee
		adornee.CFrame *= CFrame.new(0,distance,0)
		local clamped = math.clamp(adornee.Position.Y, initPart.Position.Y - 10, initPart.Position.Y + 10)
		if normal == Enum.NormalId.Bottom then
			clamped *= -1
		end
		adornee.Position = Vector3.new(adornee.Position.X,clamped,adornee.Position.Z)
	elseif normal == Enum.NormalId.Back or normal == Enum.NormalId.Front then -- back is Z axis
		local adornee = handles.Adornee
		adornee.CFrame *= CFrame.new(0,0,distance)
		local clamped = math.clamp(adornee.Position.Z, initPart.Position.Z - 10, initPart.Position.Z + 10)
		if normal == Enum.NormalId.Front then
			clamped *= -1
		end
		adornee.Position = Vector3.new(adornee.Position.X,adornee.Position.Y, clamped)
	end
end)

Oh sweet! I think this may work, I’m going to do a little more experimenting. Thank you for taking the time to write this!

I’m going to try to mess with this to see if it can be made a little more reliable.

1 Like

Hey there, was able to get it working reliably, try this out:

local handles = script.Parent.Handles
local initPart = workspace.InitPart

local maxDistance = 10

handles.Adornee = workspace.MovePart
handles.MouseButton1Down:Connect(function()
	local connections = {}
	local adornee = handles.Adornee
	local posOnDown = adornee.Position
	connections[#connections + 1] = handles.MouseDrag:Connect(function(normal, distance)
		if normal == Enum.NormalId.Right or normal == Enum.NormalId.Left then -- right is X axis
			local tempPos = posOnDown + Vector3.new(distance,0,0)
			local relativeX = initPart.Position.X - tempPos.X
			if normal == Enum.NormalId.Right then
				relativeX = -relativeX
			end
			local clamped = math.clamp(relativeX, -maxDistance, maxDistance)
			adornee.Position = Vector3.new(initPart.Position.X + clamped, adornee.Position.Y, adornee.Position.Z)
		elseif normal == Enum.NormalId.Top or normal == Enum.NormalId.Bottom then -- top is Y axis
			local tempPos = posOnDown + Vector3.new(0,distance,0)
			local relativeY = initPart.Position.Y - tempPos.Y
			if normal == Enum.NormalId.Top then
				relativeY = -relativeY
			end
			local clamped = math.clamp(relativeY, -maxDistance, maxDistance)
			adornee.Position = Vector3.new(adornee.Position.X, initPart.Position.Y + clamped, adornee.Position.Z)
		elseif normal == Enum.NormalId.Back or normal == Enum.NormalId.Front then -- back is Z axis
			local tempPos = posOnDown + Vector3.new(0,0,distance)
			local relativeZ = initPart.Position.Z - tempPos.Z
			if normal == Enum.NormalId.Back then
				relativeZ = -relativeZ
			end
			local clamped = math.clamp(relativeZ, -maxDistance, maxDistance)
			adornee.Position = Vector3.new(adornee.Position.X, adornee.Position.Y, initPart.Position.Z + clamped)
		end
	end)
	connections[#connections + 1] = handles.MouseButton1Up:Connect(function()
		for i,v in pairs(connections) do
			v:Disconnect()
		end
	end)
end)

2 Likes

That’s fantastic! It runs very smoothly. Would this also work if the part were rotated in random configurations?

Sorry for the late response, was out.

It should work with rotated parts as it’s only updating the position, not the CFrame.

Whether it’s going to move along the axis it’s rotated on though, probably not. You’d probably have to use the Up/Right/LookVector to determine where to move the part.

1 Like