Hi, I’ve got a drag/carry script which seems to be not working as expected for instance, on tablets/mobiles you can just lift the part but not walk anywhere, on the desktop you can walk and carry but theres not enough force to lift it fully as you need.
Could you help me with making the scripts work please.
--grabrequest in ServerScriptStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local GrabRequest = Instance.new("RemoteEvent")
GrabRequest.Name = "GrabRequest"
GrabRequest.Parent = ReplicatedStorage
local function GrabRequested(player, target)
local character = player.Character
if character then
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
local offset = Vector3.new(0, 0, 5) -- Adjust the offset as needed
target.CFrame = CFrame.new(humanoidRootPart.Position + offset)
end
end
end
GrabRequest.OnServerEvent:Connect(GrabRequested)
-- ServerScriptService > Scripts > Draghandler
--draghandler
-- dependencies:
local replicatedStorage = game:GetService("ReplicatedStorage")
local serverScriptService = game:GetService("ServerScriptService")
local dragController = require(serverScriptService.Modules.DragController)
-- paths:
local network = replicatedStorage.Network
local requestDrag = network.RequestDrag
local dragCancelled = network.DragCancelled
-- main:
function requestDrag.OnServerInvoke(player, part)
if not dragController.CanDrag(player, part) then return false end
dragController.Drag(player, part)
return true
end
dragCancelled.OnServerEvent:Connect(function(player)
-- TODO
end)
-- ServerScriptService > Modules (folder) > DragController (module script)
--dragcontroller script
-- dependencies:
local players = game:GetService("Players")
local collectionService = game:GetService("CollectionService")
-- data:
local playerToDragData = {}
-- DragController:
local module = {}
function module.Drag(player, part)
assert(typeof(player) == "Instance" and player:IsA("Player"), "bad argument #1 to DragController.Drag, expects Instance<Player>")
assert(module.CanDrag(player, part), "bad argument #2 to DragController.Drag, expects part that can be dragged")
part:SetNetworkOwner(player)
end
function module.CanDrag(player, part)
assert(typeof(player) == "Instance" and player:IsA("Player"), "bad argument #1 to DragController.CanDrag, expects Instance<Player>")
if module.IsDragging(player) then return false end
if typeof(part) ~= "Instance" then return false end
if not part:FindFirstChild("Configuration") then return false end -- Check if part has a Configuration child
local owner = part.Owner.Value
if owner ~= 0 and owner ~= player.UserId then return false end -- TODO: add player whitelist checks
return true
end
function module.IsDragging(player)
assert(typeof(player) == "Instance" and player:IsA("Player"), "bad argument #1 to DragController.IsDragging, expects Instance<Player>")
local dragData = playerToDragData[player]
if dragData == nil then return end
return dragData.IsDragging
end
-- main:
players.PlayerAdded:Connect(function(player)
playerToDragData[player] = {
IsDragging = false,
}
end)
players.PlayerRemoving:Connect(function(player)
playerToDragData[player] = nil
end)
return module
-- Dragger script in StarterPlayerScripts > Dragger
-- Dependencies:
local replicatedStorage = game:GetService("ReplicatedStorage")
local contextActionService = game:GetService("ContextActionService")
local runService = game:GetService("RunService")
local players = game:GetService("Players")
local userInputService = game:GetService("UserInputService")
local clientModules = replicatedStorage.Modules.Client
local dragController = require(clientModules.DragController)
local inputTypeDetector = require(clientModules.InputTypeDetector)
local localPlayer = players.LocalPlayer
local control
local baseCamera
coroutine.wrap(function()
local playerModule = localPlayer.PlayerScripts:WaitForChild("PlayerModule")
control = require(playerModule):GetControls()
baseCamera = require(playerModule:WaitForChild("CameraModule"):WaitForChild("BaseCamera"))
end)()
-- Paths:
local network = replicatedStorage.Network
local requestDrag = network.RequestDrag
local dragCancelled = network.DragCancelled
-- Data:
local inputTypes = inputTypeDetector.InputTypes
local target
local hit
-- Configuration:
local MAX_GRAB_DISTANCE = 10
-- Main:
contextActionService:BindAction("Drag", function(name, state, input)
if state == Enum.UserInputState.Begin then
if dragController.IsDragging then return Enum.ContextActionResult.Pass end
-- Get head
local character = localPlayer.Character
if character == nil then return Enum.ContextActionResult.Pass end
local head = character:FindFirstChild("Head")
if head == nil then return Enum.ContextActionResult.Pass end
-- Get target
local inputType = inputTypeDetector.GetInputType()
if inputType == inputTypes.KeyboardAndMouse or inputType == inputTypes.Gamepad then
if target == nil or hit == nil then return Enum.ContextActionResult.Pass end
elseif inputType == inputTypes.Touch then
if input.UserInputType ~= Enum.UserInputType.Touch then return Enum.ContextActionResult.Pass end
local inputPosition = input.Position
local screenPointRay = workspace.CurrentCamera:ScreenPointToRay(inputPosition.X, inputPosition.Y)
local extendedRay = Ray.new(screenPointRay.Origin, screenPointRay.Direction * 1000)
target, hit = workspace:FindPartOnRay(extendedRay, localPlayer.Character, false, true)
end
-- Check if can drag
if not dragController.CanDrag(target) then return Enum.ContextActionResult.Pass end
if (head.Position - hit).Magnitude > MAX_GRAB_DISTANCE then return Enum.ContextActionResult.Pass end
-- Prepare if touch
if inputType == inputTypes.Touch then
control:Disable()
end
-- Drag
dragController.Drag(target, hit)
-- Register drag on server
local wasCancelled = false
local connection
connection = dragController.DragCancelled:Connect(function()
connection:Disconnect()
wasCancelled = true
if inputType ~= inputTypes.Touch then return end
control:Enable()
end)
local isSuccessful = requestDrag:InvokeServer(target)
if wasCancelled or isSuccessful then return end
dragController.CancelDrag()
else
if state == Enum.UserInputState.End then
dragController.CancelDrag()
end
return Enum.ContextActionResult.Pass
end
end, false, Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch, Enum.KeyCode.ButtonR2)
while true do
local inputType = inputTypeDetector.GetInputType()
if inputType == inputTypes.KeyboardAndMouse or inputType == inputTypes.Gamepad then
local location = userInputService:GetMouseLocation()
local viewportPointRay = workspace.CurrentCamera:ViewportPointToRay(location.X, location.Y)
local extendedRay = Ray.new(viewportPointRay.Origin, viewportPointRay.Direction * 1000)
target, hit = workspace:FindPartOnRay(extendedRay, localPlayer.Character, false, true)
end
runService.Heartbeat:Wait()
end
-- Client-Side Script: ControlHandler
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local placementEvent = ReplicatedStorage:WaitForChild("PlacementEvent")
local selectedBlock = nil -- This should be set by the PlacementGuiScript or some similar mechanism
-- Flags
local isMobile = UserInputService.TouchEnabled
-- Movement and Rotation variables
local moveStep = 0.1
local rotateStep = 10
local touchInitialPosition = nil -- To store the initial touch position
-- Dummy function to get the player's plot (replace with your actual function)
local function getPlayersPlot(player)
return workspace:FindFirstChild(player.Name .. "_Plot")
end
-- Keyboard Controls
local function handleKeyboard(input)
if not selectedBlock then return end -- Make sure there's a block selected
if input.KeyCode == Enum.KeyCode.Space then
placementEvent:FireServer(selectedBlock)
selectedBlock = nil
else
-- The block follows the player's movement
local playerPosition = player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character.HumanoidRootPart.Position or Vector3.new()
selectedBlock.Position = playerPosition + Vector3.new(0, 5, 0) -- Offset by 5 studs above the player
end
end
-- Touch Controls
local function handleTouchTap()
if selectedBlock then
placementEvent:FireServer(selectedBlock)
selectedBlock = nil
end
end
local function handlePlayerMovement()
if not selectedBlock then return end -- Make sure there's a block selected
-- The block follows the player's movement
local playerPosition = player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character.HumanoidRootPart.Position or Vector3.new()
selectedBlock.Position = playerPosition + Vector3.new(0, 5, 0) -- Offset by 5 studs above the player
end
-- Main Input Handling
local function handleInput(input, gameProcessed)
if gameProcessed then
return
end
if isMobile then
-- Touch controls are handled in their own functions
else
handleKeyboard(input)
end
end
-- Setup
UserInputService.InputBegan:Connect(handleInput)
UserInputService.TouchTap:Connect(handleTouchTap)
-- Make the selected block follow the player
game:GetService("RunService").Heartbeat:Connect(handlePlayerMovement)
-- dependencies:
local userInputService = game:GetService("UserInputService")
-- enums
local inputTypes = {
KeyboardAndMouse = 1,
Gamepad = 2,
Touch = 3,
}
-- data:
local inputTypeToEnumMap = {
[Enum.UserInputType.MouseButton1] = inputTypes.KeyboardAndMouse,
[Enum.UserInputType.MouseButton2] = inputTypes.KeyboardAndMouse,
[Enum.UserInputType.MouseButton3] = inputTypes.KeyboardAndMouse,
[Enum.UserInputType.MouseWheel] = inputTypes.KeyboardAndMouse,
[Enum.UserInputType.MouseMovement] = inputTypes.KeyboardAndMouse,
[Enum.UserInputType.Keyboard] = inputTypes.KeyboardAndMouse,
[Enum.UserInputType.Touch] = inputTypes.Touch,
[Enum.UserInputType.Gamepad1] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad2] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad3] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad4] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad5] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad6] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad7] = inputTypes.Gamepad,
[Enum.UserInputType.Gamepad8] = inputTypes.Gamepad,
}
local inputType = inputTypeToEnumMap[userInputService:GetLastInputType()] or inputTypes.KeyboardAndMouse
local inputTypeChangedBindable = Instance.new("BindableEvent")
-- ClientUtil:
local module = {}
function module.GetInputType()
return inputType
end
module.InputTypeChanged = inputTypeChangedBindable.Event
module.InputTypes = inputTypes
-- main:
userInputService.LastInputTypeChanged:Connect(function(newInputType)
local enum = inputTypeToEnumMap[newInputType]
if enum == nil then return end
if enum == inputType then return end
inputType = enum
inputTypeChangedBindable:Fire(inputType)
end)
return module
-- dependencies:
local runService = game:GetService("RunService")
local collectionService = game:GetService("CollectionService")
local userInputService = game:GetService("UserInputService")
local players = game:GetService("Players")
local localPlayer = players.LocalPlayer
local playerScripts = localPlayer.PlayerScripts
local baseCamera
coroutine.wrap(function()
baseCamera = require(playerScripts:WaitForChild("PlayerModule"):WaitForChild("CameraModule"):WaitForChild("BaseCamera"))
end)()
-- paths:
local holdTarget = script.HoldTarget
local holdPositionAlignment = script.HoldPositionAlignment
local logic = workspace.Logic
-- data:
local holdGrip = Instance.new("Attachment")
local dragCancelledBindable = Instance.new("BindableEvent")
local draggedBindable = Instance.new("BindableEvent")
local currentHoldGrip
local heldPart
-- configuration:
local DRAG_DISTANCE = 10
-- DragController:
local module = {}
function module.CancelDrag()
if not module.IsDragging then return end
currentHoldGrip:Destroy()
currentHoldGrip = nil
holdPositionAlignment.Attachment0 = nil
heldPart = nil
module.IsDragging = false
dragCancelledBindable:Fire()
end
function module.Drag(part, position)
assert(module.CanDrag(part), "bad argument #1 to DragController.Drag, expects part that can be dragged")
assert(typeof(position) == "Vector3" or position == nil, "bad argument #2 to DragController.Drag, expects Vector3?")
if position == nil then
position = Vector3.new()
end
local cFrame = CFrame.new(position)
module.IsDragging = true
heldPart = part
currentHoldGrip = holdGrip:Clone()
currentHoldGrip.Position = part.CFrame:ToObjectSpace(cFrame).Position
currentHoldGrip.Parent = heldPart
holdPositionAlignment.Attachment0 = currentHoldGrip
holdTarget.CFrame = cFrame
draggedBindable:Fire(part, position)
end
function module.CanDrag(part)
if module.IsDragging then return false end
if typeof(part) ~= "Instance" then return false end
if not collectionService:HasTag(part, "Draggable") then return false end
local owner = part.Owner.Value
if owner ~= 0 and owner ~= localPlayer.UserId then return false end -- TODO: add player whitelist checks
return true
end
module.IsDragging = false
module.Dragged = draggedBindable.Event
module.DragCancelled = dragCancelledBindable.Event
-- main:
holdGrip.Visible = true
holdPositionAlignment.Parent = logic
holdTarget.Parent = logic
local function merge(a1, a2)
for _, v2 in ipairs(a2) do
table.insert(a1, v2)
end
return a1
end
coroutine.wrap(function()
while true do
if module.IsDragging and baseCamera ~= nil then
-- get necessary data
local subjectPosition = baseCamera:GetSubjectPosition()
if subjectPosition == nil then return end
-- get hit
local location = userInputService:GetMouseLocation()
local viewportPointRay = workspace.CurrentCamera:ViewportPointToRay(location.X, location.Y)
local rayOrigin = viewportPointRay.Origin
local mousePosition = CFrame.new(rayOrigin, rayOrigin + viewportPointRay.Direction):ToWorldSpace(CFrame.new(0, 0, -1000)).Position
local targetPosition = CFrame.new(subjectPosition, mousePosition):ToWorldSpace(CFrame.new(0, 0, -DRAG_DISTANCE)).Position
holdTarget.CFrame = CFrame.new(targetPosition)
end
runService.Heartbeat:Wait()
end
end)()
return module