Circle Buttons GUI

Hello,

i’m trying to create a button, however it must be a circle.

now i’m only can create a “rect” how is it possible to make a button like a circle?

Well, if it’s ok for it to just look like a circle you can just make a texture that’s a circle with 0 alpha outside of the circle. Then if you make a square button with that texture you’ll only see the circle.

The downside is that the clickable area of the button will still be square. This means your clickable area will be 27% more than the visible area, but I could only see it being a big problem if you wanted to closely pack in lots of circular controls.

To make the button’s clickable area a circle I’m not sure the work that would be involved, but if it were me I’d try the above first to see if that works for what you need.

1 Like

thanks you,

i’ll try to do that, but then i also must take the bounds of the rect!

right?

OK, figuring out the clickable area shouldn’t be too hard. It’s a circle. Enclosed in a square (rect). You know where the center of the square is, and you know the radius of the circle. You can get the pixel point that was clicked. So if the pixel is within the radius of the circle, DoStuff(), else ignore it.

AKA,

A pizza with a radius “z” and a height “a” has a volume equal to “pi z z a”

6 Likes

haha! I like that one!

and how does this code gonna look like?

It will have lines of code that will include variables, functions and loops probably… :slight_smile:

Nice one!

Ok, If you want, you can try this approach, which actually checks the alpha of the pixel the user clicked. This means the texture cannot be compressed, but in my case it was necessary to get pixel colors the user clicked on.
I used this code in a window, so the calculations will be a little different in your case, but there are comments…
Also, you don’t have to use events, and can use OnMouseDown() and Input.GetMouseButtonDown(). This is just an example of a principle. Edit is as you need.

// This rect defines the boundries in which the color wheel sits
var inRect: Rect = new Rect(375, 0, 145, 150);
var fAspectX: float;
var fAspectY: float;
var v2LocalClick: Vector2;

GUI.Button(inRect,txColorWheel, guiSkin.GetStyle("colorWheel"));

switch (Event.current.type)
{
	case EventType.MouseDown:;
	case EventType.MouseDrag:
		// Colorwheel was clicked
		
		// Figure out where exactly (since the coordinates mousePosition gives us are global, and not local to this window)
		v2LocalClick.x = Input.mousePosition.x - inRect.x - windowRect.xMin;
		v2LocalClick.y = windowRect.yMin + Input.mousePosition.y - Screen.height + inRect.height;
		
		//GuiDebug.Log(Event.current.mousePosition + "---" + inRect);
		GUI.Label(inRect, txColorWheel, guiSkin.GetStyle("colorWheel"));
		if (inRect.Contains(Event.current.mousePosition)) 
		{
			//GuiDebug.Log("In" + v2LocalClick + "---" + Input.mousePosition.y);
			fAspectX = txColorWheel.width / inRect.width; 
			fAspectY = txColorWheel.height / inRect.height; 
			
			var cTemp: Color = txColorWheel.GetPixel(v2LocalClick.x * fAspectX, v2LocalClick.y * fAspectY);
			// Check to see if the user clicked in a painted area of the color wheel (since the bounds are transparent, but still recieve clicks)
			if (cTemp.a == 1)
			{
				// Select new color
				cSelectedColor = cTemp;
			}
	    }
	    break;
}

its pretty much basic vector math and trigonomitry :shock:

(assuming you make it with a circle inside a rect button)
it requires you have the center of the circle in global coords and the radius of the circle
center_vector = circle center (global)
circle_radius = circle radius
click_vector = mouse click point (global)
length_vector = center_vector - click_vector

use the pythagorean theorem a^2 + b^2 = c^2

so length_vector.x^2 + length_vector.y^2 = length^2

since the length should be smaller of equal to the radius of the circle you can write it as:
sqrt(length_vector.x^2 + length_vector.y^2) <= circle_radius
or since sqrt is an expensive operation you can optimize it to:

length_vector.x^2 + length_vector.y^2 <= circle_radius^2

or

length_vector.xlength_vector.x + length_vector.y length_vector.y <= circle_radius*circle_radius

if that statement is true then the circle part of the button is pressed.

Spot on, perlohmann. Assuming length_vector is a Vector2, this statement can also be further optimised to:

length_vector.sqrMagnitude <= circle_radius*circle_radius

but it always helps to know the math behind it, too! :slight_smile:

thanks a lot!

i’ll try to implement this into the game

We now have the new UI in Unity 4.6, but the problem with the non-rect interactive UI-elements still persist. Good thing is, they have opened the source code, and after studying it a while, I made a slick solution: custom raycaster, which inherits from the default GraphicRaycaster. It sends input events based on target texture transparency, which allows a precise interaction with objects that have a non-rect shapes (like circles, triangles, etc).

It is available at the asset store, btw: Alpha Raycaster | GUI Tools | Unity Asset Store

In order to make circular…

  1. Create a button from canvas
  2. Click button from hierarchy view, and choose rect transform from inspector window.
  3. Reduce the size to 51.69(width) and 30(height)
  4. In the Image script, choose the knob option from the source image.
  5. And check Preserve Aspect.
  6. Now circle shape you will get.
  7. And now if you want to resize the circle… then change the scale values… you will get a beautiful circle.:slight_smile:
8 Likes

@Sathish_1 Thanks!

any other passerby’s, if you want the circle button to only allow you to click in the circle,

  1. upload your UI sprite transparent in areas you don’t want to be clicked
  2. under the Texture 2D import settings of your sprite, enable: Advanced > Read/Write Enabled
  3. add a script that calls
    GetComponent<Image>().alphaHitTestMinimumThreshold = .5f;

Worked for me, but took a while to find the answer so I hope this helps someone else get there sooner.

3 Likes