Search Unity

[solved]sliding through waypoints; lerp,coroutine,while-loop

Discussion in 'Scripting' started by SisterKy, Jan 19, 2010.

  1. SisterKy

    SisterKy

    Joined:
    Dec 6, 2009
    Posts:
    30
    *Edited Thread-Title to be more search-friendly*


    Meh, I'm giving up -.- Tried to fix this for hours now but I'm just too blind to see it.....

    I have two charas (Wasch and Lucat) and one camera.
    One waypoint in each head (camPositionWasch/Lucat) and one behind each head (camPathPointWasch/Lucat).
    The cam sits in one camPosition, should move to the first PathPoint, then to the second, last to the new camPosition.

    What I have is that it moves smoothly to the first PathPoint, then jumps to the new camPosition :/


    Code (csharp):
    1. private var camPathPointWasch;
    2. private var camPathPointLucat;
    3. private var camPositionWasch;
    4. private var camPositionLucat;  
    5.  
    6. private var lerpSpeed = 0.5;
    7.  
    8. private var firstPointReached : boolean = false;
    9. private var secondPointReached : boolean = false;
    10. private var lastPointReached : boolean = false;
    11.  
    12. function Awake ()
    13. {
    14.     camPathPointWasch = gameObject.Find("CamPathPointWasch").transform;
    15.     camPathPointLucat = gameObject.Find("CamPathPointLucat").transform;
    16.     camPositionWasch = gameObject.Find("CamPositionWasch").transform;
    17.     camPositionLucat = gameObject.Find("CamPositionLucat").transform;
    18. }
    19.  
    20.  
    21. function LucatToWasch ()
    22. {
    23.     Debug.Log("LucatToWasch started");
    24.  
    25.     while ( !lastPointReached )
    26.     {
    27.         transform.parent = camPathPointLucat;
    28.         //as long as first waypoint hasn't been reached yet,
    29.         //lerp Camera towards it and make it face in the same direction    
    30.         while ( !firstPointReached)
    31.         {
    32.             Debug.Log("First Point not reached yet");
    33.             Debug.Log("before Lerp");
    34.             Debug.Log(transform.localPosition);
    35.             transform.position = Vector3.Lerp
    36.                 (camPositionLucat.position, camPathPointLucat.position, Time.time * lerpSpeed);
    37.             Debug.Log("after Lerp");
    38.             Debug.Log(transform.localPosition);
    39.             transform.rotation = Quaternion.Lerp
    40.                 (camPositionLucat.rotation, camPathPointLucat.rotation, Time.time * lerpSpeed);
    41.  
    42.             if (transform.position == camPathPointLucat.position)
    43.             {
    44.                 Debug.Log("first Waypoint reached");
    45.                 firstPointReached = true;
    46.             }
    47.            
    48.             yield;
    49.         }
    50.    
    51.         transform.parent = camPathPointWasch;
    52.         //as long as second waypoint hasn't been reached yet,
    53.         // lerp Camera towards it and make it face in the same direction       
    54.         while ( !secondPointReached)
    55.         {
    56.             Debug.Log("Second Point not reached yet");
    57.             Debug.Log("before Lerp");
    58.             Debug.Log(transform.localPosition);
    59.             transform.position = Vector3.Lerp
    60.                 (camPathPointLucat.position, camPathPointWasch.position, Time.time * lerpSpeed);
    61.             Debug.Log("after Lerp");
    62.             Debug.Log(transform.localPosition);
    63.             transform.rotation = Quaternion.Lerp
    64.                 (camPathPointLucat.rotation, camPathPointWasch.rotation, Time.time * lerpSpeed);
    65.  
    66.             if (transform.position == camPathPointWasch.position)
    67.             {
    68.                 Debug.Log("second Waypoint reached");
    69.                 secondPointReached = true;
    70.             }
    71.            
    72.             yield;
    73.         }
    74.  
    75.         transform.parent = camPositionWasch;
    76.         //as long as last waypoint hasn't been reached yet,
    77.         //lerp Camera towards it and make it face in the same direction    
    78.         while ( !lastPointReached)
    79.         {
    80.             Debug.Log("Third Point not reached yet");
    81.             Debug.Log("before Lerp");
    82.             Debug.Log(transform.localPosition);
    83.             transform.position = Vector3.Lerp
    84.                 (camPathPointWasch.position, camPositionWasch.position, Time.time * lerpSpeed);
    85.             Debug.Log("after Lerp");
    86.             Debug.Log(transform.localPosition);
    87.             transform.rotation = Quaternion.Lerp
    88.                 (camPathPointWasch.rotation, camPositionWasch.rotation, Time.time * lerpSpeed);
    89.  
    90.             if (transform.position == camPositionWasch.position)
    91.             {
    92.                 Debug.Log("third Waypoint reached");
    93.                 lastPointReached = true;
    94.             }
    95.            
    96.             yield;
    97.         }
    98.  
    99.         yield;
    100.  
    101.     }
    102.  
    103.     firstPointReached = false;
    104.     secondPointReached = false;
    105.     lastPointReached = false;
    106.    
    107.     transform.position = camPositionWasch.position;
    108.     transform.rotation = camPositionWasch.rotation;
    109.     transform.parent = camPositionWasch;    
    110.    
    111.  
    112. }

    Debug.Log shows, that the first lerp-loop get's executed nicely with repeated calls, until the first Waypoint is reached.
    The second is entered once but that same call already reaches secondWaypoint.
    The same happens for the third loop.

    I'm all out of ideas :? :(


    Greetz, Ky.


    *Edit*
    Out of curiosity I tried
    Code (csharp):
    1.     if (firstPointReached  secondPointReached  lastPointReached)
    2.     {
    3.         firstPointReached = false;
    4.         secondPointReached = false;
    5.         lastPointReached = false;
    6.     }
    then no lerping happend anymore at all. (Each loop entered once and left right away)
    But the strange thing: after commenting the if-clause out again, it didn't return to lerping to the first waypoint! Oo Only after a restart of unity it returned to the behaviour described above...
    This is so fishy :p
     
  2. CoherentInk

    CoherentInk

    Joined:
    Jul 16, 2006
    Posts:
    216
    A couple of questions, excuse my ignorance:
    1. What is this script attached to? The camera? Some random GameObject?
    2. Why do you need to assign transform.parent before each move? Can't you just reference the camera in world space? (i.e. Camera.main.transform.position/rotation) Could be slower I suppose.
    3. Next time, can you include what the debug output is? Since you've put so many Debug.Log calls in, it would be helpful to see what the exact output is. (They made it a little difficult to see what was actually going on when I first read it!)
    And now that I look at your code again, I think the issue is Time.time. After 2 seconds into the game, Time.time * lerpSpeed will still be greater than 1, so Vector3.Lerp() will always return the final position!
    To solve this, you'll need to store the time when the movement starts and subtract that from Time.time for each Lerp:
    Code (csharp):
    1. ...
    2. startTime = Time.time;
    3. while (!secondPointReached) {
    4. ...
    5. transform.position = Vector3.Lerp(camPathPointLucat.position, camPathPointWasch.position, (Time.time - startTime) * 0.5);
    6. ...
    You'll need to do that for all three of the sections in case you decide to start this animation at any time other than the start of the level!
     
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I think it would be easier to explicitly lerp from one point to another, instead of trying to check the position:

    Code (csharp):
    1. var t = 0.0;
    2. while (t < 1.0) {
    3.    t += Time.deltaTime * (1.0 / lerpSpeed);
    4.    transform.position = Vector3.Lerp(camPositionLucat.position, camPathPointLucat.position, t);
    5.    // Do rotation the same way
    6. }
    7. // etc.
    --Eric
     
  4. SisterKy

    SisterKy

    Joined:
    Dec 6, 2009
    Posts:
    30
    Thanks to both of you! To take the time to work through my mess, very much apreciated! =D
    *huggs*! (<- don't worry, I'm a girl, lest you get any awkward feelings ;) :D )

    Both solutions work very nice!
    I think with this I got a better understanding of how lerp-functions and while-loops work, as well as Time.time...

    @CoherentInk
    What "your ignorance" are you talking about? :eek:
    It's my fault I didn't include that info in the frist place, for which I apologize! *bows*
    As for your questions (in case you still want to know):
    1. It's an empty GO that has the Cam as a child (to prevent the MouseLook-Script on the Cam from interfering with the orientation-lerp)
    2. I'm not sure if it's necessary. I tried with- and without the parenting and it didn't seem to interfere... (obviously I'm not to sure about what exactly I'm doing here anyway ^_^'' haha :oops: )
    3. Yes, sorry, will do next time -.- (it feels weird to write such intimidatingly loooong posts )

    Greetz, Ky.
     
  5. CoherentInk

    CoherentInk

    Joined:
    Jul 16, 2006
    Posts:
    216
    No worries!

    I think that Eric is right, you could do the same thing with a lot less code, and as a general rule, if you don't need it, take it out-- otherwise everything will slow down or you'll find errors later and have a hard time figuring out why.

    It's also worth pointing out that you're basically doing the same thing three times, so it's probably worth putting it in a coroutine or function (code is in Javascript):
    Code (csharp):
    1. Update () {
    2.    while (transform.position != destination3.position) {
    3.       yield LerpCamera(transform, destination1);
    4.       yield LerpCamera(transfrom, destination2);
    5.       yield LerpCamera(transform, destination3);
    6.    }
    7. }
    8. ...
    9. function LerpCamera (from : Transform, to : Transform) {
    10.    var startTime = Time.time;
    11.    while (transform.position != to.position) {
    12.       transform.position = Vector3.Lerp(from.position, to.position, (Time.time - startTime) / lerpSpeed);
    13.       transform.rotation = Quaternion.Lerp(from.rotation, to.rotation, (Time.time - startTime) / lerpSpeed);
    14.       yield;
    15.    }
    16. }
    You could then use this same code for multiple events regardless of the specifics or the number of moves in the sequence.

    Of course, this is completely untested, but good luck!

    Edit: You may also want to read about Coroutines and the yield statement.
     
  6. SisterKy

    SisterKy

    Joined:
    Dec 6, 2009
    Posts:
    30
    Oooh, much prettier code! =D <3
    Thanks for the link. =) I've read the page on co-routines (repeadedly) already, but unless I actually use something, I can't quite wrap my head around it... after this it makes a lot more sense to me.

    Greetz, Ky.



    Incase someone stumbles across this thread with the same problem, here's my final:
    Code (csharp):
    1.  
    2. //CamDolly.js
    3.  
    4. private var camPathPointWasch;
    5. private var camPathPointLucat;
    6. private var camPositionWasch;
    7. private var camPositionLucat;  
    8.  
    9. private var startTime;
    10. private var lerpSpeed = 2;
    11.  
    12. private var destinationReached : boolean = false;
    13.  
    14. function Awake ()
    15. {
    16.     camPathPointWasch = gameObject.Find("CamPathPointWasch").transform;
    17.     camPathPointLucat = gameObject.Find("CamPathPointLucat").transform;
    18.     camPositionWasch = gameObject.Find("CamPositionWasch").transform;
    19.     camPositionLucat = gameObject.Find("CamPositionLucat").transform;
    20. }
    21.  
    22.  
    23. function LucatToWasch ()
    24. {
    25.     Debug.Log("LucatToWasch started");
    26.  
    27.     while (!destinationReached)
    28.     {
    29.         yield LerpPosition(transform, camPathPointLucat);
    30.         yield LerpPosition(transform, camPathPointWasch);
    31.         yield LerpPosition(transform, camPositionWasch);
    32.         destinationReached = true;
    33.     }
    34.    
    35.     transform.parent = camPositionWasch;    
    36.     destinationReached = false;
    37. }
    38.  
    39.  
    40. function LerpPosition (from : Transform, to : Transform)
    41. {
    42.     var startTime = Time.time;
    43.     while (transform.position != to.position)
    44.     {
    45.         var t = (Time.time - startTime) / lerpSpeed;
    46.         transform.position = Vector3.Lerp(from.position, to.position, t);
    47.         transform.rotation = Quaternion.Lerp(from.rotation, to.rotation, t);
    48.         yield;
    49.     }
    50. }
    called by some other script:

    Code (csharp):
    1.  
    2. private var camDolly;
    3. private var lucatActive: boolean;
    4. private var waschActive: boolean;
    5.  
    6. function Awake ()
    7. {
    8.    camDolly = GameObject.Find("CamDolly").GetComponent("CamDolly");
    9.    waschActive = false;
    10.    lucatActive = true;
    11. }
    12.  
    13.  if ( lucatActive )
    14.     {
    15.         waschActive = false;
    16.         lucatActive = false;
    17.  
    18.         yield camDolly.LucatToWasch();
    19.        
    20.         waschActive = true;
    21.     }
    22. // This if-statement can't be in function Update because of the yield, but can to be in a seperate function called by Update
     
    Griffo likes this.
  7. Griffo

    Griffo

    Joined:
    Jul 5, 2011
    Posts:
    700
    I know this is an old post but THANKS !!