Search Unity

Pausing & Resuming Trail Renderer without timeScale?

Discussion in 'General Graphics' started by Merman, Dec 11, 2018.

  1. Merman

    Merman

    Joined:
    Nov 16, 2014
    Posts:
    51
    Good morning, Everyone.

    I wanted to know how one might go about "pausing" or "freezing" a trail renderer (without the use of Time.timeScale) and then resuming afterwards.

    The manual mentions that "all points inside a TrailRenderer store a timestamp when they are born." TrailRenderer.time counts forward from this point to determine how long the trail will be onscreen. However (as far as I can tell) this "timestamp" is not exposed anywhere and cannot be directly altered.

    A handful of Internet searches all turned up the following thread (though I didn't find it particularly helpful) :

    The "freezing" effect itself is easy enough to achieve with:
    TrailRenderer.time = Mathf.Infinity;


    This effectively prevents points from reaching expiration, but it doesn't actually suspend their aging. As such, setting TrailRenderer.time back to its previous value causes all existing "frozen" points to immediately expire all at once (if they are already older than the specified amount of time).

    I also tried using TrailRenderer.GetPositions, TrailRenderer.Clear, and TrailRenderer.AddPositions (together in that order). The result was visually identical, with all points appearing to expire at once (and with no new ones added).

    For a rough example, this was something along the lines of:
    Code (CSharp):
    1.  
    2. float b = 1.0f;
    3. Vector3[] a = new Vector3[TrailRenderer.positionCount];
    4. TrailRenderer.GetPositions(a);
    5. TrailRenderer.Clear();
    6. TrailRenderer.AddPositions(a);
    7. TrailRenderer.time = b;
    8.  
    Performed after the trail has had time to create visible points.

    Thank you in advance for any and all assistance you may be able to provide.
     
    Last edited: Dec 11, 2018
    SooiV likes this.
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    The short answer is that i don't think you can do it.

    The slightly longer answer is that, as you already deduced, the timestamps attached to each point are not exposed in any way. In theory, we could add a Pause script API, that keeps track internally of how long it was paused for, and advance the timestamps of all points, when unpaused.

    Or we could expose the timestamps. I have thought about this in the past, but it seemed like it would expose something that was quite easy to break (eg new edge cases such as changing the birth/expiration order of points in the trail).

    EDIT: Perhaps there is a 3rd party trail renderer on the Asset Store that can do it...
     
    SooiV likes this.
  3. Merman

    Merman

    Joined:
    Nov 16, 2014
    Posts:
    51
    Thanks for your reply @richardkettlewell . I felt certain that there had to be a multiplier or something similar that I was overlooking or misusing. I'm rather glad to know that at least I was not missing something obvious.

    I suppose I could manually keep track of how long a trail is meant to be "paused" and set TrailRenderer.time relative to that value. I haven't tried it, but I suspect that this would cause the trails to take progressively longer to expire after every pause/resume.

    I'll have another look at the Asset Store and consider alternatives to the trail renderer in the meantime.
     
    SooiV likes this.
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Yes, extending TrailRenderer.time by the duration of the pause would work, but only for pre-existing points. Any new points spawned after the unpause would have the new, longer lifetime.
     
    SooiV likes this.
  5. Merman

    Merman

    Joined:
    Nov 16, 2014
    Posts:
    51
    So then it could be "cheated" afterwards using something like Invoke() to restore the desired lifetime after a specified period following the resume (not that this would be an elegant solution by any stretch of the imagination).

    EDIT:

    So, out of curiosity, I tested this. It works well enough for the purpose of demonstration. Here's another "quick and dirty" example:
    Code (CSharp):
    1. float trailTime = 1.0f;
    2. float pauseTime;
    3. float resumeTime;
    4.  
    5. TrailRenderer trail;
    6.  
    7. void Awake()
    8. {
    9.      trail = GetComponent<TrailRenderer>();
    10. }
    11.  
    12. void PauseTrail()
    13. {
    14.      pauseTime = Time.time;
    15.      trail.time = Mathf.Infinity;
    16. }
    17.  
    18. void ResumeTrail()
    19. {
    20.      resumeTime = Time.time;
    21.      trail.time = (resumeTime - pauseTime) + trailTime;
    22.      Invoke("SetTrailTime", trailTime);
    23. }
    24.  
    25. void SetTrailTime()
    26. {
    27.      trail.time = trailTime;
    28. }
     
    Last edited: Dec 11, 2018
  6. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Nice hack! :D

    (just beware if you re-pause before that Invoke fires...)
     
    SooiV and Merman like this.
  7. Merman

    Merman

    Joined:
    Nov 16, 2014
    Posts:
    51
    Thanks! And yes, I did notice that. It should be a simple matter of canceling any pending Invokes ahead of PauseTrail() and/or adding a condition to SetTrailTime().
     
    SooiV and richardkettlewell like this.
  8. huulong

    huulong

    Joined:
    Jul 1, 2013
    Posts:
    224
    I replaced Invoke with a manual countdown set to trail time on Resume and decreased in Update, when the trail is not paused itself. When the countdown reaches 0, I reset the trail time.

    If a second pause and resume occurs before the end of the countdown, the countdown is simply reset to trail time, so we delay the trail time reset. It works fine!
     
    SooiV likes this.