Detecting Mouse hold

It’s actually a very simple thing, and I’m sure it has a simple solution. But I couldn’t figure it out for a long time and I can’t progress in the game. Basically:

I want this:

I get this:

Edited(I’m using SurfaceGUI). I tried using .MouseButton1Down and it doesn’t work for mobile devices?? don’t know why. Even if it works, it’s not what I’m looking for, it doesn’t do what I want. And sorry again if it’s a very basic thing.

1 Like

You should detect when the mouse is down, and when the mouse moves, check for a target, color the target the grey target and repeat until the mouse if unheld. Example, adapt to as you need.

local UIS = game:GetService("UserInputService")
local MouseDown = false

UIS.InputBegan:Connect(function(a)
    if a.UserInputType == Enum.UserInputType.MouseButton1 then
        MouseDown = true 
    end
end)
UIS.InputEnded:Connect(function(a)
    if a.UserInputType == Enum.UserInputType.MouseButton1 then
        MouseDown = false
    end
end)
spawn(function()
while wait(0.1) do
    if MouseDown == true then
        if game.Players.LocalPlayer:GetMouse().Target ~= nil then
             local t = game.Players.LocalPlayer:GetMouse().Target
             if t.Name == "Block" then
                 t.Color = Color3.new(0.1,0.1,0.1)
             end
        end
    end
end
end)
2 Likes

Also if it does work mark it as the solution

Sorry I completely forgot I’m using SurfaceGUI not ClickDetector. :worried:

Well then, use the event: MouseButton1Hold

You can also check this out, which has an example monitoring mouse movements:

Going about it:
When the user begins input, and closes input toggle some type of debounce, say a variable named ‘Holding’. Whenever the mouse moves, check if that debounce ‘Holding’ is set to true. If the mouse’s position is in a certain UI, highlight the UI. You could even check if the mouse isn’t in any box and cancel the Hold.

How can I check if mouse’s position is in a certain UI. Because as far as I see I don’t get Global Position Values from this and I’m using SurfaceGUI.

Heres an example"
local userInputService = game:GetService("UserInputService")

-- Check if mouse is in uiObj
local function checkInBounds(uiObj, position)
	local x_cond=uiObj.AbsolutePosition.X <= position.X and position.X <= uiObj.AbsolutePosition.X + uiObj.AbsoluteSize.X
	local y_cond=uiObj.AbsolutePosition.Y <= position.Y and position.Y <= uiObj.AbsolutePosition.Y + uiObj.AbsoluteSize.Y
	
	return x_cond and y_cond
end


-- User Input Service
local holding=false
userInputService.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed then
		return
	end
	if input.UserInputType==Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		holding=true
	end
end)

userInputService.InputEnded:Connect(function(input, gameProcessed)
	if gameProcessed then
		return
	end
	if input.UserInputType==Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		holding=false
	end
end)

userInputService.InputChanged:Connect(function(input, gameProcessed)
	if gameProcessed or not holding then
		return
	end
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		if checkInBounds(script.Parent.Frame, input.Position) then
			print('In object')
		end
	end
end)

There’s really plenty of ways to go about it. Really the key thing that defines a hold is the inputBegan and inputEnd. If you keep track of when each happens, then you could even design a model to work with :MouseEnter() and :MouseLeave().

When I locate the uiObj to right place it gives error because Blocks don’t have Absolute Position. I tried it with ScreenGUI and it worked fine but doesn’t work with SurfaceGui. Takes the SurfaceGui’s values as ScreenGui. Am I missing something?

Oh sorry, missed that part. The surface UI’s still have an absolute size and position scale, the problem was that those don’t line up with the player’s screen.

userInputService has an event named InputChanged, and this uses the mouse/touch position relative to the screen.
But all GuiObjects also have an event named InputChanged, which uses the mouse/touch position relative to the GuiObject’s ScreenGui Ancestor. So use this event instead, and it should work with the same code above.

GuiObject.InputChanged:Connect(function(input, gameProcessed)
	if not gameProcessed and holding and checkInBounds(GuiObject, input.Position) then
		print('In '..v.Name)
	end
end)

again, I can’t get it to work with SurfaceGui. ScreenGui works fine, but I don’t even know where to put the script when it comes to SurfaceGui. I tried putting it in GuiObject and PlayerScripts but none work.

Input related events can only be handled on the client (even if it’s connected to an object on the server), so you’ll want this in a local script. PlayerScripts is probably the best place for that in this case.
Make sure when you use InputBegan, InputChanged, or InputEnded, it’s on a GuiObject (Frame, TextButton, ImageLabel, etc.) and not a ScreenGui or SurfaceGui object.

Again there’s a lot of ways to detect user input; here’s a different technique which I think looks cleaner. This one is more designed to resemble the goal in your initial post.

Code and UI Structure
local userInputService = game:GetService("UserInputService")
local surfaceGui = workspace.GuiPart.SurfaceGui	-- Path to gui in workspace
local holding=false

local boxes=surfaceGui.SelectionSpace:GetChildren()



surfaceGui.SelectionSpace.StartBox.InputBegan:Connect(function (input, gP) -- If user starts a click or tap on the startBox then activate hold.
	if not gP and (input.UserInputType==Enum.UserInputType.MouseButton1 or input.UserInputType==Enum.UserInputType.Touch) then
		holding = true -- Enable holding when user clicks/taps on the starting UI
		surfaceGui.SelectionSpace.StartBox.Transparency=0
	end
end)

-- Connect each box to an input event; (UserInputType MouseMovement fires inputBegan if mouse/touch enters guiObject)
for i,v in pairs(boxes) do
	v.InputBegan:Connect(function (input, gP)
		if holding and not gP then		-- If a hold is active and the event isn't processed by game 
			v.Transparency=0
		end
	end)
end

surfaceGui.SelectionSpace.InputEnded:Connect(function (input, gP)	-- This object surrounds all the boxes, so if any input ends here, the holding should cancel
	holding=false
	for i,v in pairs(boxes) do
		v.Transparency=1
	end
end)

Screen Shot 2020-06-14 at 4.55.33 AM

Video

Hopefully this resolves the issues before. Let me know if you have any questions or things still aren’t working. This is also a good reference for input events

1 Like