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.
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)
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.
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)
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