Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Weird problem with yields and WaitForSeconds

Discussion in 'Scripting' started by Pericuelo, Dec 19, 2013.

  1. Pericuelo

    Pericuelo

    Joined:
    Mar 1, 2013
    Posts:
    5
    Hello everyone,

    This is my first post so I’ll take the chance to introduce myself. My name is Pere and I am a programmer in a small indie game developer called StrangeLightGames. Pleased to meet you!

    I’ve encountered a weird problem with yields. I’ve been able to fix it with a dirty trick, but I would like to know if someone has some experience with this issue or knows where the mistake might come from.

    We are developing a 2.5 platformer with simple FSM and coroutines. Testing wall jumps we realized it sometimes responded in a different way when you tried to make a wall jump in the same wall. It works fine when the second wall jump makes contact on the wall below the first jump position. The problem comes after we execute a movement called “dash” before the first wall jump. In that case, the second wall jump makes contact on the wall a few points over the first wall jump location.

    We use a simple swapping method for our states:

    Code (csharp):
    1.  
    2. private void SwapHorizontal( StateHorizontal newState ) {
    3.        switch( _currentHorizontal ) {
    4.            // Finalitzem estats en cas de ser trencats de cop
    5.        case StateHorizontal.Idle:
    6.            break;
    7.        case StateHorizontal.Inertia:
    8.            break;
    9.        case StateHorizontal.Run:
    10.            break;
    11.        case StateHorizontal.Crouch:
    12.            IncreaseController();
    13.            break;
    14.        case StateHorizontal.Dash:
    15.            StartCoroutine( ResetDash() );
    16.            IncreaseController();
    17.            break;
    18.        case StateHorizontal.Slide:
    19.            break;
    20.        case StateHorizontal.TripOver:
    21.            break;
    22.        }
    23.  
    24.        switch( newState ) {
    25.            // Inicialitzem el nou estat
    26.        case StateHorizontal.Idle:
    27.            StartCoroutine( "Idle" );
    28.            break;
    29.        case StateHorizontal.Inertia:
    30.            StartCoroutine ( "Inertia" );
    31.            break;
    32.        case StateHorizontal.Run:
    33.            StartCoroutine( "Run" );
    34.            break;
    35.        case StateHorizontal.Crouch:
    36.            DecreaseController ();
    37.            StartCoroutine ("Crouch");
    38.            break;
    39.        case StateHorizontal.Dash:
    40.            StartCoroutine( "Dash" );
    41.            break;
    42.        case StateHorizontal.Slide:
    43.            StopCoroutine(_currentHorizontal.ToString());
    44.            StartCoroutine ("Slide");
    45.            break;
    46.        case StateHorizontal.TripOver:
    47.            StopCoroutine(_currentHorizontal.ToString());
    48.            StartCoroutine ("TripOver");
    49.            break;
    50.        }
    51.  
    52.        _currentHorizontal = newState;
    53.    }
    54.  
    We then use coroutines for each state, Dash’s one is:

    Code (csharp):
    1.  
    2. /**
    3.     * Coroutina per al dash
    4.     */
    5.    private IEnumerator Dash() {
    6.        DecreaseController();
    7.  
    8.        bool run = false;
    9.        _canDash = false;
    10.        movementProps.speed = MovementProperties.DASH_SPEED;
    11.        Debug.Log ( "[MainCharControl::Dash] pre-yield 0.2f" );
    12.        float time = Time.time;
    13.        while ( time + 0.2f > Time.time ) {
    14.            yield return null;
    15.        }
    16.        // yield return new WaitForSeconds( 0.2f );
    17.        Debug.Log ( "[MainCharControl::Dash] post-yield 0.2f" );
    18.  
    19.        // Testegem si es pot aixecar
    20.        RaycastHit hit;
    21.        bool hitting; // Per saber si ens podem aixecar
    22.        float marginTop = 0.3f; // Per saber si ens podem aixecar amb una mica de marge
    23.  
    24.        hitting = Physics.SphereCast( transform.position + _controller.center, _controller.height / 4, transform.up, out hit, _controller.height / 2 + marginTop );
    25.  
    26.        while( hitting ) {
    27.            // Debug.Log ("[MainCharControl::Dash] Running");
    28.            hitting = Physics.SphereCast(transform.position + _controller.center, _controller.height / 2, transform.up, out hit, _controller.height / 2 + marginTop );
    29.            // jumpProperties.canJump = !hitting;
    30.            yield return null;
    31.        }
    32.  
    33.        run = ( _input.xAxis == movementProps.runDirection ); // Si no es la mateixa direccio, fem inertia
    34.  
    35.        StartCoroutine( ResetDash() );
    36.  
    37.        // Swap State
    38.        if( run ) {
    39.            SwapHorizontal( StateHorizontal.Run );
    40.        } else {
    41.            SwapHorizontal( StateHorizontal.Inertia );
    42.        }
    43.    }
    44.  

    I have realized the problem is a yield in the code
    Code (csharp):
    1. yield return new WaitForSeconds( 0.2f );
    Changing the code for:
    Code (csharp):
    1. while ( time + 0.2f > Time.time ) {
    2.      yield return null;
    3. }
    the issue seems to disappear.

    Anyone knows why this might be happening? Its not a big pain but it makes no sense to me and I would like to know if there is something I’m missing about WaitForSeconds().

    Thank you all!
     
  2. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    955
    Curious. Probably won't change anything, but you could try changing

    StartCoroutine( "Dash" );


    To:

    StartCoroutine(Dash());

    And make it Dash method public. I think I've run into problems before with private coroutines.
     
  3. Pericuelo

    Pericuelo

    Joined:
    Mar 1, 2013
    Posts:
    5
    Hey SunnySunshine,

    Tried both methods, and the behavior is the same :/