TrailRenderer Reset

Is there a way that I can temporarily kill a trailRenderer’s trail so that when I move an object’s position dramatically it doesn’t draw a weird trail?

I tried putting GetComponent(TrailRenderer).time = 0; before the move, and time = 1; at the end, but it didn’t work.

I guess you’ve already tried disabling/enabling the component?

Yes I have. Upon enabling it, all the trail that would have been drawn while it was disabled appears.

My solution for now anyways is to disable the trailRenderer, wait for the full 1 second of draw length for my trail size, and then move the object and reenable the renderer. It slows down the pacing of the game a bit, but it doesn’t break the gameplay, so I’m cool with that.

I would like to know how to get it done too.

What about setting the time to 0, then back to whatever it is you want after your transition?

That does not work.

Just ran into this myself. Trying to use a object pooling system so I don’t have to Instantiate and Destroy constantly. By design I have the trail Time set fairly high, so it’s not an acceptable workaround for my needs.

Some clean way of resetting a trail renderer would ideal.

two years, and still no fix?

3 Likes

Just ran into the same problem myself. I have ball objects in my game that are fired from a cannon. The balls have a short trail renderer. But if I reload a ball into the cannon after it has be fired into the level, the trail draws all the way back to the cannon.

I tried disabling/re-enabling the trail renderer when moving the balls to the cannon, but it still draws the trail bits in between when I re-enable it.

For now I will try the “wait 1 second” method that was mentioned above. Would be nice if it didn’t draw any trail for movements when disabled…

As far as I remember only disabling the gameobject that carries the trail worked. An object pool system can help (for performance) so you won’t destroy / instantiate when the bullet has finished, but you will simply DISABLE the whole bullet/trail gameobject and children, then you will enabling it again.

Better use a custom trail script than the built-in one, for many reasons. One is surely this. Other are that you can have much more control over it if you code the component yourself.

If enabling again the component/gameobject results in seeing the trail back route, well, I guess the only fix would be to make this route being drawn on a part of the 3D world where the camera is not rendering.
If this is still not acceptable, pray :slight_smile: Can be useful, at least to moderate the pain.

There’s a pretty easy workaround to this. (I’m framing this in the context or car wheel skids, so apply to whatever you like).

-When the wheel falls below the skid threshold, we start counting down 30 frames…
-During this 30 frames, the trail is still on but it’s not following the car wheel…

Simply set the “Time” from say 5 seconds to 0.1 seconds a few frames before you turn the thing off ( say 20 or 25 seconds into the countdown).
It has 5 or 10 or whatever frames to turn off, (which is easy now that it turns off in 0.1 or 0.001 seconds).
That way it’s not moving, but still turned on, and will naturally bring the trails to a proper close.

Your coundown timer now determines how long the trails stay on screen instead of the Time value.

Edit:
Don’t forget to start out with a low value, or compare your 1st skid vs 2nd.

Here’s some code:

				public int skidTimeoutCount = -1;
				
				if ( trailGameObject != null ){
					
					float slipFactor = Mathf.Abs(getSidewaysSlip());
					
					//we want it to come on and turn off at different values...
					if ( skiddingOn ){						
							if ( slipFactor < 0.25 ){							
								skiddingOn = false;				
								skidTimeoutCount = 30;	 		//start a 30 frame counter before we turn this thing off.						
							}						
					}else{						
						if ( slipFactor > 0.7f ){							
							skiddingOn = true;
							trailGameObject.time = 5.0f;		//reset it back to 5 seconds or whatever tickles your fancy.					
						}						
					}
					
					
					//count down from 30 when we're below the speed, so the skidmarks stay on screen for 30 frames.
					if ( skidTimeoutCount > -1 ){
						skidTimeoutCount--;			
						
						//10 frames from the end, we set it to timeout really quickly.
						//this forces the thing to actually time out and doesn't spazz to the new spot when it's re-enabled.
						if ( skidTimeoutCount == 10 ){
							trailGameObject.time = 0.1f;	
						}
						
						//okay, now we've passed 30 full frames.. actually turn the thing off.
						if ( skidTimeoutCount == -1 ){
							//well, nothing really....
						}
						
					}

					
					//only follow the wheel while still skidding 
					// OR  once it's turned off, have it follow the wheel, so it's already in place for when it's switched back on.
					if ( skiddingOn || (!skiddingOn  skidTimeoutCount == -1) ){
						trailGameObject.transform.localPosition = Vector3.zero - new Vector3(0, wheelRadius + suspensionTravel , 0 );
					}
						
					
					//but remain on for about 30 frames afterwards (without following)
					trailGameObject.enabled =  skiddingOn || (skidTimeoutCount > -1);
					
					
					
				}// trailGameObject != null

Excuse the double post, but it feels like a different solution might warrant a separate post.

Following the code I pasted earlier, I had a little brainwave: when the wheel leaves the ground, or you’re not skidding… just warp the trail renderer underground (obviously, don’t leave it on all the time though). This way at least you don’t need to use a pool system either.

Pseudocode

trailrenderer.y = (suspension.grounded? wheelPos + wheelRadius : wheelPos + 100 );

hey

setting the time to -1 worked for me. 0 did not, but -1 erases all of the old trails

1 Like

-1 did not work for me. What I did do was create a coroutine.

IEnumerator MoveTrailIn()
    {
        pcEmitter.GetComponent<TrailRenderer>().time = timeDelay;  //timeDelay = 0.02f
        pcEmitter.gameObject.SetActive(false);
        yield return new WaitForSeconds(timeDelay);        
        pcEmitter.position = particleCircle.position;
        pcEmitter.gameObject.SetActive(true);
        yield return new WaitForSeconds(timeDelay);
        pcEmitter.GetComponent<TrailRenderer>().time = emitterTime;  //emitterTime is the original time of the trail
    }

What I’m doing here is switching the emitter from orbiting the object to creating a trail as it moves. First I set the time to a low value then disable the object. Then wait for the life of the new trail time using yield, and move the emitter to its new position. Turn the object back on, wait for another full life span (just to be paranoid) and restore the original time. The time delay is so small it isn’t noticeable.

you can set the trail renderer 's time property to a negative value to clear the trails already displayed.
but you must wait for a few frames before set negative value back.
use MonoBehaviour.Invoke(“ResetTrails”, 0.01f) to do this job.

2 Likes

Thanks, works like a charm!

1 Like

Thank you, using Invoke worked for me as well. Now if only changing the trail renderer’s time didn’t immediately clear the existing trail. It would look much better in my project if the original trail would fade out as normal, but I suppose that isn’t possible being that we are setting the time to -1.

I use a combination of the above approaches that lets the trail expire and doesn’t involve caching the original trail time.

Basically, I use a coroutine to disable a trail renderer:

    IEnumerator DisableTrail(TrailRenderer trail)
    {
        if (trail.time < 0)
            yield break;

        yield return new WaitForSeconds(trail.time);

        trail.time = -trail.time;
    }

And to re-enable it I simple do the following:

if (trail.time < 0)
    trail.time = -trail.time;

I keep a list of trail renderers that I find using GetComponentsInChildren and make sure not to move my object while the trail renderer is disabling. If you are using an object pool, use a delayed return that waits for the trail.time before returning to the pool.

Hope that helps!

Awesome! Just what I needed :smile:

Add a helper component cooperate with TrailRenderer that set its time to 0 in coroutine.

public class TrailRendererHelper : MonoBehaviour
{
    protected TrailRenderer mTrail;
    protected float mTime = 0;

    void Awake()
    {
        mTrail = gameObject.GetComponent<TrailRenderer>();
        if (null == mTrail)
        {
            LogHelper.LogError("[TrailRendererHelper.Awake] invalid TrailRenderer.");
            return;
        }

        mTime = mTrail.time;
    }

    void OnEnable()
    {
        if (null == mTrail)
        {
            return;
        }

        StartCoroutine(ResetTrails());
    }

    IEnumerator ResetTrails()
    {
        mTrail.time = 0;

        yield return new WaitForEndOfFrame();

        mTrail.time = mTime;
    }
}
1 Like