0
\$\begingroup\$

I'm trying to make a "highlight frame," like a flashing box around a button for use in the game's tutorial. When the frame is tapped, I'd like it to register the tap (so the frame can be dismissed) but ALSO allow the button underneath to register the same tap (so that button's action is triggered.)

Is this possible? For a button to "detect a raycast without blocking a raycast," or something similar?

I could just have the button's action dismiss any highlight frames that exist, but that would entail putting "dismiss frame if exists" statements all over the place in my code. It would be much neater just to have the frame be a button which dismisses itself, without blocking the interaction with whatever it's highlighting.

Is there a way to accomplish this?

\$\endgroup\$
3
  • \$\begingroup\$ It sounds like what you really want to ask is "How to dismiss a button highlight frame when the player clicks the button?". Making the highlight into its own button that somehow passes the tap through to the button below is one conceivable way to achieve this, but it might not be the simplest way. Other options could include adding the frame as a non raycast target (so it doesn't block access to the button below) and wiring up the dismiss action to the underlying button's own click event as a separate listener, so you don't need the if statements all over as you describe. \$\endgroup\$
    – DMGregory
    Aug 7 '19 at 20:25
  • \$\begingroup\$ @DMGregory That's what I described in the third paragraph, but it would be a big pain. The highlight frame is used throughout the tutorial, so we'd need to add dismiss actions to every button that is ever highlighted, but then also add logic to make sure tapping ButtonA doesn't dismiss a highlight frame over ButtonB, etc. It would be MUCH cleaner to have the highlight frame be a self-contained thing that detects taps within it, but without blocking taps to the highlighted object. \$\endgroup\$
    – Nerrolken
    Aug 7 '19 at 21:03
  • \$\begingroup\$ could you raycast twice, and on one use a layermask for the object that is blocking it ?? \$\endgroup\$ Aug 7 '19 at 21:05
0
\$\begingroup\$

As I mentioned in the comment, I think you can do better by not trying to intercept the player's click on the original button, but instead just react to the original button itself being clicked.

We can do this while maintaining the highlight's self-containment, by giving it a script like this:

using UnityEngine.UI;
using UnityEngine.Events;

public class ButtonHighlight : MonoBehaviour {

    // Point this at the button that you want to highlight & react to.
    public Button targetButton;

    // Optionally, you can use an event to fire the next beat in the tutorial sequence.
    public UnityEvent onHighlightDismissed;

    void OnEnable() {
        // Subscribe to the target button's click.
        targetButton.onClick.AddListener(OnTargetButtonClicked);
        // Trigger any in transition or animation here.
    }

    void OnTargetButtonClicked() {
        targetButton.onClick.RemoveListener(OnTargetButtonClicked);
        // Trigger any out transition or animation here.
        // This can be done in a coroutine to wait before turning off the highlight.
        gameObject.SetActive(false);

        // Trigger the next stage of the tutorial, if any.
        if(onHighlightDismissed != null)
            onHighlightDismissed.Invoke();
    }
}

Zero changes need to be made to the code of the buttons you're interacting with. We just eavesdrop on their existing click events, using an object that is not itself a raycast target, and clean up after ourselves once the player has clicked as desired.

We get several advantages from this approach:

  • It more closely matches the intention of the feature:

    • "Hide the highlight when the player clicks the original button"

      instead of

    • "Hide the highlight when the player clicks this spoof button and then pretend the player clicked the original button"


    This means we have fewer opportunities for the effect of the code to deviate from what we meant it to do.

    With the latter style, we have to keep the spoof button carefully matched to the original - any change to one without the other risks breaking the link, so for example the player could click on the intended button and miss the highlight, leading to an invalid state where the player has clicked the button but the tutorial is still telling them to click it.

  • We get all the normal hover / keyboard interactions of the underlying button (including tab ordering) "for free" - no extra fakery or edge cases to deal with. Your interface still works identically whether the highlight is present or not, reads the same to screen readers, etc., because we haven't interfered with the interaction logic at all.

  • We're free to style the highlight however we want. It doesn't have to exactly match the shape and size of the source button, or be any specific type of object - it could be an arrow pointing at it from outside its bounds, or a particle system of sparkles showering around it, or a skinned mesh of a character grabbing the button... your visual styling is completely decoupled from the logic of "show this until the player clicks this button"

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.