using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace ParticlePlayground {
[Serializable]
public class ParticlePlaygroundTrail
{
///
/// Determines if this ParticlePlaygroundTrail should update.
///
[HideInInspector] public bool update = true;
///
/// The GameObject of this trail.
///
[HideInInspector] public GameObject trailGameObject;
///
/// The Transform of this trail.
///
[HideInInspector] public Transform trailTransform;
///
/// The Mesh Renderer component of this trail.
///
[HideInInspector] public MeshRenderer trailRenderer;
///
/// The Mesh Filter component of this trail.
///
[HideInInspector] public MeshFilter trailMeshFilter;
///
/// The Mesh component of this trail.
///
[HideInInspector] public Mesh trailMesh;
///
/// The particle this trail is following.
///
[HideInInspector] public int particleId;
///
/// The minimum point cache limit.
///
[HideInInspector] public int minPointCache = 2;
///
/// The maximum point cache limit.
///
[HideInInspector] public int maxPointCache = 32767;
[NonSerialized] public List trailPoints = new List();
[NonSerialized] public Vector3[] meshVerticesCache;
[NonSerialized] public Vector3[] meshNormalsCache;
[NonSerialized] public Vector2[] meshUvsCache;
[NonSerialized] public int[] meshTrianglesCache;
[NonSerialized] public Color32[] meshColorsCache;
private int _pointCache = 200;
private int _birthIterator;
private int _deathIterator;
private float _particleTime;
private Vector3 _particlePosition;
private Vector3 _previousParticlePosition;
private Vector3 _particleDirection;
private Vector3 _lastAddedPointPosition;
private Vector3 _lastAddedPointDirection;
private bool _isDead = false;
private bool _isReady = false;
private float _timeCached;
///
/// Initializes a new instance of the class.
///
public ParticlePlaygroundTrail ()
{
UpdateCache();
}
///
/// Initializes a new instance of the class and specifies the available point cache.
/// The mesh's available vertices, normals, uvs, triangles and colors will be based on the specified point cache.
///
/// Mesh point cache (vertices, normals and uvs will be multiplied by two, triangles by six).
public ParticlePlaygroundTrail (int pointCache)
{
_pointCache = Mathf.Clamp (pointCache, minPointCache, maxPointCache);
UpdateCache();
}
///
/// Updates the mesh cache. This is done upon creation where cache lengths will be based on the point cache.
///
public void UpdateCache ()
{
_timeCached = PlaygroundC.globalTime;
meshVerticesCache = new Vector3[_pointCache*2];
meshNormalsCache = new Vector3[_pointCache*2];
meshUvsCache = new Vector2[_pointCache*2];
meshTrianglesCache = new int[(_pointCache-1)*6];
meshColorsCache = new Color32[_pointCache*2];
_isReady = true;
}
///
/// Updates the trail mesh. This is done each frame from the main-thread.
///
public void UpdateMesh ()
{
trailMesh.Clear();
trailMesh.vertices = meshVerticesCache;
trailMesh.uv = meshUvsCache;
trailMesh.triangles = meshTrianglesCache;
trailMesh.colors32 = meshColorsCache;
trailMesh.normals = meshNormalsCache;
}
///
/// Recalculates the bounds on the trail mesh. This is done automatically when triangles are set into a mesh.
///
public void RecalculateBounds ()
{
trailMesh.RecalculateBounds();
}
///
/// Clears the trail mesh.
///
public void ClearMesh ()
{
_birthIterator = 0;
_deathIterator = 0;
meshVerticesCache = new Vector3[0];
meshNormalsCache = new Vector3[0];
meshUvsCache = new Vector2[0];
meshTrianglesCache = new int[0];
meshColorsCache = new Color32[0];
}
///
/// Sets the first point in the trail. This will add two initial points, one starting point and one ending point which will follow the assigned particle.
///
/// Position.
/// Direction.
/// Start width.
/// Lifetime.
public void SetFirstPoint (Vector3 pos, Vector3 dir, float startWidth, float lifetime, float creationTime)
{
_particleDirection = dir;
AddPoint (pos, startWidth, lifetime, creationTime);
AddPoint (pos, startWidth, lifetime, creationTime);
_birthIterator = 2;
_deathIterator = 0;
}
///
/// Sets the last point in the trail and then kills it. This will add one last point which won't follow the assigned particle.
///
/// Position.
/// Direction.
/// Start width.
/// Lifetime.
public void SetLastPoint (Vector3 pos, Vector3 dir, float startWidth, float lifetime, float creationTime)
{
_particleDirection = dir;
AddPoint (pos, startWidth, lifetime, creationTime);
Die ();
}
///
/// Adds a point into the end of the trail.
///
/// Position.
/// Width.
/// Lifetime.
public void AddPoint (Vector3 position, float width, float lifetime, float creationTime)
{
if (_birthIterator >= _pointCache || _isDead)
return;
trailPoints.Add (new TrailPoint(position, lifetime, width, creationTime));
AddPoint(position);
}
///
/// Adds a point into the end of the trail.
///
/// Position.
/// Initial Velocity.
/// Width.
/// Lifetime.
public void AddPoint (Vector3 position, Vector3 velocity, float width, float lifetime, float creationTime)
{
if (_birthIterator >= _pointCache || _isDead)
return;
trailPoints.Add (new TrailPoint(position, velocity, lifetime, width, creationTime));
AddPoint(position);
}
void AddPoint (Vector3 position)
{
_lastAddedPointDirection = position-_previousParticlePosition;
_lastAddedPointPosition = position;
meshVerticesCache[_birthIterator*2] = position;
meshVerticesCache[(_birthIterator*2)+1] = position;
meshNormalsCache[_birthIterator*2] = -Vector3.forward;
meshNormalsCache[(_birthIterator*2)+1] = -Vector3.forward;
meshUvsCache[_birthIterator*2] = new Vector2(1f, 0f);
meshUvsCache[(_birthIterator*2)+1] = new Vector2(0f, 1f);
meshColorsCache[_birthIterator*2] = new Color32();
meshColorsCache[(_birthIterator*2)+1] = new Color32();
if (trailPoints.Count>1) {
int vertexIndex = (_birthIterator)*2;
int triIndex = (_birthIterator-1)*6;
meshTrianglesCache[triIndex] = vertexIndex -2;
meshTrianglesCache[triIndex+1] = vertexIndex -1;
meshTrianglesCache[triIndex+2] = vertexIndex;
meshTrianglesCache[triIndex+3] = vertexIndex;
meshTrianglesCache[triIndex+4] = vertexIndex -1;
meshTrianglesCache[triIndex+5] = vertexIndex +1;
}
NextPoint();
}
public void RemovePoint (int index)
{
if (_deathIterator < _birthIterator-2)
{
meshVerticesCache[_deathIterator*2] = meshVerticesCache[(_deathIterator*2)+2];
meshVerticesCache[(_deathIterator*2)+1] = meshVerticesCache[(_deathIterator*2)+3];
meshColorsCache[_deathIterator*2] = new Color32();
meshColorsCache[(_deathIterator*2)+1] = new Color32();
_deathIterator++;
}
}
///
/// Sets the color at specified index. This is done automatically through the trail calculation loop.
///
/// Index.
/// Color.
public void SetColor (int index, Color32 color)
{
meshColorsCache[index*2] = color;
meshColorsCache[(index*2)+1] = color;
}
///
/// Makes the iterator jump to next point. The iterator controls which point is following the particle.
///
public void NextPoint ()
{
_birthIterator++;
}
///
/// Gets the paired particle's current time.
///
/// The paired particle's current time.
public float GetParticleTime ()
{
return _particleTime;
}
///
/// Sets the paired particle's current time.
///
/// Time.
public void SetParticleTime (float time)
{
_particleTime = time;
}
///
/// Gets the paired particle's current position.
///
/// The paired particle's position.
public Vector3 GetParticlePosition ()
{
return _particlePosition;
}
///
/// Sets the paired particle's position.
///
/// Position.
public void SetParticlePosition (Vector3 position)
{
if (_isDead)
return;
_previousParticlePosition = _particlePosition;
_particlePosition = position;
_particleDirection = (position-_previousParticlePosition).normalized;
}
///
/// Sets the paired particle's direction.
///
/// Direction.
public void SetParticleDirection (Vector3 direction)
{
_particleDirection = direction;
}
///
/// Gets the last added point position.
///
/// The last added point position.
public Vector3 GetLastAddedPointPosition ()
{
return _lastAddedPointPosition;
}
///
/// Gets the direction of the particle.
///
/// The particle direction.
public Vector3 GetParticleDirection ()
{
return _particleDirection;
}
public Vector3 GetLastAddedPointDirection ()
{
return _lastAddedPointDirection;
}
///
/// Gets the current path deviation angle based on the last added point direction and the current direction of the particle.
///
/// The path deviation angle.
public float GetPathDeviation () {
return Vector3.Angle(_lastAddedPointDirection, _particleDirection);
}
///
/// Gets the birth iterator used for iterating through the mesh arrays to set new vertex positions.
///
/// The birth iterator.
public int GetBirthIterator ()
{
return _birthIterator;
}
///
/// Gets the death iterator used for iterating through the mesh arrays to remove old vertex positions.
///
/// The death iterator.
public int GetDeathIterator ()
{
return _deathIterator;
}
///
/// Gets the point cache amount. The point cache is set at the trail's creation and determines how many vertices, triangles, uvs, normals and colors the trail mesh can have.
///
/// The point cache amount.
public int GetPointCache ()
{
return _pointCache;
}
///
/// Gets the time this trail was cached.
///
/// The cached time.
public float TimeCached ()
{
return _timeCached;
}
///
/// Determines whether this trail can remove a point at specified index.
///
/// true if this trail can remove a point at the specified index; otherwise, false.
/// Point.
public bool CanRemovePoint (int point)
{
return trailPoints[point].CanRemove();
}
///
/// Determines whether this trail can be removed. This will check if the last point in the trail has reached the end of its lifetime.
///
/// true if this trail can be removed; otherwise, false.
public bool CanRemoveTrail ()
{
if (trailPoints.Count == 0 || !_isReady)
return false;
return trailPoints[trailPoints.Count-1].CanRemove();
}
///
/// Wakes up the trail from being dead.
///
public void WakeUp ()
{
_isDead = false;
}
///
/// Makes the trail stop following its assigned particle.
///
public void Die ()
{
_isDead = true;
}
///
/// Determines whether this trail is dead.
///
/// true if this trail is dead; otherwise, false.
public bool IsDead ()
{
return _isDead;
}
}
}