Search Unity

Transform.Position coroutine stops at different values

Discussion in '2D' started by Predule, Mar 30, 2020.

  1. Predule

    Predule

    Joined:
    Mar 30, 2020
    Posts:
    5
    Hello users, I'm here to kindly ask your help with two coroutines I made. When my game goes for Game Over, before showing the player the options of restart or menu, I wanted to make a curtain animation. So Game Over leads to curtain down, restart option pops up and curtain goes up again. Now...the weird part is I made two coroutines, one moving the courtine down and the second moving it up and it I call the, it goes down and doesn't go all the way up.

    Code (CSharp):
    1.  void MovesDown()
    2.     {
    3.         StartCoroutine("CurtainDown");
    4.     }
    5.  
    6.     IEnumerator CurtainDown()
    7.     {
    8.         float seconds = 0.01f;
    9.         float speed = 1.2f;
    10.         int value = 119;
    11.         for (int i = 0; i < value; i++)
    12.         {
    13.             cortina.transform.position = cortina.transform.position + new Vector3(0, -1 * speed * seconds, 0);
    14.             yield return null;
    15.         }
    16.     }
    17.  
    18.  
    19.     void MovesUp()
    20.     {
    21.         StartCoroutine("CurtainUp");
    22.     }
    23.  
    24.     IEnumerator CurtainUp()
    25.     {
    26.         float seconds = 0.01f;
    27.         float speed = 1.25f;
    28.         float value = 237;
    29.         for (int i = 0; i < value; i++)
    30.         {
    31.             cortina.transform.position = cortina.transform.position + new Vector3(0, 1 * speed * seconds, 0);
    32.             yield return null;
    33.         }
    34.     }
    I set different speed and values trying to handle that problem but there is also a second thing messing my code up. If the player stay alive for different durations of time, the curtain moving down(and up) also stops at different positions...I feel like I'm missing out something silly, do you guys have any idea ?
     
  2. MrPaparoz

    MrPaparoz

    Joined:
    Apr 14, 2018
    Posts:
    157
    Code (CSharp):
    1. var index = 0;
    2. while(index < value){
    3.    //position thing
    4.    index++;
    5.    yield return null;
    6. }
    Try this instead of for loop.
     
  3. Predule

    Predule

    Joined:
    Mar 30, 2020
    Posts:
    5
    Switching for while only didn't work but then I deleted the functions MoveDown and MoveUp and started calling directly the coroutines, maybe the void function was messing up with the floats ?

    Edit: Also its not that much important since the moving speed isn't that different but can you guys explain me why Vector3.Down and Vector3.Up moves differently ? I thought its supposed to be just (0,-1,0) and (0,1,0). Since the speed/seconds I set is fix, why do I have to put different numbers in the float value ?

    Edit2: Nevermind, the curtain are going in different speeds again, I don't know whats happening anymore lol.
     
    Last edited: Mar 30, 2020
  4. Xiromtz

    Xiromtz

    Joined:
    Feb 1, 2015
    Posts:
    65
    You're completely missing the point of doing any sort of movement in a game. A coroutine is no different from a function called in the Update method, except that it pauses until the next frame during "yield" statements.
    You're not scaling your movements with *Time.deltaTime*, thus your animation speed changes according to your framerate!
    Changing
    cortina.transform.position = cortina.transform.position + new Vector3(0, -1 * speed * seconds, 0);
    to

    cortina.transform.position = cortina.transform.position + new Vector3(0, -1 * speed * seconds, 0) * Time.deltaTime;
    or
    cortina.transform.position = cortina.transform.position + new Vector3(0, -1 * speed * seconds * Time.deltaTime, 0);

    should fix your issue
     
  5. Xiromtz

    Xiromtz

    Joined:
    Feb 1, 2015
    Posts:
    65
    Also, I believe your approach is very weird and error prone. My recommandations:
    1. Simply create an animator. Create a "curtain down" and a "curtain up" animation. They would only need 2 frames, the first and last frame, the animator will do the interpolation for you. Then you might need 2 additional "static" animations, that are simply the last frames of the previous animations, so the curtains stay in place. Its a very elegant and easy solution in my opinion.

    2. Why calculate the position you need via a for loop with and index? Thats really unelegant code and if you ever look at it later you will likely be very confused. The code I would use:
    Code (CSharp):
    1. IEnumerator CurtainDown()
    2. {
    3.     float secondsForAnimationToFinish = 1.0f; //1 second
    4.     float currentAnimationTime = 0;
    5.     float xDistToMove = 5.0f; // Insert the distance you wish the curtain to move or change the axis
    6.     float oldX = cortina.transform.position.x;
    7.     float xAfterDone = oldX + xDistToMove;
    8.  
    9.     while (currentAnimationTime < secondsForAnimationToFinish)
    10.     {
    11.         currentAnimationTime += Time.deltaTime;
    12.  
    13.         // The time may very easily overshoot the exact time we want, so we need to break the interpolation cleanly
    14.         if (currentAnimationTime >= secondsForAnimationToFinish)
    15.         {
    16.             cortine.transform.position = new Vector3(xAfterDone,0,0);
    17.             yield break;
    18.         }
    19.  
    20.         float normalizedTime = currentAnimationTime / secondsForAnimationToFinish; // Normalize time to be a number from 0-1
    21.         float distanceToMove = normalizedTime * xDistToMove; // This should interpolate the x value correctly for every frame
    22.         cortina.transform.position = new Vector3(oldX + distanceToMove,0,0);
    23.         yield return null;
    24.     }
    25. }
    This is untested code and will need some tweaking, but you should get the idea.
     
    Predule likes this.
  6. Predule

    Predule

    Joined:
    Mar 30, 2020
    Posts:
    5
    Yeah I figured out I made some bad choices there, right now I'm using MoveTowards and it's way better. So far its working...Still figuring out how to make things properly and in a clean way. Also I belive the part you say that the time gets overshoot were my problem, since sometimes it stopped in the perfect spot or just moved a bit more and went all the way out of screen.
     
  7. Xiromtz

    Xiromtz

    Joined:
    Feb 1, 2015
    Posts:
    65
    @Predule Good to hear it's working. I believe MoveTowards basically interpolates in the same way my code would ^^