Hello, this script I’m studying for dragging objects, for some reason causes the objects to freeze in place when thrown. I want it to travel smoothly when I release my mouse after dragging.
I thought it was the passing of network ownership to the server that made it lag, but I tried adding a delay that changes the owner after some time after the initial throw; it was still freezing in place.
My suspicions lie on the destruction of the AlignPosition and AlignOrientation attachments, but I’m not sure..
Here is the code:
Serverscript
local playerService = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local collectionService = game:GetService("CollectionService")
local config = {
max_drag_distance = 30,
draggable_tag = "Draggable"
}
local requestDragRemote = replicatedStorage.Remotes:WaitForChild("RequestDrag")
local playerDragState = {}
--helper function
local function getPhysicsPart(object)
if not object then return nil end
return object:isA("Model") and object.PrimaryPart or object
end
--main function
--this is where the STOPDRAG or STARTDRAG goes
local function onRequestDrag(player, targetObject)
if not targetObject then
local currentlyDraggedObject = playerDragState[player]
if currentlyDraggedObject then
local physicsPartToRelease = getPhysicsPart(currentlyDraggedObject)
if physicsPartToRelease then
physicsPartToRelease:SetNetworkOwner(nil)
print("server is now the owner")
end
playerDragState[player] = nil
end
return false
end
if not collectionService:HasTag(targetObject, config.draggable_tag) then
warn (player.Name .. " tried to drag an object without the " .. config.draggable_tag .. " tag.")
return false
end
local physicsPart = getPhysicsPart(targetObject)
if not physicsPart then
warn(player.Name .. " tried to drag an object without a valid physics part.")
return false
end
local character = player.Character
local humanoidRootPart = character and character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then
return false
end
for _, draggedObject in pairs(playerDragState) do
if draggedObject == targetObject then
return false
end
end
local distance = (humanoidRootPart.Position - physicsPart.Position).Magnitude
if distance > config.max_drag_distance then
warn(player.Name .. " tried to drag an object from too far away.")
return false
end
physicsPart:SetNetworkOwner(player)
print("player is now the owner")
playerDragState[player] = targetObject
return true
end
local function onPlayerRemoving(player)
if playerDragState[player] then
local draggedObject = playerDragState[player]
local physicsPartToRelease = getPhysicsPart(draggedObject)
if physicsPartToRelease then
physicsPartToRelease:SetNetworkOwner(nil)
end
playerDragState[player] = nil
end
end
requestDragRemote.OnServerInvoke = onRequestDrag
playerService.PlayerRemoving:Connect(onPlayerRemoving)
Local Script
local userInputService = game:GetService("UserInputService")
local runService = game:GetService("RunService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local playerService = game:GetService("Players")
local collectionService = game:GetService("CollectionService")
local config = {
draggable_tag = "Draggable",
max_interaction_distance = 10
}
local localPlayer = playerService.LocalPlayer
local camera = workspace.CurrentCamera
local requestDragRemote = replicatedStorage.Remotes:WaitForChild("RequestDrag")
local isDragging = false
local draggedObject = nil
local dragConnection = nil
local grabDepth = 0
local grabOffset = CFrame.new()
local currentHoverTarget = nil
local currentHighlight = nil
local currentNameGui = nil
local objectAttachment = nil
local targetAttachment = nil
local alignPosition = nil
local alighnOrientation = nil
local anchored = false
local function getPhysicsPart(object)
if not object then return nil end
return object:isA("Model") and object.PrimaryPart or object
end
local function getMouseTarget()
local mousePosition = userInputService:GetMouseLocation()
local mouseRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y)
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Include
raycastParams.FilterDescendantsInstances = collectionService:GetTagged(config.draggable_tag)
local raycastResult = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 200, raycastParams)
if raycastResult then
local instance = raycastResult.Instance
--while loop finds all the ancestors of the raycast result until
--it finds a part with the draggable tag
while instance and not collectionService:HasTag(instance, config.draggable_tag) do
instance = instance.Parent
end
return instance, raycastResult.Position
end
return nil, nil
end
local function updateDrag()
if not isDragging or not targetAttachment then return end
local mousePosition = userInputService:GetMouseLocation()
local unitRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y)
local worldPointCFrame = CFrame.new(unitRay.Origin + unitRay.Direction * grabDepth)
local finalCFrame = worldPointCFrame * grabOffset:Inverse()
targetAttachment.WorldCFrame = finalCFrame
end
local function stopDrag()
if not isDragging then return end
if dragConnection then
dragConnection:Disconnect()
dragConnection = nil
end
if objectAttachment then objectAttachment:Destroy() end
if targetAttachment then targetAttachment:Destroy() end
objectAttachment,targetAttachment,alignPosition,alighnOrientation = nil,nil,nil,nil
isDragging = false
grabDepth = 0
grabOffset = CFrame.new()
requestDragRemote:InvokeServer(nil)
draggedObject = nil
end
local function startDrag(target, hitPosition)
if isDragging then return end
local physicsPart = getPhysicsPart(target)
if not physicsPart then return end
local canDrag = requestDragRemote:InvokeServer(target)
if not canDrag then return end
isDragging = true
draggedObject = target
grabDepth = (camera.CFrame.Position - hitPosition).Magnitude
grabOffset = physicsPart.CFrame:ToObjectSpace(CFrame.new(hitPosition))
objectAttachment = Instance.new("Attachment", physicsPart)
targetAttachment = Instance.new("Attachment", workspace.Terrain)
physicsPart.Anchored = anchored
alignPosition = Instance.new("AlignPosition", targetAttachment)
alignPosition.Responsiveness = 100
alignPosition.MaxForce = 100000
alignPosition.Attachment0 = objectAttachment
alignPosition.Attachment1 = targetAttachment
alighnOrientation = Instance.new("AlignOrientation", targetAttachment)
alighnOrientation.Responsiveness = 100
alighnOrientation.MaxTorque = 100000
alighnOrientation.Attachment0 = objectAttachment
alighnOrientation.Attachment1 = targetAttachment
--updateDrag()
dragConnection = runService.Heartbeat:Connect(updateDrag)
end
local function updateHoverEffect()
local character = localPlayer.Character
local rootPart = character and character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
local target, _ = getMouseTarget()
local physicsPart = getPhysicsPart(target)
if physicsPart and (rootPart.Position - physicsPart.Position).Magnitude > config.max_interaction_distance then
target = nil
end
if target ~= currentHoverTarget then
if currentHighlight then currentHighlight:Destroy() end
if currentNameGui then currentNameGui:Destroy() end
currentHighlight, currentNameGui, currentHoverTarget = nil,nil,nil
if target then
currentHoverTarget = target
currentHighlight = Instance.new("Highlight")
currentHighlight.FillColor = Color3.fromRGB(255,255,255)
currentHighlight.FillTransparency = 0.7
currentHighlight.OutlineTransparency = 0.2
currentHighlight.OutlineColor = Color3.fromRGB(255,255,255)
currentHighlight.Parent = target
local nameGui = Instance.new("BillboardGui")
nameGui.Name = "ItemNameGui"
nameGui.Adornee = physicsPart
nameGui.Size = UDim2.new(4, 0, 1, 0)
nameGui.StudsOffset = Vector3.new(0, 2.5, 0)
nameGui.Parent = physicsPart
local textLabel = Instance.new("TextLabel")
textLabel.BackgroundTransparency = 1
textLabel.Size = UDim2.new(1,0,1,0)
textLabel.Font = Enum.Font.SourceSansBold
textLabel.Text = target.Name
textLabel.TextColor3 = Color3.fromRGB(255,255,255)
textLabel.TextScaled = true
textLabel.Parent = nameGui
currentNameGui = nameGui
end
end
end
runService.Heartbeat:Connect(function()
if not isDragging then
updateHoverEffect()
end
end)
userInputService.InputBegan:Connect(function(input, gameProcessedEvent)
if gameProcessedEvent then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
local target, hitPosition = getMouseTarget()
if target and hitPosition then
local character = localPlayer.Character
local rootPart = character and character:FindFirstChild("HumanoidRootPart")
local physicsPart = getPhysicsPart(target)
if rootPart and physicsPart and (rootPart.Position - physicsPart.Position).Magnitude <= config.max_interaction_distance then
startDrag(target, hitPosition)
end
end
end
end)
userInputService.InputEnded:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
stopDrag()
end
end)