1
\$\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\$
4
  • 1
    \$\begingroup\$ Maybe try the OnTriggerStay2D method instead of the enter method \$\endgroup\$
    – Savlon
    Commented Nov 18, 2014 at 13:32
  • \$\begingroup\$ Does it have any method for adding wait or something, i'll check it out ! Thank you \$\endgroup\$ Commented Nov 18, 2014 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
    Commented Nov 18, 2014 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\$ Commented Nov 18, 2014 at 13:51

2 Answers 2

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()

\$\endgroup\$
2
  • \$\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\$ Commented Nov 19, 2014 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
    Commented Nov 19, 2014 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);
        }
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ I tried looking for MenuItem but dint quite understand the concept, Thank you so much for the answer it works \$\endgroup\$ Commented Nov 19, 2014 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
    Commented Nov 19, 2014 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\$ Commented Nov 20, 2014 at 13:41

You must log in to answer this question.

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