This script does not work I have a screen gui and module script and it does not work. Should I also Put in a regular script or local script?
local DraggableObject = require(game.StarterGui.ScreenGui.DraggableObject)
local FrameDrag = DraggableObject.new(game.StarterGui.ScreenGui.Frame)
FrameDrag:Enable()
I posted Draggable GUI That Can't Go Off-Screen yesterday, and I was wondering if this might be the answer to it. Can this GUI go off-screen or does it stop once it hits the side/top/bottom of the screen?
Thank you for making this module, I’ve been using it in my game and it works well.
Except I just noticed today something disturbing with it while I was working on a custom inventory system: If you are playing a touchscreen enabled device and start touching somewhere in your screen, then hovering to the gui object, it will start dragging it, although I started touching outside of the object. It doesn’t happen with a mouse though. Here is maybe a video so you understand better:
Will you fix that or should I maybe just try to fix it myself ?
You can do that by saving the offset of the yellow to the red gui, and then whenever the red gui moves you update the yellow gui to be the red gui’s new position plus its initial offset.
Example
-- Calculate yellow and red gui's offsets from each other
local yellowOffset = yellowGui.Position - redGui.Position
local redOffset = redGui.Position - yellowGui.Position
-- Create draggable objects
local yellowDrag = DraggableObject.new(yellowGui)
local redDrag = DraggableObject.new(redGui)
-- Whenever the yellow gui is dragged, update the red gui's position
yellowDrag.Dragged = function(yellowPos)
redGui.Position = yellowPos + redOffset
end
-- Whenever the red gui is dragged, update the yellow gui's position
redDrag.Dragged = function(redPos)
yellowGui.Position = redPos + yellowOffset
end
yellowDrag:Enable() -- Enable dragging of yellow gui
redDrag:Enable() -- Enable dragging of red gui
Alright I fixed that problem by listening the InputBegan event of UserInputService instead of the object’s event and making sure the touch started inside the object: DraggableObject.lua (3.3 KB)
I got two errors:
Players.GEILER123456.PlayerScripts.Client.DragModule:40: invalid argument #2 (Vector3 expected, got nil)
and
Players.GEILER123456.PlayerScripts.Client.DragModule:42: attempt to index nil with ‘X’
Maybe my code is wrong, here it is:
local pressing = false
local pressedFor = 0
local button1Down
local button1Up
local cloneDrag = DragModule.new(clone)
button1Down = clone.MouseButton1Down:Connect(function()
pressing = true
while pressing do
pressedFor += RunService.Heartbeat:Wait()
if pressedFor > 1 then
cloneDrag:Enable()
break
end
end
end)
button1Up = clone.MouseButton1Up:Connect(function()
pressing = false
if pressedFor < 1 then
print("Client fire drop!")
freeSlot.Item = nil
dropRemote:FireServer(name)
clone:Destroy()
button1Down:Disconnect()
button1Up:Disconnect()
else
print("It was just for positioning")
cloneDrag:Disable()
end
pressedFor = 0
end)
I attempted to fix it myself:
Changed local startPos = nil to local startPos = object.Position,
Changed local dragStart = nil to local dragStart = Vector3.new(0, 0, 0)
After these changes, it doesn’t throw the errors anymore.
Here the changed version:
--[[
@Author: Spynaz
@Description: Enables dragging on GuiObjects. Supports both mouse and touch.
For instructions on how to use this module, go to this link:
https://devforum.roblox.com/t/simple-module-for-creating-draggable-gui-elements/230678
--]]
local UDim2_new = UDim2.new
local UserInputService = game:GetService("UserInputService")
local DraggableObject = {}
DraggableObject.__index = DraggableObject
-- Sets up a new draggable object
function DraggableObject.new(Object)
local self = {}
self.Object = Object
self.DragStarted = nil
self.DragEnded = nil
self.Dragged = nil
self.Dragging = false
setmetatable(self, DraggableObject)
return self
end
-- Enables dragging
function DraggableObject:Enable()
local object = self.Object
local dragInput = nil
local dragStart = Vector3.new(0, 0, 0)
local startPos = object.Position
local preparingToDrag = false
-- Updates the element
local function update(input)
local delta = input.Position - dragStart
local newPosition = UDim2_new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
object.Position = newPosition
return newPosition
end
self.InputBegan = object.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
preparingToDrag = true
--[[if self.DragStarted then
self.DragStarted()
end
dragging = true
dragStart = input.Position
startPos = Element.Position
--]]
local connection
connection = input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End and (self.Dragging or preparingToDrag) then
self.Dragging = false
connection:Disconnect()
if self.DragEnded and not preparingToDrag then
self.DragEnded()
end
preparingToDrag = false
end
end)
end
end)
self.InputChanged = object.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
dragInput = input
end
end)
self.InputChanged2 = UserInputService.InputChanged:Connect(function(input)
if object.Parent == nil then
self:Disable()
return
end
if preparingToDrag then
preparingToDrag = false
if self.DragStarted then
self.DragStarted()
end
self.Dragging = true
dragStart = input.Position
startPos = object.Position
end
if input == dragInput and self.Dragging then
local newPosition = update(input)
if self.Dragged then
self.Dragged(newPosition)
end
end
end)
end
-- Disables dragging
function DraggableObject:Disable()
self.InputBegan:Disconnect()
self.InputChanged:Disconnect()
self.InputChanged2:Disconnect()
if self.Dragging then
self.Dragging = false
if self.DragEnded then
self.DragEnded()
end
end
end
return DraggableObject
I was getting a very annoying bug where my draggable GUI would go off screen whenever I happen to be moving diagonally. It turns out dragStart was being reset to the origin since clicking and dragging and pressing input keys with no position at the right moment can break the dragging. For anyone curious on how to fix this, similar to how self.InputChanged checks input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch, you must do this same check in self.InputChanged2 along with preparingToDrag to prevent non-dragging related input positions to affect dragStart
TL;DR If GUI dragging is glitchy (disappears off screen / teleports somewhere else) when moving, use this instead
@Author: Spynaz
@Description: Enables dragging on GuiObjects. Supports both mouse and touch.
For instructions on how to use this module, go to this link:
https://devforum.roblox.com/t/simple-module-for-creating-draggable-gui-elements/230678
--]]
local UDim2_new = UDim2.new
local UserInputService = game:GetService("UserInputService")
local DraggableObject = {}
DraggableObject.__index = DraggableObject
-- Check if either mouse movement or touch input
function MouseOrTouchMovement(input)
return input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch
end
-- Sets up a new draggable object
function DraggableObject.new(Object)
local self = {}
self.Object = Object
self.DragStarted = nil
self.DragEnded = nil
self.Dragged = nil
self.Dragging = false
setmetatable(self, DraggableObject)
return self
end
-- Enables dragging
function DraggableObject:Enable()
local object = self.Object
local dragInput = nil
local dragStart = nil
local startPos = nil
local preparingToDrag = false
-- Updates the element
local function update(input)
local delta = input.Position - dragStart
local newPosition = UDim2_new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
object.Position = newPosition
return newPosition
end
self.InputBegan = object.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
preparingToDrag = true
local connection
connection = input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End and (self.Dragging or preparingToDrag) then
self.Dragging = false
connection:Disconnect()
if self.DragEnded and not preparingToDrag then
self.DragEnded()
end
preparingToDrag = false
end
end)
end
end)
self.InputChanged = object.InputChanged:Connect(function(input)
if MouseOrTouchMovement(input) then
dragInput = input
end
end)
self.InputChanged2 = UserInputService.InputChanged:Connect(function(input)
if object.Parent == nil then
self:Disable()
return
end
if MouseOrTouchMovement(input) and preparingToDrag then
preparingToDrag = false
if self.DragStarted then
self.DragStarted()
end
self.Dragging = true
dragStart = input.Position
startPos = object.Position
end
if input == dragInput and self.Dragging then
local newPosition = update(input)
if self.Dragged then
self.Dragged(newPosition)
end
end
end)
end
-- Disables dragging
function DraggableObject:Disable()
self.InputBegan:Disconnect()
self.InputChanged:Disconnect()
self.InputChanged2:Disconnect()
if self.Dragging then
self.Dragging = false
if self.DragEnded then
self.DragEnded()
end
end
end
return DraggableObject
Other than that works like a charm, thank you @Spynaz
Everything works perfectly on PC, however, mobile seems to bug out on this, here is a video explaining my situation. Is anyone able to help me out with this?