Sprite Object Shape question

So this may be a dumb question… but I figured I’d ask this here first…

Is there a way to change the shape of touch/hit detection on a sprite? For example… say I am creating a button and I use a circle as the sprite graphic… So, I basically have an invisible square (the sprite container) with my circle inside. While my circle fills up most of the sprite container, the corners of the container do not contain any pixels from the circle. However, because the actual sprite object is a square, if I click the corners of the sprite object it will register as me clicking the circular button… even though my mouse is not technically touching the pixels of the circle… this is problematic for certain games… for example, casino games in which real money is being wagered… the laws where I am located state that the button should not be clickable outside of the button graphic… in case someone accidentally clicks the button and spends money they didnt mean to spend… so basically… is there a way that I can create a circular button that will not register an event unless the actual pixels of the circle graphic are clicked?

Does this make sense or am I confusing the heck out of you wonderful people? lol

It’s actually a very good question.

Simple fact: hitTest of UITransform is only detecting for its rectangle region (x, y, width, height)

What you want to do is a pixel precise hit test, while it’s not naturally available, but we do have another component Mask that can help you achieve the trick. If you nest the button into a circle Mask (graphics stencil), then it will only be clickable inside the mask.

The solution can be used without problem if there is only a very limited number of Mask on the screen, because Mask could cause performance issue, so you should be aware of the cost.

The reason we haven’t support pixel precise detection is also performance consideration, reading pixel value at runtime is also very expensive.

You, sir, are a saint! I had tried the mask method already with no luck… but you mentioning it here pushed me to go try it some more… actually, I still had no luck using the graphic stencil… but the graphic ellipse did the trick perfectly! You saved me so much time! I was about to have to start checking pixels for alpha values…

I was thinking about a less expensive way to accommodate circular buttons that could potentially be added to cocos natively… I realize the button component event system needs a node for the target because the event system works on Nodes… but I wonder if there is a way to set it up where the user has an option to choose between a node or a collider… a circle collider 2d would give users a visual way to size the circle to their button perfectly… and it seems like code could be written to essentially create an invisible collision at the position of the mouse click and then have that trigger an event… curious to know your thoughts?

Using collider would require raycast, it’s indeed another way to interact, but it’s not related to 2D UI, 2D UI is simply based on node event system. The feature you are suggesting is actually what we will implement in 3D UI.

do we not have the ability to get the mouse position coordinates on mouse click without raycasting? Seems like we could grab those coordinates and then create an object at those coordinates to trigger collision with a 2dcollider component and have the collision trigger the function our button normally would? It may not be conventional… but it seems like it could work?

But I can understand why you wouldn’t want to implement that in your UI system as it’s pretty far outside the box… maybe we will try it at our studio. If it works then we can use it… :slight_smile:

also, it probably wouldn’t be a good solution for someone making a game that uses a bunch of collision objects as clicking on a collidable object would cause it to trigger. In our case, our game has no collision objects so this option would suit our needs just fine… but I can definitely see why it wouldn’t be a good fit for native cocos feature… I reckon it could be tweaked to still work easily enough… but by that time, you might as well just use the mask method.

Yes, you can use Input Event System for that matter

1 Like