Hello, I've been using Unity for about a month now and I continue to be delighted by its total awesomeness. It's like having a huge chocolate cake of game development goodness thumped onto your plate with nobody around telling you to mind your diet. Yum! Anyway, I've been lurking in these forums for the last few weeks and I have benefited greatly. I'd like to give a little something back. Here's a script I developed to display particle ring effects. I know you can do something similar with the regular Ellipsoid Emitter, but I find this script gives me more precise control over the end result. Besides, it was a good learning exercise. Usage is documented in the script. Comments welcomed. Mal Code (csharp): /* ----------------------------------------------------------------------------------------------------- -- ParticleRingEffect -- This script spawns "ring" particle effects, such as are commonly used for explosion shockwaves, sensor effects, propulsion effects, etc. Note that the script can be adjusted to spawn any number of ring particle systems for repeating ring effects. Use this feature carefully so as not to adversely impact framerate. Assign this script to the transform at the location where the ring effect will be centered. The ring will be generated in the plane specified by the script transform's red axis (right) and centered around the green axis (up). ------------------------------------------------------------------------------------------------------ */ // -- ringEffect -- // This must be set to reference the prefab that contains the particle system components. // Those components can be adjusted as usual to achieve the desired appearance of the // particles. Typical "expanding ring" effects are achieved in combination with this script by: // - Starting with default component settings, then // - Particle emitter: // Emit: OFF // Simulate in Worldspace: ON // One Shot: ON // - Particle Renderer: // Materials: Your favorite particle material 8^) // - Particle Animator: // Autodestruct: ON (Prevents accumulation of used-up particle systems!) public var ringEffect : Transform; // The expansion speed of the ring. public var speed : float = 2.0; // The inner and outer radii determine the width of the ring. public var innerRadius : float = 0.5; public var outerRadius : float = 1.5; // How many ring systems to spawn. "Infinite" by default. public var numberOfRings : int = 9999999; // How often a new ring should be spawned. In seconds. public var spawnRate : float = 5.0; /* ------------------------------------------------------------------------------------------------------*/ // Time at which the last spawn occurred. private var timeOfLastSpawn : float = 0.0; // Count of rings spawned so far. private var spawnCount : int = 0; /* ------------------------------------------------------------------------------------------------------ -- SpawnRing -- This function spawns a new particle effect system each time it's called. The system spawned is the prefab referenced by the public ringEffect variable. ------------------------------------------------------------------------------------------------------- */ function SpawnRing () { // Instantiate the effect prefab. var effectObject = Instantiate(ringEffect, this.transform.position, this.transform.rotation); // Parent the new effect to this script's transform. effectObject.transform.parent = this.gameObject.transform; // Get the particle emitter from the new effect object. var emitter = effectObject.GetComponent(ParticleEmitter); // Generate the particles. emitter.Emit(); // Extract the particles from the created emitter. Notice that we copy the particles into a new javascript array. // According to the Unity docs example this shouldn't be necessary, but I couldn't get it to work otherwise. // Below, when the updated p array is reassigned to the emitter particle array, the assignment failed when p was // simply assigned the value "emitter.particles". var p : Array = new Array(emitter.particles); // Loop thru the particles, giving each an initial position and velocity. for (var i=0; i<p.length; i++) { // Generate a random unit vector in the plane defined by our transform's red axis centered around the // transform's green axis. This vector serves as the basis for the initial position and velocity of the particle. var ruv : Vector3 = RandomUnitVectorInPlane(effectObject.transform, effectObject.transform.up); // Calc the initial position of the particle accounting for the specified ring radii. Note the use of Range // to get a random distance distribution within the ring. var newPos : Vector3 = effectObject.transform.position + ((ruv * innerRadius) + (ruv * Random.Range(innerRadius, outerRadius))); p[i].position = newPos; // The velocity vector is simply the unit vector modified by the speed. The velocity vector is used by the // Particle Animator component to move the particles. p[i].velocity = ruv * speed; } // Update the actual particles. emitter.particles = p.ToBuiltin(Particle); } function LateUpdate() { // Check to see if it's time to spawn a new particle system. var timeSinceLastSpawn : float = Time.time - timeOfLastSpawn; if (timeSinceLastSpawn >= spawnRate spawnCount < numberOfRings) { SpawnRing(); timeOfLastSpawn = Time.time; spawnCount++; } } function RandomUnitVectorInPlane(xform : Transform, axis : Vector3) : Vector3 { // Rotate the specified transform's axis thru a random angle. xform.Rotate(axis, Random.Range(0.0, 360.0), Space.World); // Get a copy of the rotated axis and normalize it. var ruv : Vector3 = new Vector3(xform.right.x, xform.right.y, xform.right.z); ruv.Normalize(); return (ruv); }
You're quite welcome! I was beginning to think that nobody cared about particle ring effects. I happen to like them alot. Excellent for adding that "Jetsons" feel to a game. :wink: Cheers, Mal
Well, with just a few small modifications we could probably get a chocolate cake particle effect out of it. Mal
It would be nice if your script set Autodestruct ON automatically at startup, because simply by copy-pasting the solution you get a "crazy draw call generator".
Thanks! Good suggestion. I don't seem to get a message like you describe regardless of how I run it, but I like the idea nonetheless. I added at the top a new public variable, which defaults to autodestruction: Code (csharp): // Autodestruct the particle effect system after it produces a ring. // RECOMMENDED! public var autoDestruct : boolean = true; And the following code to the SpawnRing function: Code (csharp): // Parent the new effect to this script's transform. effectObject.transform.parent = this.gameObject.transform; // NEW ==> // Get the particle animator from the new effect object. var animator = effectObject.GetComponent(ParticleAnimator); if (animator) animator.autodestruct = autoDestruct; // <== END NEW // Get the particle emitter from the new effect object. var emitter = effectObject.GetComponent(ParticleEmitter); Mal
I'm still new here myself, so I'm not sure. I know there is the Unify Wiki http://www.unifycommunity.com/wiki/index.php?title=Main_Page and it contains numerous scripts. Whether this would be appropriate for an entry there is unclear to me. Perhaps a more experienced Unity community member could comment? Is there a vetting process for the Unify Wiki scripts? Or a better place for something like this? Cheers, Mal
That's what the wiki is for. And to answer the question above, yes, certainly this script is appropriate for the wiki. It's a public wiki, you can just post it. --Eric
I modified the script to make it work on unity iphone, I will post there (wiki) this version when I finish the tests..
Hi all, I found this script very useful, so I adapted it so it will work for iPhone, and figured I'd drop it back to the community in case anyone needs it. Thanks Malveka for putting this together. Cheers Galen Code (csharp): /* ----------------------------------------------------------------------------------------------------- -- ParticleRingEffect -- This script spawns "ring" particle effects, such as are commonly used for explosion shockwaves, sensor effects, propulsion effects, etc. Note that the script can be adjusted to spawn any number of ring particle systems for repeating ring effects. Use this feature carefully so as not to adversely impact framerate. Assign this script to the transform at the location where the ring effect will be centered. The ring will be generated in the plane specified by the script transform's red axis (right) and centered around the green axis (up). ------------------------------------------------------------------------------------------------------ */ // -- ringEffect -- // This must be set to reference the prefab that contains the particle system components. // Those components can be adjusted as usual to achieve the desired appearance of the // particles. Typical "expanding ring" effects are achieved in combination with this script by: // - Starting with default component settings, then // - Particle emitter: // Emit: OFF // Simulate in Worldspace: ON // One Shot: ON // - Particle Renderer: // Materials: Your favorite particle material 8^) // - Particle Animator: // Autodestruct: ON (Prevents accumulation of used-up particle systems!) public var ringEffect : GameObject; // The expansion speed of the ring. public var speed : float = 2.0; // The inner and outer radii determine the width of the ring. public var innerRadius : float = 0.5; public var outerRadius : float = 1.5; // How many ring systems to spawn. "Infinite" by default. public var numberOfRings : int = 9999999; // How often a new ring should be spawned. In seconds. if 0 then OnCollisionEnter() is run. public var spawnRate : float = 5.0; // Autodestruct the particle effect system after it produces a ring. // RECOMMENDED! public var autoDestruct : boolean = true; /* ------------------------------------------------------------------------------------------------------*/ // Time at which the last spawn occurred. private var timeOfLastSpawn : float = 0.0; // Count of rings spawned so far. private var spawnCount : int = 0; function Awake() { //ringEffect = gameObject.transform; } /* ------------------------------------------------------------------------------------------------------ -- SpawnRing -- This function spawns a new particle effect system each time it's called. The system spawned is the prefab referenced by the public ringEffect variable. ------------------------------------------------------------------------------------------------------- */ function SpawnRing () { // Instantiate the effect prefab. var effectObject : GameObject = Instantiate(ringEffect, this.transform.position, this.transform.rotation); // Parent the new effect to this script's transform. // NOTE: THE NEXT STEP IS NOT NECESSARY UNLESS THE EFFECT NEEDS TO MOVE WITH THE ORIGINAL OBJECT... effectObject.transform.parent = this.gameObject.transform; // NEW ==> // Get the particle animator from the new effect object. var animator : ParticleAnimator = effectObject.GetComponent(ParticleAnimator); if (animator) animator.autodestruct = autoDestruct; // <== END NEW // Get the particle emitter from the new effect object. var emitter : ParticleEmitter = effectObject.GetComponent(ParticleEmitter); // Generate the particles. emitter.Emit(); // Extract the particles from the created emitter. Notice that we copy the particles into a new javascript array. // According to the Unity docs example this shouldn't be necessary, but I couldn't get it to work otherwise. // Below, when the updated p array is reassigned to the emitter particle array, the assignment failed when p was // simply assigned the value "emitter.particles". var p : Array = new Array(emitter.particles); // Loop thru the particles, giving each an initial position and velocity. for (var i=0; i<p.length; i++) { // Generate a random unit vector in the plane defined by our transform's red axis centered around the // transform's green axis. This vector serves as the basis for the initial position and velocity of the particle. var ruv : Vector3 = RandomUnitVectorInPlane(effectObject.transform, effectObject.transform.up); // Calc the initial position of the particle accounting for the specified ring radii. Note the use of Range // to get a random distance distribution within the ring. var newPos : Vector3 = effectObject.transform.position + ((ruv * innerRadius) + (ruv * Random.Range(innerRadius, outerRadius))); var tmpParticle : Particle = p[i]; tmpParticle.position = newPos; // The velocity vector is simply the unit vector modified by the speed. The velocity vector is used by the // Particle Animator component to move the particles. tmpParticle.velocity = ruv * speed; p[i] = tmpParticle; } // Update the actual particles. emitter.particles = p.ToBuiltin(Particle); } // Update based execution (with Spawn rate control) function LateUpdate() { if(spawnRate == 0); // shutoff option else { // Check to see if it's time to spawn a new particle system. var timeSinceLastSpawn : float = Time.time - timeOfLastSpawn; if (timeSinceLastSpawn >= spawnRate spawnCount < numberOfRings) { SpawnRing(); timeOfLastSpawn = Time.time; spawnCount++; } } } function RandomUnitVectorInPlane(xform : Transform, axis : Vector3) : Vector3 { // Rotate the specified transform's axis thru a random angle. xform.Rotate(axis, Random.Range(0.0, 360.0), Space.World); // Get a copy of the rotated axis and normalize it. var ruv : Vector3 = new Vector3(xform.right.x, xform.right.y, xform.right.z); ruv.Normalize(); return (ruv); } // Optional: OnCollisionXxxxx //function OnCollisionEnter() { // SpawnRing(); //} [/code]
This seems like a cool script to use but does someone have a working example? I attach it to my script to test but I don't know what to use for Ring Effect. I used a Particle Effect prefab that I had lying around but it didn't do anything Particle Ring-ish. Also, I get the following error msg in the console: NullReferenceException: The prefab you want to instantiate is null. for this line in the script: var effectObject : GameObject = Instantiate(ringEffect, this.transform.position, this.transform.rotation); I'd like to use this ... can anyone show me how they incorporated it into their work? Thanks,
Here's the C# version. You may need to write a line of code to call the SpawnRing method. Code (csharp): using UnityEngine; using System.Collections; public class ParticleRings : MonoBehaviour { /* ----------------------------------------------------------------------------------------------------- -- ParticleRingEffect -- This script spawns "ring" particle effects, such as are commonly used for explosion shockwaves, sensor effects, propulsion effects, etc. Note that the script can be adjusted to spawn any number of ring particle systems for repeating ring effects. Use this feature carefully so as not to adversely impact framerate. Assign this script to the transform at the location where the ring effect will be centered. The ring will be generated in the plane specified by the script transform's red axis (right) and centered around the green axis (up). ------------------------------------------------------------------------------------------------------ */ // -- ringEffect -- // This must be set to reference the prefab that contains the particle system components. // Those components can be adjusted as usual to achieve the desired appearance of the // particles. Typical "expanding ring" effects are achieved in combination with this script by: // - Starting with default component settings, then // - Particle emitter: // Emit: OFF // Simulate in Worldspace: ON // One Shot: ON // - Particle Renderer: // Materials: Your favorite particle material 8^) // - Particle Animator: // Autodestruct: ON (Prevents accumulation of used-up particle systems!) public GameObject ringEffect; // The expansion speed of the ring. public float speed = 2.0f; // The inner and outer radii determine the width of the ring. public float innerRadius = 0.5f; public float outerRadius = 1.5f; // How many ring systems to spawn. "Infinite" by default. public int numberOfRings = 9999999; // How often a new ring should be spawned. In seconds. public float spawnRate = 5.0f; /* ------------------------------------------------------------------------------------------------------*/ // Time at which the last spawn occurred. private float timeOfLastSpawn = 0.0f; // Count of rings spawned so far. private int spawnCount = 0; private bool isSpawned = false; /* ------------------------------------------------------------------------------------------------------ -- SpawnRing -- This function spawns a new particle effect system each time it's called. The system spawned is the prefab referenced by the public ringEffect variable. ------------------------------------------------------------------------------------------------------- */ private void SpawnRing () { // Instantiate the effect prefab. GameObject effectObject = ((Transform) Instantiate(ringEffect.transform, this.transform.position, this.transform.rotation)).gameObject; // Parent the new effect to this script's transform. effectObject.transform.parent = this.gameObject.transform; // Get the particle emitter from the new effect object. ParticleEmitter emitter = effectObject.particleEmitter; // Generate the particles. emitter.Emit(); // Extract the particles from the created emitter. Notice that we copy the particles into a new javascript array. // According to the Unity docs example this shouldn't be necessary, but I couldn't get it to work otherwise. // Below, when the updated p array is reassigned to the emitter particle array, the assignment failed when p was // simply assigned the value "emitter.particles". Particle[] p = new Particle[emitter.particles.Length]; // Loop thru the particles, giving each an initial position and velocity. for (var i=0; i < p.Length; i++) { p[i] = emitter.particles[i]; // Generate a random unit vector in the plane defined by our transform's red axis centered around the // transform's green axis. This vector serves as the basis for the initial position and velocity of the particle. Vector3 ruv = RandomUnitVectorInPlane(effectObject.transform, effectObject.transform.up); // Calc the initial position of the particle accounting for the specified ring radii. Note the use of Range // to get a random distance distribution within the ring. Vector3 newPos = effectObject.transform.position + ((ruv * innerRadius) + (ruv * Random.Range(innerRadius, outerRadius))); p[i].position = newPos; //emitter.particles[i].position; p[i].angularVelocity = Random.Range(30f, 60f); // The velocity vector is simply the unit vector modified by the speed. The velocity vector is used by the // Particle Animator component to move the particles. p[i].velocity = ruv * speed; //emitter.particles[i].velocity; } // Update the actual particles. emitter.particles = p; emitter.worldVelocity = new Vector3(0f, Random.Range(10f, 20f), 0); } void LateUpdate() { // Check to see if it's time to spawn a new particle system. float timeSinceLastSpawn = Time.time - timeOfLastSpawn; if (timeSinceLastSpawn >= spawnRate spawnCount < numberOfRings) { SpawnRing(); timeOfLastSpawn = Time.time; spawnCount++; } } private Vector3 RandomUnitVectorInPlane(Transform xform, Vector3 axis) { // Rotate the specified transform's axis thru a random angle. xform.Rotate(axis, Random.Range(0.0f, 360.0f), Space.World); // Get a copy of the rotated axis and normalize it. Vector3 ruv = new Vector3(xform.right.x, xform.right.y, xform.right.z); ruv.Normalize(); return (ruv); } }