Created
April 24, 2011 10:46
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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