- Home /
Empty spaces in buttons are detected by mouse
Hello everyone! I have a button that has a texture. However the texture does not fill up the whole button. Thus if my mouse hovers the button but not the texture, the Button.Contains() is called right? My question is: how do I make it such that my function calls if the mouse hovers the textures but not the buttons). I think the picture below gives a better understanding of what I'm trying to say.
Pic:
My Code:
void OnGUI()
{
AbilityButtons();
}
void AbilityButtons()
{
if( buttonToBeDisplayed.Contains(Event.current.mousePosition))
{
// button pops out
buttonToBeDisplayed.Set( buttonToBeDisplayed.x + offset,
buttonToBeDisplayed.y,
buttonToBeDisplayed.width, buttonToBeDisplayed.height);
}
else
{
// button pops in
buttonToBeDisplayed.Set( buttonToBeDisplayed.x - offset,
buttonToBeDisplayed.y,
buttonToBeDisplayed.width, buttonToBeDisplayed.height);
}
//////////////////////////////////////////////////////////////////////
if( GUI.Button(buttonToBeDisplayed, textureToBeDisplayed))
{
ActivatePowers();
}
}
Answer by robertbu · Aug 17, 2013 at 01:30 AM
@alok1974's comments are on the mark. I don't know of a way to get the pixel color at the mouse position of a GUI button. You can implement the button as a texture on a plane in world space. Then the RaycastHit structure return by the Physics.Raycast() will contain a texture coordinate you can use to get the pixel color. Note the texture you get the pixel from does not have to be the texture you use for the button. You can create a mask texture with the same size that defines different areas of your button. You would read from mask texture so you would not have to deal with the shading issues of the real button. The mask can contain more than one color, so you can make different areas of the button trigger different things.
While @alok1974's suggestion of creating a mesh is a good one, all you really need is colliders in the right place.For the specific case of the image in your question, you could also implement it in world space, and use multiple colliders...a box collider for the square part and a sphere collider for the rounded part. A single game object can have multiple colliders as long as they are different types. It cannot have two of the same kind (two box colliders or two sphere colliders for example). But you can always kluge things together using empty child objects for colliders if you need more than one of a specific type.
I answered a question awhile about what you are trying to do, but I cannot find it. Here is an answer to a similar question with a script to get you started.
http://answers.unity3d.com/questions/49912/non-rectangular-buttons.html
I played a bit and came up with a example. Put the following two images in your Assets folder. Both need to be imported in a format that supports transparency, and the mask image needs to be read/write enabled:
Create a material using the buttons.png texture. The Unlit/Transparent shader would work well.
Create a vertical plane and attach the material.
Add the following script.
Drag and drop the buttons_mask texture onto the tex variable.
In the inspector, set the size of the color array to 6 and enter the following colors: (255,0,0), (0,255,0), (0,0,255), (255,255,0), (255,0,255), (0,0,255).
using UnityEngine; using System.Collections;
public class Buttons : $$anonymous$$onoBehaviour {
public Color[] colors; public Texture2D tex; void Update () { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Input.Get$$anonymous$$ouseButtonDown(0) && Physics.Raycast (ray, out hit) && hit.collider.name == "Buttons") { Color pixColor = tex.GetPixelBilinear(hit.textureCoord.x, hit.textureCoord.y); if (pixColor.a < 0.5f) { Debug.Log ("Hit an transparent area"); return; } for (int i = 0; i < colors.Length; i++) { Color c = (colors[i] - pixColor); Vector3 v = new Vector3(c.r,c.g,c.b); if (v.sqr$$anonymous$$agnitude < 0.1f) { Debug.Log ("Button " + i + " pressed"); } } } } }
You could do this using GUI by placing the texture in a box and using GetLastRect (or know the rectangle if you aren't using GUILayout) and then work out which coordinates to put into GetPixelBilinear by working out the current mouse position as a proportion of the width and height of that button rectangle.
@whydoidoit - nice idea.
@mh4 - here is a bit of sample code implementing the idea:
using UnityEngine;
using System.Collections;
public class Buttons2 : $$anonymous$$onoBehaviour {
public Color[] colors;
public Texture2D tex;
public Texture2D tex$$anonymous$$ask;
private Rect rect;
private float x = 150;
private float y = 125;
void Start() {
rect = new Rect(x,y, tex.width, tex.height);
}
void OnGUI() {
Event e = Event.current;
if (e.type == EventType.$$anonymous$$ouseDown && rect.Contains(e.mousePosition)) {
Debug.Log ("Inside");
Vector2 v2 = e.mousePosition;
v2.x -= x;
v2.y -= y;
float u = v2.x/rect.width;
float v = 1.0f - v2.y/rect.height;
Color pixColor = tex$$anonymous$$ask.GetPixelBilinear(u, v);
if (pixColor.a < 0.5f) {
Debug.Log ("Hit an transparent area");
return;
}
for (int i = 0; i < colors.Length; i++) {
Color c = (colors[i] - pixColor);
Vector3 v2b = new Vector3(c.r,c.g,c.b);
if (v2b.sqr$$anonymous$$agnitude < 0.1f) {
Debug.Log ("Button " + i + " pressed");
}
}
}
GUI.DrawTexture (rect, tex);
}
}
Answer by alok1974 · Aug 16, 2013 at 07:23 AM
I am very new to Unity and the awesome forum, but still, I will try to answer. It is possible that there may be better answers than mine but I will answer anyway.
So, the long-winded and hacky way (not even sure if this is possible) would be to query the pixel color of the texture at the mouse position. If it is green (as in your example) then trigger the event else return.
The easier and more efficient way is to create a mesh for the button having the shape of your texture. So if, for example, your button is a triangle, then make a mesh having the exact triangle shape as your texture using a 3D modeling app like max, maya, blender etc. Then apply your image as texture over this mesh. This way, the event is triggered only when the mouse is over the mesh and you do not have to change anything in your code.
I hope it is clear.
Good luck!
For the long winded way: What if the texture is an image and has multiple colors?
For the easier way: Hmm that sounds interesting but I dont know how to use $$anonymous$$aya, 3D $$anonymous$$ax etc. Lol. $$anonymous$$aybe I can ask a friend to help out with that and we'll see.
Thanks for the input though. Really appreciate it ^_^
For a newbie, Alok's answer is pretty accurate. Up-voted.
The implementation can be found on Robertbu's answer.
Your answer
Follow this Question
Related Questions
Making texture cover whole button 1 Answer
Assiging an Image to a Button 1 Answer
Make more buttons appear, on button click. 1 Answer
Update Texture type to GUI during runtime 1 Answer
Null reference exception[SOLVED] 1 Answer