Part dragging issues

Hello everyone,

Not sure how to explain this issue, but here goes.

So I’ve been experimenting with Drag Detectors recently, and they’re a great addition in my opinion! There’s just one problem - they only work in Studio as the devs work out any bugs they still have before release. Therefore, I’ve been trying to find an alternative to Drag Detectors, and I found this post by lilsquish08. All credits go to them.

Local Script, in StarterPlayerScripts

local UserInputService = game:GetService("UserInputService")

local TAG_NAME = "Grabbable"

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

local character = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")

local requestGrab = game.ReplicatedStorage.RequestGrab
local stopGrab = game.ReplicatedStorage.StopGrab

local trackingPart = nil
local heartbeat

local grabDistance = 100

function UpdateTrackingPart ()
	local position = head.Position + (mouse.Hit.Position - head.Position).Unit * 6

	trackingPart.BodyPosition.Position = position
end

function MouseDown ()
	local target = mouse.Target

	if target then
		local distanceFromTarget = (humanoidRootPart.Position - target.Position).Magnitude

		if distanceFromTarget < grabDistance then
			if target and requestGrab:InvokeServer(target) then
				trackingPart = target
				heartbeat = game:GetService("RunService").Heartbeat:Connect(UpdateTrackingPart)

				print("Player started grabbing")
			end
		end
	end
end

function MouseUp ()
	if not trackingPart then return end
	stopGrab:FireServer(trackingPart)
	trackingPart = nil
	heartbeat:Disconnect()

	print("Player stopped grabbing")
end

function CharacterAdded (character)
	mouse.TargetFilter = character
end

UserInputService.InputBegan:Connect(function(inputObject, processed)
	if processed then return end
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		MouseDown()
	end
end)

UserInputService.InputEnded:Connect(function(inputObject, processed)
	if processed then return end
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		MouseUp()
	end
end)

CharacterAdded(player.Character or player.CharacterAdded:Wait())
player.CharacterAdded:Connect(CharacterAdded)

Server Script, in ServerScriptService

local TAG_NAME = "Grabbable"

local collectionService = game:GetService("CollectionService")
local parts = collectionService:GetTagged(TAG_NAME)

local playerParts = {}

function RequestGrab (player, part)
	if playerParts[player] then return false end

	if  not collectionService:HasTag(part, TAG_NAME) then
		return false
	end

	local bp = Instance.new("BodyPosition")
	local bg = Instance.new("BodyGyro")

	bp.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
	bp.D = 900
	bp.Position = part.Position
	bp.Parent = part

	bg.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
	bg.CFrame = part.CFrame
	bg.Parent = part

	part:SetNetworkOwner(player)
	playerParts[player] = part
	return true
end

function StopGrab (player, part)
	if playerParts[player] ~= part then return false end

	part.BodyPosition:Destroy()
	part.BodyGyro:Destroy()

	playerParts[player] = nil
end

game.ReplicatedStorage.RequestGrab.OnServerInvoke = RequestGrab
game.ReplicatedStorage.StopGrab.OnServerEvent:Connect(StopGrab)

game.Players.PlayerRemoving:Connect(function(player)
	if playerParts[player] then
		StopGrab(player, playerParts[player])
	end
end)

There is a RemoteFunction “RequestGrab” and a RemoteEvent “StopGrab” in ReplicatedStorage if you are looking to recreate this.

The issues that I’m having with this: one, the model is able to go in the air. I need movement to be clamped along the XZ plane. Is there any way to do this?

Secondly, I also want the model to be able to turn. The optimal solution, in my opinion, is to apply the force at the location of the part instead of at the model’s center of mass, like on Drag Detectors when you have ApplyAtCenterOfMass unchecked. This also works if the player can rotate the model with a key.

If anyone has any knowledge on either problem, any help is appreciated. Thanks in advance!