- Home /
How to stop non-rectangular buttons from overlapping?
I'm trying to figure out how to use Unity's new UI system, and I've run into a problem. It seems that it only allows rectangles to be buttons.
What I want to do is have a circle sliced into 7 parts, where each part is clickable (see image). However, when I attempt this, the rectangle of the button of one slice overlap the images of other slices.
Is there any way to fix this using the UI system of Unity?
You should do a mouseover to check which image is Actually underneath the mouse, and then just lock that Option of THAT image as the only one that can be clicked, thus ignoring any overlap. Hope that helps
I do not understand what you're telling me. How do you do a mouseover check in Unity UI?
Answer by troien · Jan 23, 2015 at 10:28 AM
For some reason (don't ask me why) the faq of Unity UI is almost unknown to google, while it has a lot of information that is rather usefull :p
For you, this part is something I think you are looking for:
How do I make UI elements have non-rectangular hitboxes?
Add a component that implements ICanvasRaycastFilter. In your implementation of IsRaycastLocationValid, reject all points that are 'outside' your custom hitbox shape. It's up to you how you want to do that, but for example for a circular hitbox you could measure the distance between the point and your object's center and reject the point if that distance is greater than your circle's radius. Or perhaps you could look up the alpha value of the pixel the hit is on, as per this script by senritsu.
Sadly, the link over there is broken :( However, using google I was able to find this...
Forum post: http://forum.unity3d.com/threads/none-rectangle-shaped-button.263684
Download link: http://forum.unity3d.com/attachments/raycastmask-cs.110370/
I have no clue what the linked code says, but it works. Thanks a lot for your googling skills :)
This is what I used too. Too bad Unity didn't bother documenting IRaycastFilter
Answer by miguelSantirso · Jun 06, 2015 at 04:38 PM
I found another (probably better) solution for this problem. I used a Collider2D (PolygonCollider2D) to define the clickable shape and then used this RaycastFilter:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent (typeof (RectTransform), typeof (Collider2D))]
public class Collider2DRaycastFilter : MonoBehaviour, ICanvasRaycastFilter
{
Collider2D myCollider;
RectTransform rectTransform;
void Awake ()
{
myCollider = GetComponent<Collider2D>();
rectTransform = GetComponent<RectTransform>();
}
#region ICanvasRaycastFilter implementation
public bool IsRaycastLocationValid (Vector2 screenPos, Camera eventCamera)
{
var worldPoint = Vector3.zero;
var isInside = RectTransformUtility.ScreenPointToWorldPointInRectangle(
rectTransform,
screenPos,
eventCamera,
out worldPoint
);
if (isInside)
isInside = myCollider.OverlapPoint(worldPoint);
return isInside;
}
#endregion
}
Using a collider for this is a bit hacky but the result is much simpler, probably faster and makes it much easier to adjust the clickable shape.
This could be improved by creating a custom alternative to replace the Collider2D but that's a bit too much work for what I need.
Thanks for this little gem. To make use of this script:
Create a new script and paste in this content.
Add a 2d collider component to your game object
Add the script to the game object
Would be great if Unity just changed the way the hit box functioned based on if there is a 2d collider component on your button.
Thanks for the filter.
I think this is the best way to archive this kind of purposes.
This script is awesome. Simple but accomplishes the task perfectly! Thank you so much!!
Answer by rob5300 · Jan 22, 2015 at 09:55 PM
The only way i can think that you can do this is by not using the new UI and using a system of another camera, and Sprites which have custom scripts to detect clicks and hovers using OnMouseOver and OnMouseDown. (Make sure the sprites have 2d colliders too!
Soo for example:
using System.Collections;
using UnityEngine;
public class Example : MonoBehaviour {
//This may or may not work, this is just to illustrate.
public Color MouseOverColor;
public Sprite sprite;
private Color startColor;
void Start(){
startColor = sprite.color;
}
void OnMouseOver(){
//For example change the button color when moused over
sprite.color = MouseOverColor;
}
void OnMouseExit(){
//To revert the color on the mouse exiting.
sprite.color = oldColor;
}
void OnMouseUpAsButton(){
//This is called when the mouse is released over the same
//collider as it was pressed on, great for buttons.
DoThing();
}
}
This would work using raycasting, yea? (thanks for your reply btw)
No problem! And Yep, i gave the examples of using the mouse events in case you didn't wish to use raycasting. You may have to use Physics2D.Raycast for 2d sprite colliders, but try the normal one first!
Hi can you give more details about the mouse actions? Thanks
@jniris I would recommend you writing a new question and provide some more details about what actions you want to know about therein. Or, alternatively, try making a forum post if you can't think of a way to make your question more specific. UnityAnswers is more of a "I have a problem, please give me a solution"-kind of site.
Answer by menehune23 · Oct 19, 2015 at 10:43 AM
I recently came across this and found the answers here on this forum to be a great starting point! I consolidated and updated the info into a concise blog post: