How would I go about making a dragging system that works for mobile aswell.
My aim is something that is smooth not jagged.
How would I go about making a dragging system that works for mobile aswell.
My aim is something that is smooth not jagged.
Check this out:
Already gave this a try a while ago, they dont work as intended.
You can hold the part and move it etc, but when you move your character away or towards the block doesnât move.
Example from another devforum post
If you want it to feel like the object is being held in 3D space you will need to make the script yourself. 3D drag detectors are kinda limited nowadays. Try this script:
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local dragging = false
local draggedPart = nil
local distance = 10 -- how far from camera to hold the object
-- Raycast to pick up the part
mouse.Button1Down:Connect(function()
local result = mouse.Target
if result and result:IsA("BasePart") then
dragging = true
draggedPart = result
distance = (camera.CFrame.Position - result.Position).Magnitude
end
end)
-- Release when mouse lifted
mouse.Button1Up:Connect(function()
dragging = false
draggedPart = nil
end)
-- Update dragged part position
RunService.RenderStepped:Connect(function()
if dragging and draggedPart then
local unitRay = camera:ScreenPointToRay(mouse.X, mouse.Y)
local targetPosition = unitRay.Origin + unitRay.Direction * distance
-- Optional: Tween or smooth this movement
draggedPart.CFrame = CFrame.new(targetPosition)
end
end)
Iâll give this a go soon, would this also work for mobile?
At the moment Iâve got this
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local InputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Modules = ReplicatedStorage.Modules
local Packages = ReplicatedStorage.Packages
local Mouse = require(Packages.Mouse)
local JanitorModule = require(Packages.Janitor)
local BlockController = require(script.Parent.BlockController)
local DragController = {
isDragging = false :: RBXScriptConnection
}
function DragController:stopDragging()
if not self.isDragging then return end
self.isDragging:Disconnect()
end
function DragController:startDragging(part: BasePart)
self.isDragging = RunService.Heartbeat:Connect(function()
part.Position = Mouse.Hit.Position
end)
end
function DragController:Init()
end
function DragController:Start()
InputService.InputBegan:Connect(function(input: InputObject, GPE: boolean)
if GPE then return end
if input.UserInputType == Enum.UserInputType.Touch then
-- mobile
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
-- computa
end
end)
InputService.InputEnded:Connect(function(input: InputObject)
end)
end
return DragController
Well, no.
But with a few tweaks it may work:
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local dragging = false
local draggedPart = nil
local holdDistance = 10
local touchPosition = Vector2.new()
UIS.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseMovement then
touchPosition = input.Position
end
end)
UIS.InputBegan:Connect(function(input, processed)
if processed then return end
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
touchPosition = input.Position
local ray = camera:ScreenPointToRay(touchPosition.X, touchPosition.Y)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {player.Character}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
local result = workspace:Raycast(ray.Origin, ray.Direction * 100, raycastParams)
if result and result.Instance and result.Instance:IsA("BasePart") then
dragging = true
draggedPart = result.Instance
holdDistance = (camera.CFrame.Position - result.Position).Magnitude
end
end
end)
UIS.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
dragging = false
draggedPart = nil
end
end)
RunService.RenderStepped:Connect(function()
if dragging and draggedPart then
local ray = camera:ScreenPointToRay(touchPosition.X, touchPosition.Y)
local targetPos = ray.Origin + ray.Direction * holdDistance
draggedPart.CFrame = CFrame.new(targetPos)
end
end)
Try this one, I changed it so it may work now for both mobile and PC (and maybe console)
I found this script inside a place I made 2 years ago btw. But it still works since Roblox still uses mouse
Let me know if it worked
This works as intended but how would i make it so it isnt with the camera constantly, rather capped around holddistance
The issue with using the camera ray directly is that the dragged part will always try to follow the exact direction of the camera, which can make it âfloatâ too farwhen the player moves
Instead of locking the part to the ray, what you can do is define a âhold distanceâ (like 10 studs) in front of the character, raycast from the screen like normal, but instead of moving the part exactly to where the ray hits.
That way, it doesnât glitch when the player walks around.
It still lets you move and drag the part with touch or mouse, but the part doesnât fly off or stick too close to the camera. It also works on mobile without needing to manually position attachments or welds.
Hereâs the updated script:
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local character = player.Character or player.CharacterAdded:Wait()
local rootPart = character:WaitForChild("HumanoidRootPart")
local dragging = false
local draggedPart = nil
local maxDistance = 10
local touchPosition = Vector2.zero
UIS.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseMovement then
touchPosition = input.Position
end
end)
UIS.InputBegan:Connect(function(input, processed)
if processed then return end
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
touchPosition = input.Position
local ray = camera:ScreenPointToRay(touchPosition.X, touchPosition.Y)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
local result = workspace:Raycast(ray.Origin, ray.Direction * 100, raycastParams)
if result and result.Instance and result.Instance:IsA("BasePart") then
local partPos = result.Instance.Position
local distance = (rootPart.Position - partPos).Magnitude
if distance <= maxDistance then
dragging = true
draggedPart = result.Instance
end
end
end
end)
UIS.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
dragging = false
draggedPart = nil
end
end)
RunService.RenderStepped:Connect(function()
if dragging and draggedPart then
local ray = camera:ScreenPointToRay(touchPosition.X, touchPosition.Y)
local target = ray.Origin + ray.Direction * maxDistance
local origin = rootPart.Position + rootPart.CFrame.LookVector * maxDistance
local clampedPos = origin:Lerp(target, 0.5)
draggedPart.CFrame = CFrame.new(clampedPos)
end
end)
Let me know if this works. Sorry for the long explanation, I just wanted you to understand
It slightly works but it still moves with the camera, also doesnât follow the mouse fully anymore, rather slightly drifts towards it and stops
Can you show me a video showcasing this? So I can update the script âmore clearlyâ
Yep, I think I already saw the problem.
First of all, make sure itâs on a seperated script [ignore this if youâre sure that itâs correctly placed (atleast the source)]
If you put the source inside a script already made before, tell me if itâs Server script or Local, because the script I gave you is only for Local.
Second of all, make sure the script is placed inside a tool.
Hereâs the script
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local runService = game:GetService("RunService")
local uis = game:GetService("UserInputService")
local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")
local dragging = false
local draggedPart = nil
local maxDistance = 15
local holdOffset = Vector3.new(0, 0, -8) -- Position to hold object in front of player
-- Get a point in front of the character (ignores camera angle)
local function getHoldPosition()
return root.Position + root.CFrame:VectorToWorldSpace(holdOffset)
end
-- Try to find a draggable part
local function getDraggablePart()
local ray = Ray.new(camera.CFrame.Position, (mouse.Hit.p - camera.CFrame.Position).Unit * maxDistance)
local part = workspace:FindPartOnRay(ray, character)
return part
end
-- Start dragging
local function beginDrag(part)
dragging = true
draggedPart = part
if draggedPart:IsA("BasePart") then
draggedPart:SetNetworkOwner(player)
end
end
-- Stop dragging
local function endDrag()
dragging = false
draggedPart = nil
end
-- Input handling
mouse.Button1Down:Connect(function()
local part = getDraggablePart()
if part then
beginDrag(part)
end
end)
mouse.Button1Up:Connect(endDrag)
uis.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch then
endDrag()
end
end)
-- Update loop
runService.RenderStepped:Connect(function()
if dragging and draggedPart then
local desiredPosition = getHoldPosition()
local direction = (mouse.Hit.p - desiredPosition)
local targetPosition = desiredPosition + direction.Unit * math.min(direction.Magnitude, maxDistance)
-- Smoothly move the part
draggedPart.Velocity = (targetPosition - draggedPart.Position) * 10
end
end)
Again⌠Let me know if itâs better now
I think the problem was that the part was influenced by the camera, and the drift happens because the part is trying to lerp or tween towards a target thatâs moving around too âfastâ
Would this be a server script, as for the SetNetworkOwner
LocalScript, client sets owner
Server has to set an owner, but local is already LocalPlayer
You can also send the whole script so I can make some changes so it fits better.
But is your script local or server?
Ive been using a localscript inside of StarterPlayerScripts
Ok, perfect!
It could be inside a Tool or inside StarterPlayerScripts. Both work. I forgot to mention that too.
Well, but did the last script I gave you work?
It didnât it seemed to just not function at all, also get a âClient canât set network ownership errorâ
My bad.
Remove that line, It should work Mixed up Server with Local. Sorry
Doesnât work
Local Script inside of StarterPlayerScript
This time it doesnt drag at all
Try to put the script inside the tool.
And make sure the part is unachored