एकल # क्लिक को ठीक से कैसे अलग करें और C # का उपयोग करके Unity3D में डबल-क्लिक करें?


15

यहाँ जो मैं समझने और जानने की कोशिश कर रहा हूँ, वह एक बहुत ही बुनियादी बात है: C # का उपयोग करते हुए, एकता में 3 मुख्य माउस बटन के लिए सिंगल-क्लिक और डबल-क्लिक को ठीक से अलग करने का सबसे सामान्य और सबसे पॉलिश तरीका क्या है ?

ठीक से शब्द पर मेरा जोर कुछ नहीं के लिए है। हालांकि मुझे आश्चर्य था कि ऐसा लगता है कि इस वेबसाइट में पहले कभी नहीं पूछा गया था, बेशक मैंने यूनिटी के मंचों और यूनिटी के स्वयं के प्रश्न-उत्तर पृष्ठों पर कई समान प्रश्न खोजे और पाए हैं। हालांकि, जैसा कि अक्सर इन संसाधनों में पोस्ट किए गए उत्तरों के साथ होता है, वे सभी या तो सादे गलत लग रहे थे या कम से कम थोड़ा बहुत शौकिया थे।

मुझे समझाने दो। प्रस्तावित समाधान हमेशा दो दृष्टिकोणों और उनके संगत दोषों में से एक थे:

  1. हर बार एक क्लिक होता है, अंतिम क्लिक के बाद से समय डेल्टा की गणना करें और यदि यह किसी दिए गए सीमा से छोटा था, तो डबल क्लिक का पता लगाया जाएगा। हालाँकि, इस समाधान के परिणामस्वरूप डबल क्लिक का पता चलने से पहले एक त्वरित सिंगल क्लिक का पता लगाया जाता है, जो अधिकांश स्थितियों में अवांछनीय होता है क्योंकि तब यह सिंगल और डबल क्लिक दोनों क्रियाओं को सक्रिय करता है।

किसी न किसी उदाहरण:

float dclick_threshold = 0.25f;
double timerdclick = 0;

if (Input.GetMouseButtonDown(0) 
{
   if (Time.time - timerdclick) > dclick_threshold)
   {
       Debug.Log("single click");
       //call the SingleClick() function, not shown
   } else {
       Debug.Log("double click");
       //call the DoubleClick() function, not shown
   }
   timerdclick = Time.time;
}
  1. सक्रिय होने के लिए सिंगल-क्लिक में देरी के लिए सेट करें, जिसका अर्थ है, प्रत्येक क्लिक पर, केवल एक क्लिक क्रिया को सक्रिय करें यदि अंतिम क्लिक के बाद का समय देरी किसी दिए गए सीमा से ऊपर है। हालाँकि, यह सुस्त परिणाम देता है, क्योंकि एकल-क्लिक का पता लगाने से पहले प्रतीक्षा को नोटिस करना संभव है। इससे भी बदतर, इस तरह का समाधान मशीनों में विसंगतियों से ग्रस्त है, क्योंकि यह इस बात पर ध्यान नहीं देता है कि ओएस स्तर पर उपयोगकर्ता की डबल-क्लिक गति सेटिंग कितनी धीमी या तेज़ है।

किसी न किसी उदाहरण:

   float one_click = false;
   float dclick_threshold = 0.25f;
   double timerdclick = 0;

   if (one_click && ((Time.time - timerdclick) > dclick_threshold))
   {
       Debug.Log("single click");
       //call the SingleClick() function, not shown
       one_click = false;
   }

   if (Input.GetMouseButtonDown(0))
   {

       if (!one_click)
       {
           dclick = -1;
           timerdclick = Time.time;
           one_click = true;
       }

       else if (one_click && ((Time.time - timerdclick) < dclick_threshold))
       {
           Debug.Log("double click");
           //call the DoubleClick() function, not shown
           one_click = false;
       }

   }

इसलिए, मेरे प्रश्न निम्नलिखित हैं। क्या इन समाधानों के अलावा, C # का उपयोग करते हुए एकता में दोहरे क्लिकों का पता लगाने का एक अधिक पॉलिश और विश्वसनीय तरीका है, और एक जो उपरोक्त समस्याओं को संभालता है?


हम्म। दो-क्लिकों का सही तरीके से पता लगाने के बारे में ... मैं केवल यह सोच सकता हूं कि मैं इसे करने के बारे में कैसे जाऊंगा, जो कि शायद कम शौकिया नहीं है।
Draco18s अब SE

2
मुझे नहीं लगता कि आप किसी भी बेहतर क्लिक का पता लगा सकते हैं - आप उपयोगकर्ता शारीरिक कार्रवाई के परिणामों की भविष्यवाणी नहीं कर सकते। मैं अपने GUI और यांत्रिकी को डिजाइन करने पर ध्यान केंद्रित करूंगा ताकि ट्रिगर किए गए कार्य इस तथ्य को छिपा सकें जितना वे कर सकते हैं। * ठीक है, सिद्धांत रूप में, आप कुछ AI का उपयोग कर व्यवहार का विश्लेषण कर सकते हैं, लेकिन परिणाम सुसंगत नहीं होंगे
wondra 23

1
उत्तर 1 का उल्लेख करते हुए, "हालांकि, इस समाधान के परिणामस्वरूप डबल क्लिक करने का पता चलने से पहले एक त्वरित सिंगल क्लिक का पता चलता है, जो अवांछनीय है।" मैं वास्तव में नहीं देखता कि तुम क्या देख रहे हो। यदि इस समाधान के साथ कोई समस्या है, तो मुझे लगता है कि यह गेम मैकेनिक है जिसे ट्विकिंग की आवश्यकता है। उदाहरण के लिए एक आरटीएस लें। आप इसे चुनने के लिए एक यूनिट पर क्लिक करते हैं (ए), अन्य सभी इकाइयों (एक्शन बी) को चुनने के लिए डबल क्लिक करें। यदि आप डबल क्लिक करते हैं, तो आप केवल एक्शन बी नहीं चाहते हैं, आप ए और बी दोनों चाहते हैं। यदि आप पूरी तरह से अलग होना चाहते हैं, तो यह राइट क्लिक, या ctrl + क्लिक, आदि होना चाहिए
पीटर

जवाबों:


13

Coroutines मज़ेदार हैं:

using UnityEngine;
using System.Collections;

public class DoubleClickTest : MonoBehaviour 
{
private float doubleClickTimeLimit = 0.25f;

protected void Start()
{
    StartCoroutine(InputListener());
}

// Update is called once per frame
private IEnumerator InputListener() 
{
    while(enabled)
    { //Run as long as this is activ

        if(Input.GetMouseButtonDown(0))
            yield return ClickEvent();

        yield return null;
    }
}

private IEnumerator ClickEvent()
{
    //pause a frame so you don't pick up the same mouse down event.
    yield return new WaitForEndOfFrame();

    float count = 0f;
    while(count < doubleClickTimeLimit)
    {
        if(Input.GetMouseButtonDown(0))
        {
            DoubleClick();
            yield break;
        }
        count += Time.deltaTime;// increment counter by change in time between frames
        yield return null; // wait for the next frame
    }
    SingleClick();
}


private void SingleClick()
{
    Debug.Log("Single Click");
}

private void DoubleClick()
{
    Debug.Log("Double Click");
}

}

व्यक्तिगत बटन दबाए जाने पर यह पता नहीं लगता है; बस जब स्क्रीन पर क्लिक किया जाता है या सामान्य रूप से डबल क्लिक किया जाता है (हालांकि ओपी ने अनुरोध नहीं किया था, इसलिए यह इतना पूछना उचित नहीं है)। कोई सुझाव है कि कैसे एक कर सकता है?
zavtra

मैं यह नहीं देखता कि यह प्रश्न में प्रस्तावित दूसरी विधि से कैसे भिन्न है।
जॉन हैमिल्टन

5

मैं अंग्रेजी नहीं पढ़ सकता। लेकिन UniRx आपकी मदद करने में सक्षम हो सकता है।

https://github.com/neuecc/UniRx#introduction

void Start () {

    var clickStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0));
    var bufferStream = clickStream.Buffer (clickStream.Throttle (TimeSpan.FromMilliseconds (250))).Publish ().RefCount ();
    bufferStream.Where (xs => xs.Count == 1).Subscribe (_ => Debug.Log ("single click"));
    bufferStream.Where (xs => xs.Count >= 2).Subscribe (_ => Debug.Log ("double click"));
}

यह काम करता है, लेकिन विंडोज में डबल क्लिक की तरह लागू नहीं होता है। जब आप क्लिक करते हैं, उदाहरण के लिए, एक पंक्ति में 6 बार, केवल एक डबल क्लिक का उत्पादन होता है। विंडोज में, यह 3 डबल क्लिक होगा। आप में कोशिश कर सकते हैं Control Panel → Mouse
मैक्सिम कमालोव

2

विंडोज डिफ़ॉल्ट डबल क्लिक देरी 500ms = 0.5 सेकंड है।

आम तौर पर एक गेम में नियंत्रण पर डबल क्लिक को संभालना बहुत आसान होता है जिसे विश्व स्तर पर नहीं, क्लिक किया जा रहा है। यदि आप विश्व स्तर पर दोहरे क्लिक को संभालने का निर्णय लेते हैं, तो आपको 2 बहुत ही अवांछनीय दुष्प्रभावों से बचने के लिए वर्कअराउंड को लागू करना होगा:

  1. हर एक क्लिक में 0.5 सेकंड की देरी हो सकती है।
  2. एक नियंत्रण पर एक क्लिक के बाद एक और नियंत्रण पर एक क्लिक के तुरंत बाद दूसरे नियंत्रण पर डबल-क्लिक के रूप में गलत व्याख्या की जा सकती है।

यदि आपको एक वैश्विक कार्यान्वयन का उपयोग करना है, तो आपको क्लिक के स्थान को भी देखना होगा - यदि माउस बहुत दूर चला गया तो यह डबल क्लिक नहीं है। आप सामान्य रूप से फ़ोकस ट्रैकर लागू करेंगे जो फ़ोकस बदलने पर डबल क्लिक काउंटर को रीसेट करता है।

इस सवाल पर कि क्या आपको तब तक इंतजार करना चाहिए जब तक डबल-क्लिक टाइमआउट पास न हो जाए, इसके लिए प्रत्येक नियंत्रण के लिए अलग तरीके से काम करने की आवश्यकता होती है। आपके 4 कार्यक्रम हैं:

  1. होवर करें।
  2. सिंगल क्लिक, जो डबल क्लिक हो भी सकता है और नहीं भी।
  3. डबल क्लिक करें।
  4. डबल क्लिक टाइमआउट, सिंगल क्लिक डबल नहीं होने की पुष्टि की गई।

जब भी संभव हो, आप GUI इंटरैक्शन को डिज़ाइन करने का प्रयास करें, जैसे कि अंतिम ईवेंट का उपयोग नहीं किया जाएगा: Windows फ़ाइल एक्सप्लोरर एक क्लिक पर तुरंत एक आइटम का चयन करेगा, और इसे एक डबल क्लिक पर खोल देगा, और एक पुष्ट सिंगल पर कुछ भी नहीं करेगा पर क्लिक करें।

दूसरे शब्दों में: आप अपने सुझाए गए दोनों विकल्पों का उपयोग करते हैं, इस पर निर्भर करता है कि नियंत्रण का वांछित व्यवहार क्या है।


2

उपरोक्त समाधान पूरी स्क्रीन पर किए गए क्लिक के लिए काम करते हैं। यदि आप व्यक्तिगत बटनों पर डबल-क्लिक का पता लगाना चाहते हैं, तो मैंने पाया है कि उपरोक्त उत्तर के लिए यह संशोधन ठीक काम कर रहा है:

using UnityEngine;
using System.Collections;

public class DoubleClickTest : MonoBehaviour
{
    private float doubleClickTimeLimit = 0.35f;
    bool clickedOnce = false;
    public string singleTapMove;
    public string doubleTapMove;
    float count = 0f;

    public void startClick(){
        StartCoroutine (ClickEvent ());
    }

    public IEnumerator ClickEvent()
    {
        if (!clickedOnce && count < doubleClickTimeLimit) {
            clickedOnce = true;
        } else {
            clickedOnce = false;
            yield break;  //If the button is pressed twice, don't allow the second function call to fully execute.
        }
        yield return new WaitForEndOfFrame();

        while(count < doubleClickTimeLimit)
        {
            if(!clickedOnce)
            {
                DoubleClick();
                count = 0f;
                clickedOnce = false;
                yield break;
            }
            count += Time.deltaTime;// increment counter by change in time between frames
            yield return null; // wait for the next frame
        }
        SingleClick();
        count = 0f;
        clickedOnce = false;
    }
    private void SingleClick()
    {
        Debug.Log("Single Click");
    }

    private void DoubleClick()
    {
        Debug.Log("Double Click");
    }
}

इस स्क्रिप्ट को जितने चाहें उतने बटन संलग्न करें। फिर संपादक के ऑन क्लिक सेक्शन में (प्रत्येक बटन के लिए जिसे आप इसे संलग्न करते हैं), '+' पर क्लिक करें, गेम ऑब्जेक्ट के रूप में खुद को बटन जोड़ें, और फिर कॉल करने के लिए फ़ंक्शन के रूप में "DoubleClickTest -> startClick () 'का चयन करें। जब बटन दबाया जाता है।


1

मैं एक उचित सिंगल-डबल क्लिक हैंडलर की तलाश में था। मैंने इस विषय को पाया है और कुछ अच्छे विचारों को एकत्रित किया है। तो अंत में मैं निम्नलिखित समाधान के साथ आया हूं और मैं इसे आपके साथ साझा करना चाहता हूं। मुझे उम्मीद है कि आपको यह तरीका मददगार लगेगा।

मुझे लगता है कि यह एकता के निरीक्षक का उपयोग करने के लिए एक महान दृष्टिकोण है, क्योंकि इस तरह से आपका कोड अधिक लचीला है क्योंकि आप अपने खेल की किसी भी वस्तु को नेत्रहीन और सुरक्षित रूप से संदर्भित कर सकते हैं।

सबसे पहले अपने किसी भी गेम ऑब्जेक्ट में इवेंट सिस्टम घटक जोड़ें । यह स्टैंडअलोन इनपुट मॉड्यूल घटक भी जोड़ देगा । यह माउस क्लिक और टच जैसी इनपुट घटनाओं का ध्यान रखेगा। मैं एक व्यक्तिगत गेम ऑब्जेक्ट पर ऐसा करने की सलाह देता हूं।

इसके बाद अपने किसी भी रेकास्ट इनेबल्ड गेम ऑब्जेक्ट में इवेंट ट्रिगर कंपोनेंट को जोड़ें । एक यूआई तत्व या स्प्राइट की तरह, एक कोलाइडर के साथ 3 डी ऑब्जेक्ट । यह हमारी स्क्रिप्ट पर क्लिक ईवेंट वितरित करेगा। पॉइंटर क्लिक इवेंट प्रकार जोड़ें और रिसीवर गेम ऑब्जेक्ट सेट करें, जिस पर क्लिक कंट्रोलर स्क्रिप्ट घटक है और अंत में इसके ऑनक्लिक () विधि का चयन करें । (इसके अलावा आप एक अद्यतन में सभी क्लिक प्राप्त करने के लिए स्क्रिप्ट को बदल सकते हैं () और इस चरण को छोड़ दें।)

तो रिसीवर गेम ऑब्जेक्ट, जो निश्चित रूप से इवेंट ट्रिगर के साथ एक हो सकता है, सिंगल या डूडल क्लिक इवेंट के साथ कुछ भी करेगा।

आप डबल क्लिक, वांछित बटन और एकल और डबल क्लिक के लिए कस्टम ईवेंट के लिए समय सीमा निर्धारित कर सकते हैं। केवल सीमा यह है कि आप एक गेम ऑब्जेक्ट के लिए एक समय में केवल एक बटन चुन सकते हैं ।

यहाँ छवि विवरण दर्ज करें

स्क्रिप्ट ही दो टाइमर्स के साथ हर पहले क्लिक पर एक कॉरआउट शुरू करती है। पहले के साथ सिंक में FirstClickTime और currentTime।

समय सीमा समाप्त होने तक हर फ्रेम के अंत में एक बार यह कोरआउट करता है। इस बीच ऑनक्लिक () विधि क्लिकों की गिनती जारी रखती है।

जब समय सीमा समाप्त हो जाती है तो यह क्लिक-एनकाउंटर के अनुसार सिंगल- या डबलक्लिक इवेंट को कॉल करता है। फिर यह इस काउंटर को शून्य पर सेट करता है ताकि कोरटाइन समाप्त हो सके और पूरी प्रक्रिया शुरू से शुरू हो।

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

public class ClickController : MonoBehaviour
{
    public float timeLimit = 0.25f;
    public PointerEventData.InputButton button;

    [System.Serializable]
    public class OnSingleClick : UnityEvent {};
    public OnSingleClick onSingleClick;

    [System.Serializable]
    public class OnDoubleClick : UnityEvent {};
    public OnDoubleClick onDoubleClick;

    private int clickCount;
    private float firstClickTime;
    private float currentTime;

    private ClickController () {
        clickCount = 0;
    }

    public void onClick (BaseEventData data) {

        PointerEventData pointerData = data as PointerEventData;

        if (this.button != pointerData.button) {
            return;
        }

        this.clickCount++;

        if (this.clickCount == 1) {
            firstClickTime = pointerData.clickTime;
            currentTime = firstClickTime;
            StartCoroutine (ClickRoutine ());
        }
    }

    private IEnumerator ClickRoutine () {

        while (clickCount != 0)
        {
            yield return new WaitForEndOfFrame();

            currentTime += Time.deltaTime;

            if (currentTime >= firstClickTime + timeLimit) {
                if (clickCount == 1) {
                    onSingleClick.Invoke ();
                } else {
                    onDoubleClick.Invoke ();
                }
                clickCount = 0;
            }
        }
    }
}

ठीक है, ठीक है, मेरी पहली पोस्ट थोड़ी अधिक जानकारीपूर्ण होनी चाहिए। इसलिए मैंने विस्तृत विवरण जोड़ा और स्क्रिप्ट को थोड़ा परिष्कृत किया। यदि आप इसे पसंद करते हैं तो कृपया अपना -1 हटा दें।
23

0

मुझे लगता है कि उपयोगकर्ता के दिमाग को पढ़ने का कोई तरीका नहीं है या तो वह सिंगल या डबल क्लिक करने वाला है, आखिर हमें इनपुट के लिए इंतजार करना होगा। यद्यपि आप दूसरे क्लिक के लिए 0.01 सेकंड (कम से कम) का इंतजार सेट कर सकते हैं। इस संबंध में मैं प्रतीक्षा विकल्प के लिए जाऊंगा।

और हाँ Coroutinesमज़ेदार हैं ...

एक विकल्प

float _threshold = 0.25f;

void Start ()
{
    StartCoroutine ("DetectTouchInput");
}

IEnumerator DetectTouchInput ()
{
    while (true) {
        float duration = 0;
        bool doubleClicked = false;
        if (Input.GetMouseButtonDown (0)) {
            while (duration < _threshold) {
                duration += Time.deltaTime;
                yield return new WaitForSeconds (0.005f);
                if (Input.GetMouseButtonDown (0)) {
                    doubleClicked = true;
                    duration = _threshold;
                    // Double click/tap
                    print ("Double Click detected");
                }
            }
            if (!doubleClicked) {
                // Single click/tap
                print ("Single Click detected");
            }
        }
        yield return null;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.