using UnityEngine;
using System.Collections.Generic;
public class Trail : MonoBehaviour
{
private static Point frees = null;
private static Point createPoint(Transform trans, float path, Point next){
Point point = null;
if (frees != null){
point = frees;
frees = point.next;
point.update(trans, path);
point.next = next;
point.right = trans.right;
return point;
} else {
return new Point(trans, path, next);
}
}
private static void clearNext(Point point){
if (point.next != null){
Point old = frees;
frees = point.next;
frees.next = old;
point.next = null;
}
}
public Material material;
public float minWidth = 0.7f;
public float maxWidth = 3f;
private const float maxAngle = 20;
private const float minVertexDistance = 1f;
private const float maxVertexDistance = 3f;
private float path = 0;
private Vector3 prevousPosition;
GameObject trailObj = null;
Mesh mesh = null;
private Transform _transform;
private Transform trailTransform;
private Point start;
void Start () {
_transform = transform;
trailObj = new GameObject ("Trail");
trailTransform = trailObj.transform;
trailTransform.parent = _transform;
trailTransform.localPosition = Vector3.zero;
trailTransform.localRotation = Quaternion.identity;
trailTransform.localScale = Vector3.one;
MeshFilter meshFilter = (MeshFilter)trailObj.AddComponent (typeof(MeshFilter));
mesh = meshFilter.mesh;
trailObj.AddComponent (typeof(MeshRenderer));
trailObj.renderer.sharedMaterial = material;
prevousPosition = _transform.position;
}
protected void OnDisable(){
if (mesh){
Destroy(mesh);
}
}
public void UpdateTrail (float deltaTime, bool isVisible) {
if (_transform == null) {
return;
}
path += (_transform.position - prevousPosition).magnitude;
if (path > 1000) {
path -= 1000;
}
prevousPosition = _transform.position;
if (start == null) {
start = createPoint(_transform, path, start);
}
if (start.next == null) {
start = createPoint (_transform, path, start);
}
bool @add = false;
float sqrDistance = (start.next.position - _transform.position).sqrMagnitude;
if (sqrDistance > minVertexDistance * minVertexDistance) {
if (sqrDistance > maxVertexDistance * maxVertexDistance) {
@add = true;
} else if (Vector3.Angle (_transform.right, start.right) > maxAngle) {
@add = true;
}
}
if (@add) {
start = createPoint(_transform, path, start);
} else {
start.update (_transform, path);
}
int pointsCount = 0;
Point current = start;
while (current != null) {
current.life -= deltaTime * 0.5f;
if (current.life < -0.2f) {
clearNext(current);
}
pointsCount++;
current = current.next;
}
if (pointsCount < 2) {
//trailObj.renderer.enabled = false;
return;
}
mesh.Clear ();
if (isVisible){
updateMesh (pointsCount);
}
}
private void updateMesh (int pointsCount) {
Vector3[] vertices = new Vector3[pointsCount * 2];
Vector2[] uvs = new Vector2[pointsCount * 2];
int[] triangles = new int[(pointsCount - 1) * 6];
Color[] meshColors = new Color[pointsCount * 2];
Point point = start;
int i = 0;
Matrix4x4 mat = trailTransform.worldToLocalMatrix;
while (point != null) {
Color color = Color.Lerp (Color.white, Color.clear, 1 - point.life);
meshColors[i * 2] = color;
meshColors[(i * 2) + 1] = color;
float width = Mathf.Lerp (minWidth, maxWidth, 1 - point.life);
Vector3 half = point.right * 0.5f * width;
vertices[i * 2] = mat.MultiplyPoint (point.position - half);
vertices[(i * 2) + 1] = mat.MultiplyPoint (point.position + half);
float uvRatio = point.path * 0.25f;
uvs[i * 2] = new Vector2 (uvRatio, 0);
uvs[(i * 2) + 1] = new Vector2 (uvRatio, 1);
if (i > 0) {
int triIndex = (i - 1) * 6;
int vertIndex = i * 2;
triangles[triIndex + 0] = vertIndex - 2;
triangles[triIndex + 1] = vertIndex - 1;
triangles[triIndex + 2] = vertIndex - 0;
triangles[triIndex + 3] = vertIndex + 1;
triangles[triIndex + 4] = vertIndex + 0;
triangles[triIndex + 5] = vertIndex - 1;
}
point = point.next;
i++;
}
mesh.vertices = vertices;
mesh.colors = meshColors;
mesh.uv = uvs;
mesh.triangles = triangles;
}
class Point
{
public float life = 1f;
public float path = 0;
public Vector3 position = Vector3.zero;
public Vector3 right;
public Point next;
public Point (Transform trans, float aPath, Point next) {
this.next = next;
position = trans.position;
position.y += 0.01f;
right = trans.right;
life = 1f;
path = aPath;
}
public void update (Transform trans, float aPath) {
position = trans.position;
position.y += 0.01f;
life = 1f;
path = aPath;
}
}
}