How to create limit for 2D object position?

So, i have Image which i need to move when player press and hold right mouse button.
Everything works good but i got stuck on part to limit the position, so image won’t go to not right place.
Here is my code:

local UserInputService = game:GetService("UserInputService")
local Player = game:GetService("Players").LocalPlayer
local Mouse = Player:GetMouse()
local AlreadyPressed = false
local MouseIsHere = false
local LastPosition = script.Parent.Position
local function Button2Up()
	if script.Parent.Visible == true then
		AlreadyPressed = true
		end
end
local CanUse = false
local function Button2Down()
	if script.Parent.Visible == true then
		if MouseIsHere == true then
	AlreadyPressed = false
			UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
	while true do
				task.wait()
		if AlreadyPressed == true then
			UserInputService.MouseBehavior = Enum.MouseBehavior.Default
			break
				end
				if MouseIsHere == false then
					script.Parent.Position = LastPosition
				end
		local MouseDelta = UserInputService:GetMouseDelta()
			script.Parent.Position = UDim2.new(UDim.new(script.Parent.Position.Width.Scale,script.Parent.Position.Width.Offset + MouseDelta.X),UDim.new(script.Parent.Position.Height.Scale,script.Parent.Position.Height.Offset + MouseDelta.Y))
		end
	elseif MouseIsHere == false then
		script.Parent.Position = LastPosition
			end
	end
end
local function MouseEnter()
	if script.Parent.Visible == true then
		MouseIsHere = true
	end
end
local function MouseLeft()
	if script.Parent.Visible == true then
		MouseIsHere = false
	end
end
script.Parent.MouseLeave:Connect(MouseLeft)
script.Parent.MouseEnter:Connect(MouseEnter)
Mouse.Button2Down:Connect(Button2Down)
Mouse.Button2Up:Connect(Button2Up)
2 Likes

Do you want to drag something around in StarterGUI (Player-Screen) or inside part?

2 Likes

I hope you mean on Screen, so I wrote a LocalScript that should only be inside a Frame:

local UIS = game:GetService('UserInputService')
local frame = script.Parent
local dragToggle = nil
local dragSpeed = 0.25
local dragStart = nil
local startPos = nil

local function updateInput(input)
	local delta = input.Position - dragStart
	local position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X,
		startPos.Y.Scale, startPos.Y.Offset + delta.Y)
	game:GetService('TweenService'):Create(frame, TweenInfo.new(dragSpeed), {Position = position}):Play()
end

frame.InputBegan:Connect(function(input)
	if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then 
		dragToggle = true
		dragStart = input.Position
		startPos = frame.Position
		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				dragToggle = false
			end
		end)
	end
end)

UIS.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		if dragToggle then
			updateInput(input)
		end
	end
end)
1 Like

In StarterGui.


Thanks for your help! I will test your code when roblox will be repaired.

Sorry, i just tested it and it is the same as mine script but more smoothly and with mobile support, i think you didn’t understand me, i mean i don’t need to player move frame more than limited position, because i make frame which player need to move (it’s full screen), but i don’t want player to see what happens out of it. Also, anyways thanks for your reply, and for try to help me.

1 Like

What I am getting for information:

  1. It should only allow one axis.
  2. Should be inside screen. (not out of bounce)
  3. Like a puzzle game where you have to move a piece to an exact position.

Thanks for knowing, would have been easy if that was the answer! :sweat_smile:

1 Like

Have you found a solution for this yet? If not, by “limit” do you mean you want it to only move so far on the X and Y axis or are you looking for it only to be moved to an exact location on the screen?

If wanting to restrict it from moving so far on the X and Y axis, you can use math.clamp(). I’ll be able to provide further help once I know what you’re looking for. :slight_smile:

1 Like

No, lol.

I want it to only move so far on the X and Y axis.

I tried it already, but I don’t know how can i calculate max X and max Y Axis based on it’s size and position to put into math.clamp.

Thanks again, i thought no one would reply after that much time.

No worries! :slight_smile: I’ve set up an example place using majority of the code you’ve already written. Hope this helped!
UIBoundsExample.rbxl (46.1 KB)

1 Like

Thanks , but how i can do it if object which i need to move is full screened too?

I’m confused by what you mean by “full screened” – if it’s the size of the entire screen? If so, what bounds would you go by when there’s no extra space left? :thinking: Could you explain more about what you’re using this for and what you’re trying to achieve.

Thanks :slight_smile:

1 Like

Thanks for still try to help me.

Yes.

I try to make something like skill tree.

No worries :slight_smile: Ohh so you mean to move it anywhere around the screen but not outside of the screen?

local function updateInput(input)
	local delta = input.Position - dragStart
	
	local MinXBounds, MaxXBounds = 0,ScreenSize.X-ElementSize.X
	local MinYBounds, MaxYBounds = 0,ScreenSize.Y-ElementSize.Y
	
	local position = UDim2.new(
		0,
		math.clamp(((startPos.X.Offset-ElementSize.X/2) + delta.X),MinXBounds,MaxXBounds),
		0,
		math.clamp(((startPos.Y.Offset-ElementSize.Y/2) + delta.Y),MinYBounds,MaxYBounds)
	)
	
	game:GetService('TweenService'):Create(frame, TweenInfo.new(dragSpeed), {Position = position}):Play()
end

If you change the “updateInput” function in the example place I gave you with that code above, it will allow for moving the UI element anywhere within the screen while respecting the size of the element you’re moving so it doesn’t go outside of the screen.

If this still isn’t what you mean, my apologies.

1 Like

Thanks but it looks like it doesn’t work and sometime i get this error:
invaild argument to clamp (max must be greater than or equal to min) as i understand MaxXBounds is smaller than MinXBounds, also as i understand element is even bigger than screen size.

Could you maybe provide a screenshot of what you’re working on? If the UI element you’re moving is larger than the screen size, there’s no way you can keep it in bounds of the screen size.

1 Like

Okey.


If you want example here: All my Operatives' Skill Tree (Reupload) [Roblox: Entry Point] - YouTube just watch few seconds and you will understand that it doesn’t move after it reached corners to left.

Aah… Cool. I think the issue is likely you’re not properly referencing the UI element you’re wanting to move. Where is this script parented at? Can you send a screenshot of the hierarchy and your current code? :slight_smile: I would recommend having the script a direct child of the ScreenGui as well – you’d have to change your variable references of course.

1 Like

image
Code:

local UIS = game:GetService("UserInputService")
local frame = script.Parent
local dragToggle = nil
local dragSpeed = 0.25
local dragStart = nil
local startPos = nil

local ScreenSize = script.Parent.Parent.AbsoluteSize
print(ScreenSize)
local Bounds = Instance.new("Frame")
Bounds.Parent = script.Parent.Parent
Bounds.Size = UDim2.new(0,(ScreenSize.X*.6),0,(ScreenSize.Y*.6))
Bounds.Position = UDim2.new(.2,0,.2,0)
Bounds.Visible = false
local player = game.Players.LocalPlayer
local ElementSize = script.Parent.AbsoluteSize

--[[
	IF YOU HAVE ANY FURTHER QUESTIONS ABOUT THIS, FEEL FREE TO DM ME @WrollingYou 
	Hope this helped! :) 
	Feel free to remove this commented section and the others after you've read them! :)
	~ 6/13/2023
]]


local function updateInput(input)
	local delta = input.Position - dragStart

	local MinXBounds, MaxXBounds = 0,ScreenSize.X-ElementSize.X
	local MinYBounds, MaxYBounds = 0,ScreenSize.Y-ElementSize.Y

	local position = UDim2.new(
		0,
		math.clamp(((startPos.X.Offset-ElementSize.X/2) + delta.X),MinXBounds,MaxXBounds),
		0,
		math.clamp(((startPos.Y.Offset-ElementSize.Y/2) + delta.Y),MinYBounds,MaxYBounds)
	)
	print(position)

	game:GetService("TweenService"):Create(frame, TweenInfo.new(dragSpeed), {Position = position}):Play()
end

frame.InputBegan:Connect(function(input)
	if (input.UserInputType == Enum.UserInputType.MouseButton2 or input.UserInputType == Enum.UserInputType.Touch) then 
		dragToggle = true
		dragStart = input.Position
		local MousePos = UIS:GetMouseLocation()
		startPos = UDim2.new(frame.Position.X.Scale,MousePos.X, frame.Position.Y.Scale, MousePos.Y) --frame.Position
		updateInput(input)
		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				dragToggle = false
			end
		end)
	end
end)

UIS.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		if dragToggle then
			updateInput(input)
		end
	end
end)

Thanks, I see now what the issue is and what you were trying to achieve. Here’s updated code that should work :100: for doing just what you’re looking for. :slight_smile:

local UIS = game:GetService("UserInputService")
local frame = script.Parent
local dragToggle = nil
local dragSpeed = 0.25
local dragStart = nil
local startPos = nil

local ScreenSize = script.Parent.Parent.AbsoluteSize
local player = game.Players.LocalPlayer


local function updateInput(input)
	local delta = input.Position - dragStart
	
	local MinXBounds, MaxXBounds = -(frame.AbsoluteSize.X-ScreenSize.X), 0
	local MinYBounds, MaxYBounds = -(frame.AbsoluteSize.Y-ScreenSize.Y), 0

	local position = UDim2.new(
		0,
		math.clamp((startPos.X + delta.X),MinXBounds,MaxXBounds),
		0,
		math.clamp((startPos.Y + delta.Y),MinYBounds,MaxYBounds)
	)
	
	game:GetService("TweenService"):Create(frame, TweenInfo.new(dragSpeed), {Position = position}):Play()
end

frame.InputBegan:Connect(function(input)
	if (input.UserInputType == Enum.UserInputType.MouseButton2 or input.UserInputType == Enum.UserInputType.Touch) then 
		dragToggle = true
		dragStart = input.Position
		startPos = frame.AbsolutePosition
		updateInput(input)
		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				dragToggle = false
			end
		end)
	end
end)

UIS.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		if dragToggle then
			updateInput(input)
		end
	end
end)

Hope this helped! :slight_smile:

1 Like