-3
\$\begingroup\$

I need a triple click detection on my 2d game.

I have a Canvas with a fire button inside and I'm searching a way to trigger 3 different actions on the player's script when I press this button once, twice, or three times.

There's a similar question about detecting double-clicks in Unity, but it wasn't clear which of the seven different answers would be appropriate for this situation, or how to extend them to handle three clicks.

\$\endgroup\$
3
  • 4
    \$\begingroup\$ The implementation is almost identical to 2 clicks. I would recommend learning some basic programming logic before making games, it's much easier than trying to piece things together from the internet. \$\endgroup\$
    – Kroltan
    Commented Nov 12, 2016 at 14:18
  • \$\begingroup\$ I don't think this is a bad question to ask. Here on GD.SE, our question about implementing double-clicks in Unity has no accepted answer and a wide array of very different suggestions, so I can understand someone new to the problem feeling disoriented. We answer some variation on basic vector math just about every week, so I think it's reasonable to answer this variation on a core input feature. \$\endgroup\$
    – DMGregory
    Commented Nov 12, 2016 at 16:13
  • \$\begingroup\$ Yes, basically I'm disoriented. I'm absolutely a begginer to proggramming world and I'm learning a lot with this great and amazing site. Of course, I not only "piece things", on this project I only used internet as a guide, and OF COURSE i learned the basics of the object-oriented programming..thank you for the comments!! \$\endgroup\$
    – Jordi4321
    Commented Nov 12, 2016 at 17:44

1 Answer 1

3
\$\begingroup\$

The basic strategy here is to set up our script to remember it was clicked (some number of times), but delay acting on that information for a short period of time, in case another click immediately follows.

For UI elements in a Canvas, the most robust method is probably to use a variation on Norb's answer for the double-click case. This leverages the Unity UI event system to give a lot of flexibility.

For this, we put a custom ClickController script on each UI object we want to be able to react to multiple click types - make sure they have their "Raycast Target" box checked so they're visible to mouse events:

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using System.Collections;

public class ClickController : MonoBehaviour
{
    // Configure how we listen for clicks (how fast, which button).

    [Tooltip("Seconds after each click to wait for a follow-up")]
    public float timeLimit = 0.25f;

    [Tooltip("Which mouse/stylus button to react to")]
    public PointerEventData.InputButton button;

    // Expose events we can wire-up in the inspector to our desired handlers.

    // I added this so we can use it to show visible feedback immediately
    // on the first click, to minimize perceived latency.        
    public UnityEvent onAtLeastOneClick;    
    
    public UnityEvent onSingleClick;        
    
    public UnityEvent onDoubleClick;

    public UnityEvent onTripleClick;

    // Internal state for keeping track of clicks.

    private int clickCount;
    private Coroutine delayedClick;

    // Auto-configure on Start.
    // I added this to reduce fiddly inspector setup - we'll use an existing
    // EventTrigger component if it's there, or add one & wire it up if not.
    void Start()
    {
        EventTrigger trigger = GetComponent<EventTrigger>();
        if (trigger == null)
            trigger = gameObject.AddComponent<EventTrigger>();

        var entry = new EventTrigger.Entry();
        entry.eventID = EventTriggerType.PointerClick;
        entry.callback.AddListener(onClick);

        trigger.triggers.Add(entry);
    }

    // Main click handler - this is where the magic happens.
    public void onClick(BaseEventData data)
    {
        PointerEventData pointerData = data as PointerEventData;

        // Ignore clicks on buttons we're not watching.
        if (this.button != pointerData.button)
            return;

        // Count up the clicks.
        clickCount++;

        // React accordingly.
        switch(clickCount)
        {
            // First click: fire OnAtLeastOneClick and wait to see if a second comes in.
            case 1:
                delayedClick = StartCoroutine(DelayClick(onSingleClick, timeLimit));
                onAtLeastOneClick.Invoke();
                break;
            // Second click: cancel single-click and wait to see if a third comes in.
            case 2:
                StopCoroutine(delayedClick);
                delayedClick = StartCoroutine(DelayClick(onDoubleClick, timeLimit));
                break;
            // Third click: cancel double-click fire OnTripleClick immediately.
            case 3:
                StopCoroutine(delayedClick);
                delayedClick = null;
                onTripleClick.Invoke();
                clickCount = 0;
                break;
        }
    }

    // This handles firing off the click after a delay.
    // We cancel it if a new click comes in sooner.
    private IEnumerator DelayClick(UnityEvent clickEvent, float delay)
    {
        yield return new WaitForSeconds(delay);
        // This coroutine didn't get stopped, so no new click came in.
        // Fire off the corresponding click event and reset.
        clickEvent.Invoke();
        clickCount = 0;
        delayedClick = null;
    }
}

The script looks like this when attached, with four events you can link-up to call public methods on any component in your scene:

Example of this script's interface in the Unity Inspector

As described in the comments above, I added the OnAtLeastOneClick method so we have something we can call right away as soon as the player interacts (triggering this OnPress would also work if you need it even sooner). Firing off some visual and audio feedback at that moment can help cover the waiting period for the next click to come in, helping the interaction feel snappy & responsive. Since at this moment we don't yet know whether this will be a single-, double-, or triple-click, the feedback has to work for all three, and more specialized feedback can be triggered a fraction of a second later once we know for sure what input action we're dealing with.

\$\endgroup\$
1
  • \$\begingroup\$ OH MY GOD!! This is incredible, BIG answer, really great. I think this answer may be useful for many people because I searched on the web during hours and I can't saw one "compresible" answer for me...all the tips I found confused me a lot, or I searched with bad words, I don't know. And I can understand the script, with the programming job when I see the code I can understand it, but create one from 0 is very very difficult for me with my level...I need examples to get ideas...THANK YOU!!!! \$\endgroup\$
    – Jordi4321
    Commented Nov 12, 2016 at 18:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .