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; } } }