using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace ParticlePlayground {
public class PlaygroundFollow : MonoBehaviour {
///
/// Reference to the particle system.
///
public PlaygroundParticlesC particles;
///
/// Reference to an existing GameObject. This will be cloned to be used on every particle.
///
public GameObject referenceObject;
///
/// The lifetime of the followers. Set 0 to follow during each particle's individual lifetime.
///
public float followerLifetime = 0;
///
/// The size of the cache. Set 0 to automatically set the needed amount.
///
public int cacheSize = 0;
///
/// Determines if the Playground Followers should broadcast to any event listeners.
///
public bool sendEvents = false;
///
/// This event occurs when followers are born and sendEvents are set to true.
///
public event OnPlaygroundFollower followerEventBirth;
///
/// This event occurs when follower dies and sendEvents are set to true.
///
public event OnPlaygroundFollower followerEventDeath;
///
/// The reference to the trail renderer (if existing)
///
TrailRenderer referenceTrailRenderer;
///
/// If the follower has a Trail Renderer component, this sets trail time once the follower is active again.
///
float trailTime = 0;
///
/// The list of active followers.
///
List followers = new List();
///
/// As Playground is running in a multithreaded environment we need a queue for instantiation (which cannot be called from a different thread).
///
List waitingFollowers = new List();
PlaygroundFollower[] referenceObjectsCache;
PlaygroundFollower[] queue = new PlaygroundFollower[0];
int cacheIndex = 0;
PlaygroundEventC birthEvent;
PlaygroundEventC deathEvent;
Transform followerParent;
void Start ()
{
if (referenceObject == null || particles == null)
return;
// Create and setup the birth event
birthEvent = PlaygroundC.CreateEvent(particles);
birthEvent.broadcastType = EVENTBROADCASTC.EventListeners;
birthEvent.eventType = EVENTTYPEC.Birth;
// Create and setup the death event
deathEvent = PlaygroundC.CreateEvent(particles);
deathEvent.broadcastType = EVENTBROADCASTC.EventListeners;
deathEvent.eventType = EVENTTYPEC.Death;
// Hook up the event listeners to the delegates
birthEvent.particleEvent += OnParticleDidBirth;
deathEvent.particleEvent += OnParticleDidDie;
// Create a parent for all followers (for Hierarchy convenience)
followerParent = new GameObject("Followers").transform;
followerParent.parent = transform;
// Get the trail renderer (if available) and its time
referenceTrailRenderer = referenceObject.GetComponent();
if (referenceTrailRenderer!=null)
trailTime = referenceTrailRenderer.time;
// Set an extra amount of followers if required (a trail's time will exceed a particle's)
int extra = followerLifetime<=0?
Mathf.CeilToInt(Mathf.Abs (particles.lifetime-trailTime)+(trailTime-particles.lifetime))+2 :
Mathf.CeilToInt(Mathf.Abs (particles.lifetime-followerLifetime)+(followerLifetime-particles.lifetime))+2 ;
if (particles.lifetime<=1f) extra++;
// Create the follower cache (this will be iterated through and reused whenever a particle rebirths)
referenceObjectsCache = new PlaygroundFollower[cacheSize>0? cacheSize : particles.particleCount+Mathf.CeilToInt(particles.particleCount*extra)];
for (int i = 0; i(), 0, 0);
referenceObjectsCache[i].transform.parent = followerParent;
if (referenceObjectsCache[i].trailRenderer!=null)
referenceObjectsCache[i].trailRenderer.time = 0;
referenceObjectsCache[i].gameObject.SetActive(false);
}
}
///
/// Event listener for particle birth.
///
/// Particle.
void OnParticleDidBirth (PlaygroundEventParticle particle)
{
waitingFollowers.Add (new PlaygroundFollower(null, null, null, followerLifetime<=0? particle.totalLifetime+trailTime : followerLifetime, particle.particleId));
}
///
/// Event listener for particle death.
///
/// Particle.
void OnParticleDidDie (PlaygroundEventParticle particle)
{
int followerId = GetFollowerWithId(particle.particleId);
if (followerId<0) return;
followers[followerId].enabled = false;
}
///
/// Gets the follower which has the passed in particle identifier.
///
/// The follower with particle identifier.
/// Particle identifier.
int GetFollowerWithId (int particleId)
{
float lowestLife = 999f;
int returnIndex = -1;
for (int i = 0; i0)
{
queue = waitingFollowers.ToArray();
}
}
void LateUpdate ()
{
UpdateFollowers();
}
void UpdateFollowers ()
{
// Follow, lifetime, remove
for (int i = 0; i0)
{
if (queue.Length!=waitingFollowers.Count) return;
int inQueueThisFrame = waitingFollowers.Count;
foreach (PlaygroundFollower wFollower in queue)
{
AddFollower (wFollower, followers.Count-1);
}
if (inQueueThisFrame==waitingFollowers.Count)
waitingFollowers = new List();
else waitingFollowers.RemoveRange (0, inQueueThisFrame-1);
queue = new PlaygroundFollower[0];
}
}
void AddFollower (PlaygroundFollower follower, int i)
{
if (follower==null) return;
followers.Add (follower.Clone());
followers[followers.Count-1].enabled = true;
followers[followers.Count-1].gameObject = referenceObjectsCache[cacheIndex].gameObject;
followers[followers.Count-1].gameObject.SetActive(true);
followers[followers.Count-1].transform = referenceObjectsCache[cacheIndex].transform;
followers[followers.Count-1].trailRenderer = referenceObjectsCache[cacheIndex].trailRenderer;
followers[followers.Count-1].particleId = follower.particleId;
followers[followers.Count-1].transform.position = particles.playgroundCache.position[followers[followers.Count-1].particleId];
if (followers[followers.Count-1].trailRenderer!=null)
followers[followers.Count-1].trailRenderer.time = trailTime;
if (sendEvents && followerEventBirth!=null)
followerEventBirth(followers[followers.Count-1]);
NextCacheIndex();
}
void RemoveFollower (int i)
{
if (sendEvents && followerEventDeath!=null)
followerEventDeath(followers[i]);
followers[i].enabled = false;
if (followers[i].trailRenderer!=null)
followers[i].trailRenderer.time = 0;
followers[i].gameObject.SetActive(false);
followers.RemoveAt(i);
}
void NextCacheIndex ()
{
cacheIndex = (cacheIndex+1)%referenceObjectsCache.Length;
}
///
/// Gets an active follower at index. This will only return active followers.
///
/// The active follower.
/// Index.
public PlaygroundFollower GetActiveFollower (int index)
{
index = Mathf.Clamp (index, 0, followers.Count);
return followers[index];
}
///
/// Gets a cached follower at index. This can return inactive followers waiting for their turn to be enabled.
///
/// The cached follower.
/// Index.
public PlaygroundFollower GetCachedFollower (int index)
{
index = Mathf.Clamp (index, 0, referenceObjectsCache.Length);
return referenceObjectsCache[index];
}
///
/// Gets the amount of active followers.
///
/// The active followers count.
public int GetActiveFollowersCount ()
{
return followers.Count;
}
///
/// Gets the amount of cached followers.
///
/// The cached followers count.
public int GetCachedFollowersCount ()
{
return referenceObjectsCache.Length;
}
}
///
/// Playground follower class.
///
public class PlaygroundFollower {
public bool enabled = true;
public float lifetime;
public Transform transform;
public GameObject gameObject;
public TrailRenderer trailRenderer;
public int particleId;
///
/// Initializes a new instance of the class.
///
/// Transform to reposition.
/// Start lifetifetime.
/// Particle identifier to follow.
public PlaygroundFollower (Transform setTransform, GameObject setGameObject, TrailRenderer setTrailRenderer, float setLifetime, int setParticleId)
{
transform = setTransform;
gameObject = setGameObject;
trailRenderer = setTrailRenderer;
lifetime = setLifetime;
particleId = setParticleId;
}
///
/// Clones this instance.
///
public PlaygroundFollower Clone ()
{
return new PlaygroundFollower (transform, gameObject, trailRenderer, lifetime, particleId);
}
}
///
/// Event delegate for sending a PlaygroundFollower to any event listeners.
///
public delegate void OnPlaygroundFollower(PlaygroundFollower follower);
}