Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Circle Buttons GUI

Discussion in 'Immediate Mode GUI (IMGUI)' started by Jaapstudent, Mar 27, 2009.

  1. Jaapstudent

    Jaapstudent

    Joined:
    Mar 27, 2009
    Posts:
    24
    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?
     
  2. dawvee

    dawvee

    Joined:
    Nov 12, 2008
    Posts:
    276
    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.
     
    ranjurave likes this.
  3. Jaapstudent

    Jaapstudent

    Joined:
    Mar 27, 2009
    Posts:
    24
    thanks you,

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

    right?
     
  4. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    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.
     
  5. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    AKA,

    A pizza with a radius "z" and a height "a" has a volume equal to "pi z z a"
     
  6. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    haha! I like that one!
     
  7. Jaapstudent

    Jaapstudent

    Joined:
    Mar 27, 2009
    Posts:
    24
    and how does this code gonna look like?
     
  8. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    It will have lines of code that will include variables, functions and loops probably... :)

    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.

    Code (csharp):
    1.  
    2. // This rect defines the boundries in which the color wheel sits
    3. var inRect: Rect = new Rect(375, 0, 145, 150);
    4. var fAspectX: float;
    5. var fAspectY: float;
    6. var v2LocalClick: Vector2;
    7.  
    8. GUI.Button(inRect,txColorWheel, guiSkin.GetStyle("colorWheel"));
    9.  
    10. switch (Event.current.type)
    11. {
    12.     case EventType.MouseDown:;
    13.     case EventType.MouseDrag:
    14.         // Colorwheel was clicked
    15.        
    16.         // Figure out where exactly (since the coordinates mousePosition gives us are global, and not local to this window)
    17.         v2LocalClick.x = Input.mousePosition.x - inRect.x - windowRect.xMin;
    18.         v2LocalClick.y = windowRect.yMin + Input.mousePosition.y - Screen.height + inRect.height;
    19.        
    20.         //GuiDebug.Log(Event.current.mousePosition + "---" + inRect);
    21.         GUI.Label(inRect, txColorWheel, guiSkin.GetStyle("colorWheel"));
    22.         if (inRect.Contains(Event.current.mousePosition))
    23.         {
    24.             //GuiDebug.Log("In" + v2LocalClick + "---" + Input.mousePosition.y);
    25.             fAspectX = txColorWheel.width / inRect.width;
    26.             fAspectY = txColorWheel.height / inRect.height;
    27.            
    28.             var cTemp: Color = txColorWheel.GetPixel(v2LocalClick.x * fAspectX, v2LocalClick.y * fAspectY);
    29.             // Check to see if the user clicked in a painted area of the color wheel (since the bounds are transparent, but still recieve clicks)
    30.             if (cTemp.a == 1)
    31.             {
    32.                 // Select new color
    33.                 cSelectedColor = cTemp;
    34.             }
    35.         }
    36.         break;
    37. }          
    38.  
     
  9. perlohmann

    perlohmann

    Joined:
    Feb 12, 2009
    Posts:
    221
    its pretty much basic vector math and trigonomitry :eek:

    (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.x*length_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.
     
  10. dawvee

    dawvee

    Joined:
    Nov 12, 2008
    Posts:
    276
    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! :)
     
  11. Jaapstudent

    Jaapstudent

    Joined:
    Mar 27, 2009
    Posts:
    24
    thanks a lot!

    i'll try to implement this into the game
     
  12. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    461
    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: https://assetstore.unity.com/packages/tools/gui/alpha-raycaster-28601
     
    Last edited: Aug 11, 2021
  13. Sathish_1

    Sathish_1

    Joined:
    Dec 28, 2015
    Posts:
    1
    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.:)
     
    miniil, bluethings, neel507 and 5 others like this.
  14. ryan_mclaughlin

    ryan_mclaughlin

    Joined:
    Apr 20, 2016
    Posts:
    1
  15. horsesNhalo

    horsesNhalo

    Joined:
    Dec 23, 2017
    Posts:
    2
    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.
     
    mos99z and bluethings like this.