Skip to content

Instantly share code, notes, and snippets.

@mandarinx
Created August 28, 2017 17:59
Show Gist options
  • Save mandarinx/1d57dc7d1afd2c92d57eab5c0e60d251 to your computer and use it in GitHub Desktop.
Save mandarinx/1d57dc7d1afd2c92d57eab5c0e60d251 to your computer and use it in GitHub Desktop.
Trails
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// tester part here, scroll for smartTrail class
public class testSmartTrail : MonoBehaviour {
[Header("Line parameters")]
public float maxDuration=1.5f;
public float maxDistance=8;
public float minStepDistance=.0625f;
[Space]
public bool update=true;
public bool step;
float tm;
float stepTime;
smartTrail trail;
public bool useLineRenderer = true;
LineRenderer lr;
void Reset(){
trail = null;
}
void OnValidate(){
maxDistance = Mathf.Max(maxDistance, 0);
maxDuration = Mathf.Max(maxDuration, 0);
minStepDistance = Mathf.Max(minStepDistance, 0);
trail.setParams(maxDistance,maxDuration,minStepDistance);
}
void OnDrawGizmos(){
if(trail==null || trail.lPoints.Count==0)
trail = new smartTrail(maxDistance, maxDuration, minStepDistance);
float dt = Mathf.Clamp(time-tm, 0, .03f);
tm = time;
bool ends=false; // only first or last point's position changed, can be used for optimization
bool full=false; // have to reapply whole array
if(update || step){
stepTime += dt;
if(step) {update=false; step=false;}
trail.updateLine(transform.position, time, out ends, out full);
}
// draw it
if(useLineRenderer){
if(lr==null)
lr = gameObject.AddComponent<LineRenderer>();
lr.positionCount = trail.lPoints.Count;
for(int p=0;p<lr.positionCount;p++)
lr.SetPosition(p, trail.lPoints[p]);
}else{
var exLR = GetComponent<LineRenderer>();
DestroyImmediate(exLR);
}
}
public static float time {get{
#if UNITY_EDITOR
if(!Application.isPlaying)
return (float)UnityEditor.EditorApplication.timeSinceStartup;
#endif
return Time.time;
}}
}
// smart trail class can be in its own .CS file
[System.Serializable]
public class smartTrail {
float maxDistance, maxDuration, minStepDistance, minStepDistanceSQ;
public List<Vector2> lPoints;
List<float> lTimes;
float curLength;
Vector2 lastAddedPoint;
bool hasLast;
public smartTrail(float maxDistance, float maxDuration, float minStepDistance=.0625f){
setParams(maxDistance,maxDuration,minStepDistance);
}
public void setParams(float maxDistance, float maxDuration, float minStepDistance=.0625f){
this.maxDistance = maxDistance;
this.maxDuration = maxDuration;
this.minStepDistance = minStepDistance;
minStepDistanceSQ = minStepDistance*minStepDistance;
}
public void updateLine(Vector2 point, float now, out bool endUpd, out bool fullUpd){
endUpd = false;
fullUpd = false;
if(lPoints==null || lPoints.Count==0) {
lPoints = new List<Vector2>(){point};
lTimes = new List<float>(){now};
hasLast = true;
lastAddedPoint = point;
curLength = 0;
return;
}
float newAddDist = 0;
Vector2 lastPoint = lPoints[lPoints.Count-1];
newAddDist = ((hasLast ? lastAddedPoint : lastPoint) - point).sqrMagnitude;
if(newAddDist<minStepDistanceSQ){
lPoints[lPoints.Count-1] = point;
lTimes[lPoints.Count-1] = now;
endUpd = (lastPoint-point).sqrMagnitude>.1f;
if(lPoints.Count>1 && clipDuration(ref fullUpd))
endUpd = true;
return;
}
newAddDist = Mathf.Sqrt(newAddDist);
curLength += newAddDist;
lastAddedPoint = point;
lPoints.Add(point);
lTimes.Add(now);
hasLast = true;
endUpd = true;
clipDuration(ref fullUpd);
clipLength();
fullUpd = true;
}
void clipLength(){
if(lPoints.Count<2) return;
float extraLength = curLength - maxDistance;
if(extraLength<0) return;
//safety
int lTries = 10000;
while(extraLength>0){
lTries--; if(lTries==0) return;
Vector2 lastDir = lPoints[1]-lPoints[0];
float lastDist = lastDir.magnitude;
if(lastDist<extraLength && lPoints.Count>2){
lPoints.RemoveAt(0);
lTimes.RemoveAt(0);
extraLength -= lastDist;
curLength -= lastDist;
}else{
lPoints[0] += lastDir.normalized * extraLength;
curLength -= extraLength;
extraLength = 0;
}
}
}
bool clipDuration(ref bool fullUpd){
float lineDuration = lTimes[lTimes.Count-1] - lTimes[0];
if(lineDuration>maxDuration){
float extra = lineDuration - maxDuration;
int dTries = 10000;
while(extra>0 && lPoints.Count>1 && curLength>minStepDistance){
dTries--; if(dTries==0) return true;
Vector2 dir = lPoints[1] - lPoints[0];
float dur = lTimes[1] - lTimes[0];
float dist = dir.magnitude;
fullUpd = true;
lPoints.RemoveAt(0);
lTimes.RemoveAt(0);
curLength = Mathf.Max(curLength - dist, minStepDistance);
extra -= dur;
}
return true;
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment