Detecting where on the ui a click happened

i have a problem, i made a imagebutton with an image of a triangle (since roblox doesnt have any ui triangles by itself) and set the backgroundtransparency to 1, but now using things like MouseEnter fire too early (putting the mouse on background fires it, despite the fact its just an invisible part of ui)
so how do i detect whether the mouse is actually on the image, or just on the background?

You can try using BaseGui:GetGuiObjectsAtPosition()

You can try using UserInputService:GetMouseLocation() and comparing with your GUI positions.

Not sure this will help but …

local UIS=game:GetService("UserInputService")
UIS.InputBegan:Connect(function(Input, gameProcessedEvent)
	if gameProcessedEvent then
		if Input.UserInputType == Enum.UserInputType.MouseButton1 then
		--
		end
	end
end)

gameProcessedEvent will be true if it’s actually over a gui “part”.

The button’s InputBegan and InputChanged events provide an InputObject as their first parameter. These events fire on hovers as well as clicks. The X and Y of the InputObject’s Position property match the point on screen where the mouse is. The AbsolutePosition and AbsoluteSize of the button can tell you the rough square boundary of the ImageButton. Since it’s not yet possible to do pixel checks on images outside of Studio, you can do some math on the mouse coordinates on the image to guess if it overlaps the triangle. You can make this easier if you convert the coordinates to two decimals between 0 and 1 representing where in the boundary the mouse is, kinda how UDim’s Scale works.

2 Likes

Building off of this, all we need to try and figure out is if the mouse is in a specified triangular area.

To start, instead of using AbsoluteSize and AbsolutePosition, we can just use the image’s Position and Size properties. For this we will use scale. To convert to scale we will need the ScreenGui’s AbsoluteSize, however.

Ensure that your image is converted to scale (Both Size and Position)

local screen_gui = --> path to ScreenGui
local screen_size = screen_gui.AbsoluteSize

local image = --> path to Image
local pos = image.Position
local size = image.Size

Before we go any further, we need to define the 3 vertices of your triangle. It is recommended that your base vertices are in 2 of the corners and your 3rd vertex is on the opposite side in the middle. Here is an example:

Here we will define the vertices.

local p0 = Vector2.new(pos.X, pos.Y - size.Y/2) -- Top middle
local p1 = Vector2.new(pos.X - size.X/2, pos.Y + size.Y/2) -- Bottom right
local p2 = Vector2.new(pos.X + size.X/2, pos.Y + size.Y/2) -- Bottom left

Note: “p” represents “point”, starting at “point 0”

Now, let’s create a function that will determine if a given mouse input is in the bounds of our triangular area.

This function was sourced from this post here:

local function CheckInBounds(mouse_pos: Vector2): boolean
	local p = Vector2.new(mouse_pos.X / screen_size.X, mouse_pos.Y / screen_size.Y)
	
	local s = p0.Y * p2.X - p0.X * p2.Y + (p2.Y - p0.Y) * p.X + (p0.X - p2.X) * p.Y
	local t = p0.X * p1.Y - p0.Y * p1.X + (p0.Y - p1.Y) * p.X + (p1.X - p0.X) * p.Y
	
	if (s < 0) ~= (t < 0)  then
		return false
	end
	
	local area = -p1.Y * p2.X + p0.Y * (p2.X - p1.X) + p0.X * (p1.Y - p2.Y) + p1.X * p2.Y
	
	if area < 0  then
		return (s <= 0 and s + t >= area)
	else
		return (s >= 0 and s + t <= area)
	end
end

Then, using the button.MouseButton1Click function, we can get the location of the mouse (X and Y) using UserInputService.

local uis = game:GetService("UserInputService")

image.MouseButton1Click:Connect(function()
	local mouse_pos = uis:GetMouseLocation()
	local in_bounds = CheckInBounds(mouse_pos)
	
	--[[
	
	if in_bounds then
		-- Mouse clicked inside of triangle
	end
	
	]]
	
	print(in_bounds)
end)

All of this should detect if the mouse position is between the three given vertices of your triangle.

1 Like