Need help with my own bounded drag script

So, the problem is, yes it is bounded and working extremely great but you have to initialize the values pretty much manually through :SetAxis()
Wonder if doing automatic bounding is possible with my code?

export type Dimension = UDim2
export type UIObject = GuiObject
export type numeric = number

export type Axis = {
	X: {
		LeftVector: numeric,
		RightVector: numeric
	},
	Y: {
		UpVector: numeric,
		DownVector: numeric
	},
	Hash: {
		LigamentDetached: boolean,
		LeftVectorTriggered: boolean,
		RightVectorTriggered: boolean,
		UpVectorTriggered: boolean,
		DownVectorTriggered: boolean
	}
}

export type Drag = {
	Container: UIObject,
	Pointer: UIObject,
	Truncated: boolean,
	Enabled: boolean,
	Active: boolean,
	Speed: numeric,
	StartPos: Dimension,
	RecentLerpPos: Dimension,
	RecentPointerPos: Vector2,
	Connections: {
		Runtime: RBXScriptConnection,
		Entry: RBXScriptConnection,
		Exit: RBXScriptConnection
	},
	Axis: Axis
}

local function Lerp(a: number, b: number, m: number)
	return a + (b - a) * m
end

local RunService = game:GetService('RunService')
local UserInputService = game:GetService('UserInputService')

local Drag = {}
Drag.__index = Drag

function Drag.new(Container: UIObject, Pointer: UIObject?, Speed: numeric?)
	return setmetatable({
		Container = Container :: UIObject,
		Pointer = Pointer :: UIObject,
		Truncated = false :: boolean,
		Enabled = false :: boolean,
		Active = false :: boolean,
		Speed = Speed or 8 :: numeric,
		StartPos = Container.Position :: Dimension,
		RecentLerpPos = nil :: Dimension,
		RecentPointerPos = UserInputService:GetMouseLocation() :: Vector2,
		Connections = {} :: {
			Runtime: RBXScriptConnection,
			Entry: RBXScriptConnection
		},
		Axis = {
			X = {
				LeftVector = 0,
				RightVector = 0
			},
			Y = {
				UpVector = 0,
				DownVector = 0
			},
			Hash = {
				LigamentDetached = false,
				LeftVectorTriggered = false,
				RightVectorTriggered = false,
				UpVectorTriggered = false,
				DownVectorTriggered = false
			}
		} :: Axis
	}, Drag)
end

function Drag:Attach()
	local self = self :: Drag

	local Axis = self.Axis

	local RightVector = Axis.X.RightVector
	local LeftVector = Axis.X.LeftVector
	local UpVector = Axis.Y.UpVector
	local DownVector = Axis.Y.DownVector
	local BoundaryReached = Axis.Hash.LigamentDetached

	local Update = function(deltaTime: numeric)
		if not self.Truncated then return end
		if not self.Enabled then return end
		if not self.StartPos then return end
		if not self.Active and self.RecentLerpPos then
			if BoundaryReached then return end
			local containerPos = UDim2.new(
				self.StartPos.X.Scale,
				Lerp(self.Container.Position.X.Offset, self.RecentLerpPos.X.Offset, deltaTime * self.Speed),
				self.StartPos.Y.Scale,
				Lerp(self.Container.Position.Y.Offset, self.RecentLerpPos.Y.Offset, deltaTime * self.Speed)
			)

			self.Container.Position = containerPos
			return
		end

		local deltaPointer = self.RecentPointerPos - UserInputService:GetMouseLocation()
		local xGoal = self.StartPos.X.Offset - deltaPointer.X
		local yGoal = self.StartPos.Y.Offset - deltaPointer.Y

		if xGoal > RightVector then
			BoundaryReached = true
			xGoal = RightVector
		else
			BoundaryReached = false
		end
		
		if xGoal < LeftVector then
			BoundaryReached = true
			xGoal = LeftVector
		else
			BoundaryReached = false
		end
		
		if yGoal > DownVector then
			BoundaryReached = true
			yGoal = DownVector
		else
			BoundaryReached = false
		end
		
		if yGoal < UpVector then
			BoundaryReached = true
			yGoal = UpVector
		else
			BoundaryReached = false
		end
		
		local RecentLerpPosition = UDim2.new(
			self.StartPos.X.Scale,
			xGoal, 
			self.StartPos.Y.Scale, 
			yGoal
		)

		self.RecentLerpPos = UDim2.new(
			self.StartPos.X.Scale,
			xGoal, 
			self.StartPos.Y.Scale, 
			yGoal
		)
		
		local ContainerPosition = UDim2.new(
			self.StartPos.X.Scale,
			Lerp(self.Container.Position.X.Offset, xGoal, deltaTime * self.Speed),
			self.StartPos.Y.Scale,
			Lerp(self.Container.Position.Y.Offset, yGoal, deltaTime * self.Speed)
		)
		
		self.Container.Position = ContainerPosition
	end

	if self.Pointer then
		self.Connections.Entry = self.Pointer.InputBegan:Connect(function(input) 
			if input.UserInputType == Enum.UserInputType.MouseButton1 then
				self.Active = true
				self.StartPos = self.Container.Position
				self.RecentPointerPos = UserInputService:GetMouseLocation()

				input.Changed:Connect(function()
					if input.UserInputState == Enum.UserInputState.End then
						self.Active = false
					end
				end)
			end
		end)

		self.Connections.Runtime = RunService.Heartbeat:Connect(Update)
	else
		self.Connections.Entry = self.Container.InputBegan:Connect(function(input) 
			if input.UserInputType == Enum.UserInputType.MouseButton1 then
				self.Active = true
				self.StartPos = self.Container.Position
				self.RecentPointerPos = UserInputService:GetMouseLocation()

				input.Changed:Connect(function()
					if input.UserInputState == Enum.UserInputState.End then
						self.Active = false
					end
				end)
			end
		end)

		self.Connections.Runtime = RunService.Heartbeat:Connect(Update)
	end

	self.Truncated = true
	self.Enabled = true
end

function Drag:SetAxis(RightVector: numeric, LeftVector: numeric, UpVector: numeric, DownVector: numeric)
	local self: Drag = self

	self.Axis.X.LeftVector = LeftVector
	self.Axis.X.RightVector = RightVector

	self.Axis.Y.UpVector = UpVector
	self.Axis.Y.DownVector = DownVector
end

return Drag

This topic is mostly just a math problem and since im bad at math, I dont think I’ll be doing this on my own.

And there’s another problem, it happens when I idle while holding my mouse onto the UI Object, the position gets offset by 1 and it looks really weird, I dont really know how to reproduce it though.

1 Like

You could add a parameter to your constructor specifying the axes at the time the Drag is created

I mean I want to be fitting on all types and sizes of viewports, currently been trying to for the past week. Its mostly just a math problem, I might remake it to fit my standards.

I already fixed it, by doing some small tweaks! Thanks.