Skip to content

Instantly share code, notes, and snippets.

@N-Carter
Created April 24, 2011 10:46
Show Gist options
  • Save N-Carter/939478 to your computer and use it in GitHub Desktop.
Save N-Carter/939478 to your computer and use it in GitHub Desktop.
A component that acts like a ParticleEmitter but injects particles into other emitters
using UnityEngine;
using System.Collections;
// This component can emit particles into one or more ParticleEmitters. As several ParticleInjectors can emit to a shared set of
// ParticleEmitters, this allows you to save draw calls by having fewer separate particle systems.
//
// Note that when a ParticleEmitter's Simulate In World Space checkbox is off, it's OK to attach ParticleInjectors to separate
// hierarchies and move them independently. If it's turned on, the ParticleInjectors really need to be children of the emitter
// for the emission behaviour to make sense.
[AddComponentMenu("Particle Systems/Particle Injector")]
public class ParticleInjector : MonoBehaviour
{
// Uses this.particleEmitter if m_Emitters is zero-sized, or disables itself if there isn't one:
[SerializeField] protected ParticleEmitter[] m_Emitters;
[SerializeField] protected bool m_UseEmitterSettings = true; // Ignore local settings and just use those from each emitter
[SerializeField] protected bool m_SameForAllEmitters = false; // Give the same particle to all emitters instead of a random one for each
// The following settings should behave identically to those from ParticleEmitter:
[SerializeField] protected bool m_Emit;
[SerializeField] protected float m_MinSize = 1.0f;
[SerializeField] protected float m_MaxSize = 1.0f;
[SerializeField] protected float m_MinEnergy = 1.0f;
[SerializeField] protected float m_MaxEnergy = 1.0f;
[SerializeField] protected int m_MinEmission = 10;
[SerializeField] protected int m_MaxEmission = 10;
[SerializeField] protected Vector3 m_WorldVelocity;
[SerializeField] protected Vector3 m_LocalVelocity;
[SerializeField] protected Vector3 m_RndVelocity;
[SerializeField] protected Vector3 m_TangentVelocity;
[SerializeField] protected float m_AngularVelocity;
[SerializeField] protected float m_RndAngularVelocity;
// These settings can't be read from the emitter, so they're always used no matter what m_UseEmitterSettings is set to:
[SerializeField] protected Color m_Colour;
[SerializeField] protected Vector3 m_Ellipsoid;
protected delegate void RandomParticle(ParticleEmitter emitter, out Particle particle);
protected RandomParticle m_RandomParticle;
protected void Start()
{
if(m_Emitters == null || m_Emitters.Length == 0)
{
if(particleEmitter)
m_Emitters = new ParticleEmitter[] {particleEmitter};
else
{
enabled = false;
return;
}
}
if(m_UseEmitterSettings)
m_RandomParticle = RandomParticleFromEmitterSettings;
else
m_RandomParticle = RandomParticleFromLocalSettings;
if(m_Emit)
StartCoroutine(Emitter());
}
protected IEnumerator Emitter()
{
// FIXME: is this a reasonable way to control particle emission rate? What happens if the emission rate is zero?
while(m_Emit)
{
EmitRandomParticle();
yield return new WaitForSeconds(1.0f / Random.Range(m_MinEmission, m_MaxEmission));
}
}
protected void EmitRandomParticle()
{
Particle particle;
m_RandomParticle(m_Emitters[0], out particle);
foreach(var emitter in m_Emitters)
{
emitter.Emit(particle.position,
particle.velocity,
particle.size,
particle.energy,
particle.color,
particle.rotation,
particle.angularVelocity);
if(!m_SameForAllEmitters)
m_RandomParticle(emitter, out particle);
}
}
protected void RandomParticleFromEmitterSettings(ParticleEmitter emitter, out Particle particle)
{
particle = new Particle();
Vector3 randomVelocity = Vector3.Scale(Random.insideUnitSphere, emitter.rndVelocity);
if(emitter.useWorldSpace)
{
particle.position = transform.TransformPoint(Vector3.Scale(Random.insideUnitSphere, m_Ellipsoid));
particle.velocity = emitter.worldVelocity + transform.rotation * (emitter.localVelocity + randomVelocity);
}
else
{
// FIXME: check that this stuff really is working in local space.
particle.position = Vector3.Scale(Random.insideUnitSphere, m_Ellipsoid);
particle.velocity = transform.InverseTransformDirection(emitter.worldVelocity) +
transform.localRotation * (emitter.localVelocity + randomVelocity);
}
particle.energy = Random.Range(emitter.minEnergy, emitter.maxEnergy);
// Do something with particle.startEnergy?
particle.size = Random.Range(emitter.minSize, emitter.maxSize);
particle.rotation = (emitter.rndRotation ? Random.Range(-180.0f, 180.0f) : 0.0f); // Is this test useful?
particle.angularVelocity = m_AngularVelocity + Random.Range(-emitter.rndAngularVelocity, emitter.rndAngularVelocity);
particle.color = m_Colour;
}
protected void RandomParticleFromLocalSettings(ParticleEmitter emitter, out Particle particle)
{
particle = new Particle();
Vector3 randomVelocity = Vector3.Scale(Random.insideUnitSphere, m_RndVelocity);
if(emitter.useWorldSpace)
{
particle.position = transform.TransformPoint(Vector3.Scale(Random.insideUnitSphere, m_Ellipsoid));
particle.velocity = m_WorldVelocity + transform.rotation * (m_LocalVelocity + randomVelocity);
}
else
{
particle.position = Vector3.Scale(Random.insideUnitSphere, m_Ellipsoid);
particle.velocity = transform.InverseTransformDirection(m_WorldVelocity) + transform.localRotation * (m_LocalVelocity + randomVelocity);
}
particle.energy = Random.Range(m_MinEnergy, m_MaxEnergy);
particle.size = Random.Range(m_MinSize, m_MaxSize);
particle.rotation = Random.Range(-180.0f, 180.0f);
particle.angularVelocity = m_AngularVelocity + Random.Range(-m_RndAngularVelocity, m_RndAngularVelocity);
particle.color = m_Colour;
}
public bool emit
{
get {return m_Emit;}
set
{
if(value)
{
if(!m_Emit)
{
m_Emit = true;
StartCoroutine(Emitter());
}
}
else
m_Emit = false;
}
}
#region Gizmos
protected void OnDrawGizmosSelected()
{
Gizmos.color = Color.green;
Gizmos.DrawRay(transform.position, m_WorldVelocity);
Gizmos.color = Color.red;
if(m_Ellipsoid != Vector3.zero)
{
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, m_Ellipsoid);
Gizmos.DrawWireSphere(Vector3.zero, 1.0f);
}
else
{
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
Gizmos.DrawWireCube(Vector3.zero, Vector3.one * 0.1f);
}
Gizmos.color = Color.yellow;
Gizmos.DrawRay(Vector3.zero, m_LocalVelocity);
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment