Empty Rect to catch clicks?

What’s the best way to build an empty, invisible rect that still catches clicks? So far I’ve been using the TEXT component without anything in it, just to get the click callbacks, but that seems terrible. Is there a better way?

Empty Image? :slight_smile:

Is it any better? :slight_smile:

or use some class that derives from Graphic class, and implements some of click interfaces.

I’ve just used empty images.

Hard to say, i’d probably go with a Button without the Image component.
Does ‘best’ mean, when it gives you the best performance or when it’s the easiest to use?

Trav3l3r:

Image is enough, if you add Image, you add Image component, if you add Button, You add Image and Button… when only Image component is needed to capture clicks.

If using custom script you only add your script, no need for Image component then.

Whether or not a UI-object captures clicks depends on the “Raycast Target” option in the component.

The bare minimum you need is a RectTransform, An graphic based component, a Script implementing the pointer handler events you want to trap.
The base event system uses the graphical raycaster which needs an image to “bounce” off, although the image can be blank. Using the Text component is a cool idea as it doesn’t show anything by default.
But if you created your own component inheriting from Graphic (or MaskableGraphic) you could achieve the same thing (and even have your event handlers in the same script)

Hmm, might just test/play with that.

OK, had a play and created this script, it doesn’t require any other components other than a RectTransform and be a child of a Canvas:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class EmptyClicker : Graphic, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("You clicked the magic box");
    }
   
    protected override void Awake()
    {
        this.color = new Color(0,0,0,0);
    }
}

Acts as an empty area to click on. Don’t really need the awake function if you configure the colour of the image in the editor.

*Note
Remember though, this will block any clicks passing through the RectTransform area, so anything behind it (higher in the hierarchy) will not be interactable. But I’m sure everyone here already knows that :smile:

Would be interesting to pair this up with either the new clipping framework or a shapable mask to control where in the rect you can click. Or possibly have a click-test against an image/spec to further refine the clickable area.

3 Likes

That’s pretty neat

1 Like

You should see what I’m trying to work up for the next UI extensions update :stuck_out_tongue:

1 Like

I just viewed some of your latest videos on Youtube. Your project looks really nice and very useful, too. :slight_smile:

1 Like

Thanks @Trav3l3r it’s a project of passion unifying all the good UI components I can find, whipping them up in to a unified library, then ading my own controls.
Plus all the packaging / recording and tutorials on it all :smile:

Unfortunately that’s still a draw call. :confused: I’ve been wondering what would be the best way to create modal dialogs where you prevent clicking outside the object. On mobile it’s not optimal to use a full screen graphic for that, since it’s drawn even with 0 alpha and fillrate is the bottleneck.

Everything is a draw call, even an empty rect, this is because everything in the UI system resolved down to a quad on the Canvas. (else interactivity won’t work as it’s based on Raycasts)
If you want reaction without a draw call, then you’ll have to use the physics raycasters but that will involve a whole heap of more work lining it up where you want it to interact.

The draw calls for empties should be batched however so it shouldn’t be to big of a hit

An empty rect is not a draw call but an empty graphic is. It’s not the extra draw call that’s the problem either, it’s fill rate on mobile, since AFAIK even “empty” graphics with 0 alpha are drawn.

1 Like

@iivo_k - Hi, if what I suggested to OP is not good enough, I was thinking about this (simple solution) - how about using just RectTransformUtility?

Figure out if user is inside your panel rectangle and use that info, for example keeping list of other button etc Image components, and disable raycast on them or something else when popup is active.

It would be not using EventSystem at all, no Image/Graphic component needed, however you’d have to check it in some Update method.

Even CanvasGroup needs Graphic component to block clicks. But I just wonder is it really so expensive to render empty Image panel that is screen size. I have to admit I’ve got no idea if it wastes fill rate.

You could write your own Input module that handles this functionality. It is the input module that does the actual ray casting, you could create a system that doesn’t use ray casting and only check if the pointer is inside the RectTransform. Kinda reinventing the wheel, but allows for more flexibility.

I have an even simpler empty rect, that takes clicks and is less performanec intensive than using empty text:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class EmptyGraphic : Graphic
{
        protected override void OnPopulateMesh (VertexHelper vh)
        {
                vh.Clear ();
        }
}
4 Likes

Hey, that’s actually quite neat! I too have been trying to find a way to have empty blocker objects that catch clicks but do not consume fillrate for ages. Seems like this trick works, thanks!

@mh114 : hi, and If I may ask, how is this any different than what is already mentioned above?

“use some class that derives from Graphic class and implements some of click interfaces” or Simon’s spelled out version? Actually it is the same solution, and Simon’s code is almost 1:1 what I refered to.

(I expect that you did read all the posts - sorry if not!)

AFAIK for this to work, if class is derived from Graphic, then it has to have canvas renderer, so it has a fill (which, you of course can make transparent) but it still renders something I think?

Like I mentioned, I’ve used Image component as a lazy person solution as you anyway have to have filled rect, so it’s quite the same as having Image component, but a little bit less overhead, because Image is derived from Graphic class…

or is there some difference I missed?

But that is indeed the trick here; even though Graphic requires canvas renderer, that custom empty graphic doesn’t output any vertices, hence nothing gets rendered. It is the best solution so far and I’m beating myself for not figuring it out myself! :slight_smile:

EDIT: And to clarify why this matters: on mobile you want to avoid overdraw as much as you can, especially on devices like iPhone 4 which have way too high resolution for their shitty GPUs to handle. And when you have fullscreen “empty” quad covering the whole screen, you’re introducing yet more overdraw for every single pixel! On fill-rate limited devices you’ll see the FPS plummet when you do this. For PC-like platforms it doesn’t really matter that much.

1 Like