0
\$\begingroup\$

So i'm using Kinect with unity to track user's hand movements, and let the user's hand act as a mouse, I have written the code to detect a collision between a button (sprite object) and the hand cursor using OnTriggerEnter2D, but I want the hand cursor to remain on the button (sprite object) for atleast 3 seconds for it to be considered as a button click action. The WaitForSeconds coroutine doesn't seem to be working. What am i doing wrong?

public class MenuSelect : MonoBehaviour{

private string btnName;
private string themeName;

// Use this for initialization
void Start () 
{
    //gestureListener = Camera.main.GetComponent<GestureListener>();    
}

// Update is called once per frame
void Update () 
{

}

void OnTriggerEnter2D(Collider2D col)
{
    //print("Collision Detected");
    StartCoroutine(WaitTime(3));
    if(col.gameObject.tag == "Button")
    {
        btnName = col.gameObject.name;
        switch(btnName)
        {
            case "musicBtn":
                Application.LoadLevel("Menu_Music");
                break;

            case "startBtn":
                Application.LoadLevel("Menu_Select");
                break;

            case "instructBtn":
                print("Instruction Clicked");
                break;

            case "exitBtn":
                Application.Quit();
                break;

            case "themeBtn":
                Application.LoadLevel("Menu_Theme");
                break;

            case "backBtn":
                Application.LoadLevel("Menu_LoadScreen");
                break;
        }
    }

}

IEnumerator WaitTime(float waitTime)
{
    yield return new WaitForSeconds(waitTime);
    print("seconds up already");
}   }
\$\endgroup\$
  • 1
    \$\begingroup\$ Maybe try the OnTriggerStay2D method instead of the enter method \$\endgroup\$ – Savlon Nov 18 '14 at 13:32
  • \$\begingroup\$ Does it have any method for adding wait or something, i'll check it out ! Thank you \$\endgroup\$ – Sweta Dwivedi Nov 18 '14 at 13:35
  • \$\begingroup\$ No it doesn't but it constantly runs the OnTriggerStay method if your collider is continuously touching the object… The OnTriggerEnter method gets called once whenever the object first touches the collider… therefore, it will trigger on collision, wait 3 seconds and then check for the tag, which may be null due to the OnTriggerEnter method already being called \$\endgroup\$ – Savlon Nov 18 '14 at 13:46
  • \$\begingroup\$ okay thankyou, i have changed it to OnTriggerStay2D! but the funny this is when i attached the script to the button object rather than the cursor object . . it seemed to be working fine then \$\endgroup\$ – Sweta Dwivedi Nov 18 '14 at 13:51
1
\$\begingroup\$

The coroutine itself will pause, but the code that called StartCoroutine() will keep going. So in this case, WaitTime() will pause but OnTriggerEnter2D() will keep going.

What you probably want instead is for the entire button logic to go in the coroutine. Then it won't matter that OnTriggerEnter2D() keeps going, since starting the coroutine is all it does. At that point you should call the coroutine function something other than WaitTime() since it's doing a lot more than just waiting eg. WaitThenRespondToButton()

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ OnTriggerStay2D I will start coroutine but as soon as my hand cursor (trigger) moves out of the button, i want it to stopcoroutine by calling StopCoroutine("WaitRespondForButton"); inside TriggerExit2D, but its not working, its still jumping to the next menu after 5 seconds are up? \$\endgroup\$ – Sweta Dwivedi Nov 19 '14 at 11:25
  • \$\begingroup\$ You should probably have a boolean value that becomes true OnTriggerEnter and false OnTriggerExit and check that value in the coroutine. \$\endgroup\$ – jhocking Nov 19 '14 at 16:07
1
\$\begingroup\$

Your WaitTime Coroutine will not pause the evaluation of the following code. The Coroutine will be kicked off and logic will immediately continue. Your Coroutine is waiting 3 seconds and will call that print function wherever it resides but that's all it will do.

You should probably go with something like:

private float triggerEnterTime = 0;

void OnTriggerEnter2D(Collider2D col)
{
    triggerEnterTime = Time.time;
}

void OnTriggerStay2D(Collider2D col)
{
    // Too soon?
    if(Time.time - triggerEnterTime < 3)
    {
        // Might want to do something to indicate graphically that you're holding
        //     like a progress bar. For now, simply abort for this frame.
        return;
    }

    // Has been held for 3 seconds, evaluate it
    if(col.gameObject.tag == "Button")
    {
        btnName = col.gameObject.name;
        switch(btnName)
        {
            case "musicBtn":
                Application.LoadLevel("Menu_Music");
                break;

            case "startBtn":
                Application.LoadLevel("Menu_Select");
                break;

            case "instructBtn":
                print("Instruction Clicked");
                break;

            case "exitBtn":
                Application.Quit();
                break;

            case "themeBtn":
                Application.LoadLevel("Menu_Theme");
                break;

            case "backBtn":
                Application.LoadLevel("Menu_LoadScreen");
                break;
        }
    }
}

That should do the trick but something that might be cleaner is to define a "MenuItemBehavior" that will handle itself rather than some master switch statement.

Something like the following. I'd attach it individually to each button and then set "TargetScene" for each as well. This should work for most of them though you'd have to do something slightly different for "Instruction" and "Exit"

public class SceneMenuItemController : MonoBehaviour
{
    public string TargetScene;

    private float triggerEnterTime = 0;

    void OnMouseUpAsButton()
    {
        if (!string.IsNullOrEmpty(TargetScene))
        {
            Application.LoadLevel(TargetScene);
        }
    }

    void OnTriggerEnter2D(Collider2D col)
    {
        triggerEnterTime = Time.time;
    }

    void OnTriggerStay2D(Collider2D col)
    {
        // Too soon?
        if(Time.time - triggerEnterTime < 3)
        {
            // Might want to do something to indicate graphically that you're holding
            //     like a progress bar. For now, simply abort for this frame.
            return;
        }

        if (!string.IsNullOrEmpty(TargetScene))
        {
            Application.LoadLevel(TargetScene);
        }
    }
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I tried looking for MenuItem but dint quite understand the concept, Thank you so much for the answer it works \$\endgroup\$ – Sweta Dwivedi Nov 19 '14 at 11:10
  • 1
    \$\begingroup\$ @SwetaDwivedi - It's not something built-in but something you can make yourself to serve your needs. I added an example. \$\endgroup\$ – McAden Nov 19 '14 at 18:14
  • \$\begingroup\$ Ohh i'm sorry i misunderstood, so like a class where i can attach the target scene rather than going around adding a switch statement! Great suggestion, Dint even cross my mind! Thank you very much :) \$\endgroup\$ – Sweta Dwivedi Nov 20 '14 at 13:41

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.