Alpha area on round GUI button return click event

I currently have a texture of a circle assigned to a GUI button. The button works fine, but I'm getting the mouse click when the user clicks on the transparent area of the button. I'd like to only get the mouse click event when the mouse is on the opaque area of the button. Is this possible?

Not without a completely custom control. Click handling is based on the "bounding" rect of the control, so everything in the GUI system is actually rectangular as far as layout and input handling goes.

-Jeremy

You could get the screen coordinates of the mouse click, calculate where in your image the user clicked (if they clicked in your image), sample that pixel of the image, and then do whatever you need to do if it's not transparent.
You can only sample pixels from images that are imported with a particular kind of compression. I'm afraid I can't remember which off the top of my head, though.

Non-compressed, actually (RGBA32, also works with other non-compressed formats like RGB24 and Alpha8), which is what you'd want to use for GUI graphics anyway. Nifty solution, though converting from "screen coords" to "where in my image is this" seems, offhand, like it would be somewhat tricky.

--Eric

I'd do something like this (WARNING: Untested code):

public Texture2D myCustomIcon, myCustomIconClicked;



/*
    ...
 */



public void OnGUI()
{
    if( AlphaButton( new Vector2( 100, 100 ), myCustomIcon, myCustomIconClicked ) )
    {
        Debug.Log( "Yarrr! Clicked!" );
    }
}



public static bool AlphaButton( Vector2 pos, Texture2D icon, Texture2D iconClicked )
{
    return AlphaButton( pos, icon, iconClicked, 0.5f );
}



public static bool AlphaButton( Vector2 pos, Texture2D icon, Texture2D iconClicked, float alphaThreshold )
{
    Rect iconRect;
    Vector2 relativeClick;

    iconRect = new Rect( pos.x, pos.y, icon.width, icon.height );

    if( Event.current.type == EventType.MouseDown  CheckRect( Event.current.mousePosition, iconRect ) )
    {
        relativeClick = new Vector2( Event.current.mousePosition.x - pos.x, Event.current.mousePosition.y - pos.y );

        if( icon.GetPixel( relativeClick.x, relativeClick.y ).a > alphaThreshold )
        {
            GUI.DrawTexture( iconRect, iconClicked );
            return true;
        }
    }

    GUI.DrawTexture( iconRect, icon );
    return false;
}



public static bool CheckRect( Vector2 point, Rect rect )
{
    return  point.x >= rect.x  point.x <= rect.x + rect.width 
            point.y >= rect.y  point.y <= rect.y + rect.height;
}

Ok I got a bit carried away on that one. Hope it helps :wink:

Thanks for the code Angry Ant. I thought the GUI in Unity would be smart enough to take the alpha channel into account. Apps like Flash, Dreamweaver, and Torque seemd to do this, so I thought it was the same in Unity. I'll try testing for the alpha myself and see if that'll work for me. Thanks all.

AngryAnt - you're a legend. Took 5 mins to modify the example you gave and now I have a generic custom cursor CS script :smile: Happy days.

Anyone who's looking for a custom cursor (particularly NooBees like myself.. just attach this as a script to an object in your scene and add two different textures for your normal onclick custom cursor.

[DISCLAIMER: Modified from AngryAnt's code - I don't really know what I doing so this may not work...]

using UnityEngine;
using System.Collections;

public class CustomCursor: MonoBehaviour {

    public delegate void OnCursorGUI();
    private OnCursorGUI cursor;

    public Texture2D custom_cursor_on_click;
    public Texture2D custom_cursor;

    public void Awake()
    {
       cursor = NormalCursor;
    }

    public void OnGUI()
    {
       if(custom_cursor!=null)
          cursor = MakeCustomCursor;
       else
           cursor = NormalCursor;
       cursor();
    }

    private void MakeCustomCursor()
    {
        float w,h;
        Texture2D cursor_texture;
        if( Input.GetMouseButton( 0 ) )
        {
            w = custom_cursor_on_click.width;
            h = custom_cursor_on_click.height;
            cursor_texture = custom_cursor_on_click;
        }
        else
        {
            w = custom_cursor.width;
            h = custom_cursor.height;
            cursor_texture = custom_cursor;
        }
        GUI.DrawTexture( new Rect( Event.current.mousePosition.x-(w/2), Event.current.mousePosition.y-(h/2), w, h), cursor_texture );
        Screen.showCursor = false;
    }

    private void NormalCursor()
    {
        Screen.showCursor = true;
    } 

}

Hello,

public Texture2D myCustomIcon;
    public Texture2D myCustomIconClicked;


/*
   ...
 */



public void OnGUI()
{
   if( AlphaButton( new Vector2( 50 , 50), myCustomIcon, myCustomIconClicked ) )
   {
      Debug.Log( " Click Marica!" );
   }
}



public static bool AlphaButton( Vector2 pos, Texture2D icon, Texture2D iconClicked )
{
   return AlphaButton( pos, icon, iconClicked, 0.5f );
}



public static bool AlphaButton( Vector2 pos, Texture2D icon, Texture2D iconClicked, float alphaThreshold )
{
   Rect iconRect;
   Vector2 relativeClick;

   iconRect = new Rect( pos.x, pos.y, icon.width, icon.height );

   if( Event.current.type == EventType.MouseDown  CheckRect( Event.current.mousePosition, iconRect ) )
   {
      relativeClick = new Vector2( Event.current.mousePosition.x - pos.x, Event.current.mousePosition.y - pos.y );

      if (icon.GetPixel((int)relativeClick.x, (int)relativeClick.y).a > alphaThreshold)
      {
         GUI.DrawTexture( iconRect, iconClicked );
         return true;
      }
   }

   GUI.DrawTexture( iconRect, icon );
   return false;
}



public static bool CheckRect( Vector2 point, Rect rect )
{
   return    point.x >= rect.x  point.x <= rect.x + rect.width 
         point.y >= rect.y  point.y <= rect.y + rect.height;
}
}

358738--12465--$propertybutton_110_101.png


Can you explain in some more detail? I'm not sure what you mean by that.

In my unity 3D editor show the alpha button, but when click it, doesn't show the click texture.

Should I modified some propierties of the texture???

358738--12465--$propertybutton_110_101.png

When the image imports, the texture will have an alpha channel if one was created for the file (say if you use a transparent background with Photoshop). If not, you can use the Generate Alpha From Grayscale option. This will set white areas to full opacity, black areas to full transparency and other pixels' alpha to the equivalent brightness level.

[quote=“anon_97456974”, post:10, topic: 384158]
In my unity 3D editor show the alpha button, but when click it, doesn’t show the click texture.

Should I modified some propierties of the texture???
[/quote]

Sorry for answering on a two year old thread but maybe for somebody else searching around for round buttons this reply could be useful. The above code does not show the clicked Icon texture long enough (it’s just drawn during the frame when the mouse click happens) or that was at least the case for me.

Replace Event.current.type == EventType.MouseDown with Input.GetMouseButton(0) and everything works like a charm (meaning as long as you hold down the left mouse button).

Not fully related to the original question but you can also add a hover on icon extending the AlphaButton function like this:

public static bool AlphaButton( Vector2 pos, Texture2D icon, Texture2D iconClicked, Texture2D iconHover, float alphaThreshold )
    {
        Rect iconRect;
        Vector2 relativeClick;
       
        iconRect = new Rect( pos.x, pos.y, icon.width, icon.height );
       
        if(CheckRect( Event.current.mousePosition, iconRect ) )
        {
            relativeClick = new Vector2( Event.current.mousePosition.x - pos.x, Event.current.mousePosition.y - pos.y );
           
            if( icon.GetPixel( (int)relativeClick.x, (int)relativeClick.y ).a > alphaThreshold )
            {
				GUI.DrawTexture( iconRect, iconHover );
				if(Input.GetMouseButton(0)) {
                	GUI.DrawTexture( iconRect, iconClicked );
				}
				return true;
            }
        }
       	
        GUI.DrawTexture( iconRect, icon, ScaleMode.ScaleToFit, true, 0 );
		return false;
    }