Help with a dragging system

Hello! I am looking to make a X and Y dragging system for my game using the players mouse when I ran into a problem.

I can have the player move the part on the X, Y, and Z axis perfectly fine
xyz.wmv (153.8 KB)

But when I try to lock the axis to only X and Y, this happens
xy.wmv (247.5 KB)

RunService.RenderStepped:Connect(function()
	if Clicking == true then
		if Target ~= nil and CollectionService:HasTag(Target, "FoodItem") then
			
			Target.Position = Vector3.new(Mouse.Hit.x, Mouse.Hit.y, Target.Position.z)
			-- The code above is what has the weird offset with the mouse.
			-- Target is just a pre determined part in workspace.
			
		end
	end
end)

If anybody can help me figure out a solution to fix the weird offset when you drag around a part it would be greatly appriceated! Sorry if this is a stupid question, I have no idea what I’m doing, lol.

3 Likes

It seems like the mouse isn’t hitting where you expect. Try printing the Z coordinate of mouse.Hit, and compare it to what it should be.

I’d guess the FoodItem part isn’t at the same Z coordinate as the part, so you’re getting a kind of parallax effect that is clearly visible in the video.

2 Likes

Thanks for responding! Mouse.Hit.z’s position is indeed behind where the parts z position is. So how exactly would I get rid of this parallax effect to have it exactly where the mouse is on the X and Y axis?

1 Like

You do it by figuring out where the mouse hits the specific plane you’re interested in, by doing ray-plane collision detection. The code for this is available on one of my favorite sites: https://geomalgorithms.com/code.html Specifically we want the function intersect3D_SegmentPlane() - find the 3D intersection of a segment and a plane.

Here's the license, make sure you read and comply with it
// Copyright 2001, 2012, 2021 Dan Sunday
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// There is no warranty for this code, and the author of it cannot
// be held liable for any real or imagined damage from its use.
// Users of this code must verify correctness for their application.

If you want to see the original C++ source, it’s in the file C05_Line_Plane_Intersection.cpp.

Here's the ported Lua code, ready to plop into any roblox game:
--[[
// Copyright 2001, 2012, 2021 Dan Sunday
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// There is no warranty for this code, and the author of it cannot
// be held liable for any real or imagined damage from its use.
// Users of this code must verify correctness for their application.
]]
-- intersect3D_SegmentPlane(): find the 3D intersection of a segment and a plane
--  Input:  
--      segment = a segment = {Vector3 P1, Vector3 P2}, and 
--      plane = a plane = {Vector3 P, Vector N}
--  Output: *I0 = the intersect point (when it exists)
--  Return: 
--      nil,           0 = disjoint (no intersection)
--      Vector3 point, 1 = intersection in the unique point point
--      nil,		   2 = the segment lies in the plane (counted as no intersectio)
local SMALL_NUM = 10e-5
function intersect3D_SegmentPlane(segment, plane)
	local u = segment.P2 - segment.P1
	local w = segment.P1 - plane.P

	local D = plane.N:Dot(u)
	local N = -plane.N:Dot(w)

	if math.abs(D) < SMALL_NUM then     -- segment is parallel to plane
		if N == 0 then                  -- segment lies in plane
			return nil, 2
		else                            -- no intersection
			return nil, 0 
		end
	end

	-- they are not parallel
	-- compute intersect param
	local sI = N/D
	if sI < 0 or sI > 1 then -- no intersection
		return nil, 0
	end

	local intersection = segment.P1 + sI * u -- compute segment intersect point
	return intersection, 1
end

And here’s a test place showing how it can be used to get the intersection of the mouse ray with an any plane, in this case defined by a part.

RayPlaneIntersectTest.rbxl (28.9 KB)

And here's the code for the usage example
function getMouseRaySegment()
	return {
		P1 = mouse.UnitRay.Origin,
		P2 = mouse.UnitRay.Origin + mouse.UnitRay.Direction * 1000
	}
end

function getPartFrontPlane(part)
	return { -- A plane, represented as a point P in the plane and the normal N of the plane
		P = part.CFrame:PointToWorldSpace(Vector3.new(0, 0, -part.Size.Z/2)),
		N = part.CFrame.LookVector
	}
end

while wait() do
	local s = getMouseRaySegment()
	local p = getPartFrontPlane(game.Workspace.Plane)
	local i, err = intersect3D_SegmentPlane(s, p)
	if i then
		game.Workspace.Cursor.CFrame = CFrame.new() + i
	else
		print(err) --either s is in the plane so there is no UNIQUE intersect, or they don't interesect at all
	end
end

Let me know if you need help adapting it to your specific situation

I’ve almost got it working, newcode.wmv (271.0 KB) , my only issue now, as you can see in the video, is that it’s not preserving the parts original Z position. Sorry for asking so many questions, but how would I make it so that the Z position of the part never changes?

You’d have to place the plane at the original Z position

1 Like