Search Unity

Particle Ring Effect Script

Discussion in 'Scripting' started by Malveka, Nov 23, 2009.

  1. Malveka

    Malveka

    Joined:
    Nov 6, 2009
    Posts:
    191
    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! :D

    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):
    1.  
    2. /* -----------------------------------------------------------------------------------------------------
    3.     -- ParticleRingEffect --
    4.    
    5.     This script spawns "ring" particle effects, such as are commonly used for explosion
    6.     shockwaves, sensor effects,  propulsion effects, etc.  Note that the script can be
    7.     adjusted to spawn any number of ring particle systems for repeating ring effects.
    8.     Use this feature carefully so as not to adversely impact framerate.  
    9.    
    10.     Assign this script to the transform at the location where the ring effect will be
    11.     centered.  The ring will be generated in the plane specified by the script transform's
    12.     red axis (right) and centered around the green axis (up).  
    13.    ------------------------------------------------------------------------------------------------------ */
    14.  
    15. // -- ringEffect --
    16. // This must be set to reference the prefab that contains the particle system components.
    17. // Those components can be adjusted as usual to achieve the desired appearance of the
    18. // particles.  Typical "expanding ring" effects are achieved in combination with this script by:
    19. //  - Starting with default component settings, then
    20. //  - Particle emitter:
    21. //      Emit: OFF
    22. //      Simulate in Worldspace: ON
    23. //      One Shot: ON
    24. //  - Particle Renderer:
    25. //      Materials: Your favorite particle material 8^)
    26. //  - Particle Animator:
    27. //      Autodestruct: ON (Prevents accumulation of used-up particle systems!)
    28. public var ringEffect : Transform;
    29.  
    30. // The expansion speed of the ring.
    31. public var speed : float = 2.0;
    32.  
    33. // The inner and outer radii determine the width of the ring.
    34. public var innerRadius : float = 0.5;
    35. public var outerRadius : float = 1.5;
    36.  
    37. // How many ring systems to spawn.  "Infinite" by default.
    38. public var numberOfRings : int = 9999999;
    39.  
    40. // How often a new ring should be spawned.  In seconds.
    41. public var spawnRate : float = 5.0;
    42.  
    43. /* ------------------------------------------------------------------------------------------------------*/
    44. // Time at which the last spawn occurred.  
    45. private var timeOfLastSpawn : float = 0.0;
    46.  
    47. // Count of rings spawned so far.
    48. private var spawnCount : int = 0;
    49.  
    50.  
    51. /* ------------------------------------------------------------------------------------------------------
    52.     -- SpawnRing --
    53.    
    54.     This function spawns a new particle effect system each time it's called.  The system
    55.     spawned is the prefab referenced by the public ringEffect variable.
    56.    ------------------------------------------------------------------------------------------------------- */
    57. function SpawnRing () {
    58.     // Instantiate the effect prefab.
    59.     var effectObject = Instantiate(ringEffect, this.transform.position, this.transform.rotation);
    60.    
    61.     // Parent the new effect to this script's transform.  
    62.     effectObject.transform.parent = this.gameObject.transform;
    63.    
    64.     // Get the particle emitter from the new effect object.
    65.     var emitter = effectObject.GetComponent(ParticleEmitter);
    66.    
    67.     // Generate the particles.
    68.     emitter.Emit();
    69.    
    70.     // Extract the particles from the created emitter.  Notice that we copy the particles into a new javascript array.
    71.     // According to the Unity docs example this shouldn't be necessary, but I couldn't get it to work otherwise.  
    72.     // Below, when the updated p array is reassigned to the emitter particle array, the assignment failed when p was
    73.     // simply assigned the value "emitter.particles".
    74.     var p : Array = new Array(emitter.particles);
    75.    
    76.     // Loop thru the particles, giving each an initial position and velocity.
    77.     for (var i=0; i<p.length; i++) {
    78.    
    79.         // Generate a random unit vector in the plane defined by our transform's red axis centered around the
    80.         // transform's green axis.  This vector serves as the basis for the initial position and velocity of the particle.
    81.         var ruv : Vector3 = RandomUnitVectorInPlane(effectObject.transform, effectObject.transform.up);
    82.        
    83.         // Calc the initial position of the particle accounting for the specified ring radii.  Note the use of Range
    84.         // to get a random distance distribution within the ring.
    85.         var newPos : Vector3 = effectObject.transform.position
    86.                 + ((ruv * innerRadius) + (ruv * Random.Range(innerRadius, outerRadius)));
    87.         p[i].position = newPos;
    88.        
    89.         // The velocity vector is simply the unit vector modified by the speed.  The velocity vector is used by the
    90.         // Particle Animator component to move the particles.
    91.         p[i].velocity = ruv * speed;
    92.     }
    93.     // Update the actual particles.
    94.     emitter.particles = p.ToBuiltin(Particle);
    95. }
    96.  
    97. function LateUpdate()
    98. {
    99.     // Check to see if it's time to spawn a new particle system.
    100.     var timeSinceLastSpawn : float = Time.time - timeOfLastSpawn;
    101.     if (timeSinceLastSpawn >= spawnRate  spawnCount < numberOfRings) {
    102.         SpawnRing();
    103.         timeOfLastSpawn = Time.time;
    104.         spawnCount++;
    105.     }
    106. }
    107.  
    108. function RandomUnitVectorInPlane(xform : Transform, axis : Vector3) :  Vector3
    109. {
    110.     // Rotate the specified transform's axis thru a random angle.
    111.     xform.Rotate(axis, Random.Range(0.0, 360.0), Space.World);
    112.    
    113.     // Get a copy of the rotated axis and normalize it.
    114.     var ruv : Vector3 = new Vector3(xform.right.x, xform.right.y, xform.right.z);  
    115.     ruv.Normalize();
    116.     return (ruv);
    117. }
    118.  
     
  2. deps

    deps

    Joined:
    Nov 19, 2009
    Posts:
    78
    This will come in handy, I'm sure! Thanks a lot! :)
     
  3. Malveka

    Malveka

    Joined:
    Nov 6, 2009
    Posts:
    191
    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
     
  4. Alric

    Alric

    Joined:
    Feb 17, 2009
    Posts:
    331
    That's all very well, but really you just made me want cake :?
     
  5. Malveka

    Malveka

    Joined:
    Nov 6, 2009
    Posts:
    191
    Well, with just a few small modifications we could probably get a chocolate cake particle effect out of it. :)

    Mal
     
  6. the_gnoblin

    the_gnoblin

    Joined:
    Jan 10, 2009
    Posts:
    722
    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".

    :)
     
  7. Malveka

    Malveka

    Joined:
    Nov 6, 2009
    Posts:
    191
    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):
    1.  
    2. // Autodestruct the particle effect system after it produces a ring.
    3. // RECOMMENDED!
    4. public var autoDestruct : boolean = true;
    5.  

    And the following code to the SpawnRing function:

    Code (csharp):
    1.  
    2. // Parent the new effect to this script's transform.
    3.    effectObject.transform.parent = this.gameObject.transform;
    4.  
    5. // NEW ==>
    6.     // Get the particle animator from the new effect object.  
    7.    var animator = effectObject.GetComponent(ParticleAnimator);
    8.    if (animator)
    9.     animator.autodestruct = autoDestruct;
    10. // <== END NEW
    11.  
    12.    // Get the particle emitter from the new effect object.
    13.    var emitter = effectObject.GetComponent(ParticleEmitter);
    14.    
    Mal
     
  8. Serial

    Serial

    Joined:
    Nov 25, 2009
    Posts:
    5
    Is there a code snippets area that stuff like this can go in?
     
  9. Malveka

    Malveka

    Joined:
    Nov 6, 2009
    Posts:
    191
    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
     
  10. FiveFingers

    FiveFingers

    Joined:
    Oct 15, 2009
    Posts:
    541
    We want (would like) a code repository forum / website section!

    :D
     
  11. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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
     
  12. FiveFingers

    FiveFingers

    Joined:
    Oct 15, 2009
    Posts:
    541
    I modified the script to make it work on unity iphone, I will post there (wiki) this version when I finish the tests..
     
  13. galent

    galent

    Joined:
    Jan 7, 2008
    Posts:
    1,078
    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):
    1. /* -----------------------------------------------------------------------------------------------------
    2.    -- ParticleRingEffect --
    3.    
    4.    This script spawns "ring" particle effects, such as are commonly used for explosion
    5.    shockwaves, sensor effects,  propulsion effects, etc.  Note that the script can be
    6.    adjusted to spawn any number of ring particle systems for repeating ring effects.
    7.    Use this feature carefully so as not to adversely impact framerate.  
    8.    
    9.    Assign this script to the transform at the location where the ring effect will be
    10.    centered.  The ring will be generated in the plane specified by the script transform's
    11.    red axis (right) and centered around the green axis (up).  
    12.    ------------------------------------------------------------------------------------------------------ */
    13.  
    14. // -- ringEffect --
    15. // This must be set to reference the prefab that contains the particle system components.
    16. // Those components can be adjusted as usual to achieve the desired appearance of the
    17. // particles.  Typical "expanding ring" effects are achieved in combination with this script by:
    18. //   - Starting with default component settings, then
    19. //   - Particle emitter:
    20. //      Emit: OFF
    21. //      Simulate in Worldspace: ON
    22. //      One Shot: ON
    23. //   - Particle Renderer:
    24. //      Materials: Your favorite particle material 8^)
    25. //   - Particle Animator:
    26. //      Autodestruct: ON (Prevents accumulation of used-up particle systems!)
    27. public var ringEffect : GameObject;
    28.  
    29. // The expansion speed of the ring.
    30. public var speed : float = 2.0;
    31.  
    32. // The inner and outer radii determine the width of the ring.
    33. public var innerRadius : float = 0.5;
    34. public var outerRadius : float = 1.5;
    35.  
    36. // How many ring systems to spawn.  "Infinite" by default.
    37. public var numberOfRings : int = 9999999;
    38.  
    39. // How often a new ring should be spawned.  In seconds.  if 0 then OnCollisionEnter() is run.
    40. public var spawnRate : float = 5.0;
    41.  
    42. // Autodestruct the particle effect system after it produces a ring.
    43. // RECOMMENDED!
    44. public var autoDestruct : boolean = true;
    45.  
    46. /* ------------------------------------------------------------------------------------------------------*/
    47. // Time at which the last spawn occurred.  
    48. private var timeOfLastSpawn : float = 0.0;
    49.  
    50. // Count of rings spawned so far.
    51. private var spawnCount : int = 0;
    52.  
    53. function Awake() {
    54.     //ringEffect = gameObject.transform;
    55. }
    56.  
    57. /* ------------------------------------------------------------------------------------------------------
    58.    -- SpawnRing --
    59.    
    60.    This function spawns a new particle effect system each time it's called.  The system
    61.    spawned is the prefab referenced by the public ringEffect variable.
    62.    ------------------------------------------------------------------------------------------------------- */
    63. function SpawnRing () {
    64.    // Instantiate the effect prefab.
    65.    var effectObject : GameObject = Instantiate(ringEffect, this.transform.position, this.transform.rotation);
    66.    
    67.    // Parent the new effect to this script's transform.
    68.    // NOTE: THE NEXT STEP IS NOT NECESSARY UNLESS THE EFFECT NEEDS TO MOVE WITH THE ORIGINAL OBJECT...  
    69.    effectObject.transform.parent = this.gameObject.transform;
    70.    
    71.    // NEW ==>
    72.    // Get the particle animator from the new effect object.  
    73.    var animator : ParticleAnimator = effectObject.GetComponent(ParticleAnimator);
    74.    if (animator)
    75.         animator.autodestruct = autoDestruct;
    76. // <== END NEW
    77.  
    78.    // Get the particle emitter from the new effect object.
    79.    var emitter : ParticleEmitter = effectObject.GetComponent(ParticleEmitter);
    80.        
    81.    // Generate the particles.
    82.    emitter.Emit();
    83.    
    84.    // Extract the particles from the created emitter.  Notice that we copy the particles into a new javascript array.
    85.    // According to the Unity docs example this shouldn't be necessary, but I couldn't get it to work otherwise.  
    86.    // Below, when the updated p array is reassigned to the emitter particle array, the assignment failed when p was
    87.    // simply assigned the value "emitter.particles".
    88.    var p : Array = new Array(emitter.particles);
    89.    
    90.    // Loop thru the particles, giving each an initial position and velocity.
    91.    for (var i=0; i<p.length; i++) {
    92.    
    93.       // Generate a random unit vector in the plane defined by our transform's red axis centered around the
    94.       // transform's green axis.  This vector serves as the basis for the initial position and velocity of the particle.
    95.       var ruv : Vector3 = RandomUnitVectorInPlane(effectObject.transform, effectObject.transform.up);
    96.        
    97.       // Calc the initial position of the particle accounting for the specified ring radii.  Note the use of Range
    98.       // to get a random distance distribution within the ring.
    99.       var newPos : Vector3 = effectObject.transform.position
    100.             + ((ruv * innerRadius) + (ruv * Random.Range(innerRadius, outerRadius)));
    101.      
    102.       var tmpParticle : Particle = p[i];
    103.       tmpParticle.position = newPos;
    104.        
    105.       // The velocity vector is simply the unit vector modified by the speed.  The velocity vector is used by the
    106.       // Particle Animator component to move the particles.
    107.       tmpParticle.velocity = ruv * speed;
    108.       p[i] = tmpParticle;
    109.    }
    110.    // Update the actual particles.
    111.    emitter.particles = p.ToBuiltin(Particle);
    112.      
    113. }
    114.  
    115. // Update based execution (with Spawn rate control)
    116. function LateUpdate()
    117. {
    118.    if(spawnRate == 0); // shutoff option
    119.    else {
    120.         // Check to see if it's time to spawn a new particle system.
    121.         var timeSinceLastSpawn : float = Time.time - timeOfLastSpawn;
    122.         if (timeSinceLastSpawn >= spawnRate  spawnCount < numberOfRings) {
    123.             SpawnRing();
    124.             timeOfLastSpawn = Time.time;
    125.             spawnCount++;
    126.         }
    127.    }
    128. }
    129.  
    130. function RandomUnitVectorInPlane(xform : Transform, axis : Vector3) :  Vector3
    131. {
    132.    // Rotate the specified transform's axis thru a random angle.
    133.    xform.Rotate(axis, Random.Range(0.0, 360.0), Space.World);
    134.    
    135.    // Get a copy of the rotated axis and normalize it.
    136.     var ruv : Vector3 = new Vector3(xform.right.x, xform.right.y, xform.right.z);    
    137.    ruv.Normalize();
    138.    return (ruv);
    139. }
    140.  
    141. // Optional: OnCollisionXxxxx
    142. //function OnCollisionEnter() {
    143. //      SpawnRing();
    144. //}
    [/code]
     
  14. mojojojo

    mojojojo

    Joined:
    Dec 16, 2009
    Posts:
    138
    Probably a dumb question but is that a javascript?
     
  15. galent

    galent

    Joined:
    Jan 7, 2008
    Posts:
    1,078
    Yes, that's a javascript version.

    Cheers,

    Galen
     
  16. Vitruvius

    Vitruvius

    Joined:
    Jul 31, 2010
    Posts:
    15
    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,
     
  17. headkitgames

    headkitgames

    Joined:
    Oct 30, 2009
    Posts:
    23
    anyone translated this (the iOS-version) into C#?
     
  18. Rush-Rage-Games

    Rush-Rage-Games

    Joined:
    Sep 9, 2010
    Posts:
    1,997
    Awesome, thanks!
     
  19. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Ok I converted it to C# and finally got it work. It was tough haha. Will post the C# version soon.
     
    Last edited: Oct 16, 2011
  20. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Here's the C# version. You may need to write a line of code to call the SpawnRing method.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ParticleRings : MonoBehaviour {
    6. /* -----------------------------------------------------------------------------------------------------
    7.     -- ParticleRingEffect --
    8.    
    9.     This script spawns "ring" particle effects, such as are commonly used for explosion
    10.     shockwaves, sensor effects,  propulsion effects, etc.  Note that the script can be
    11.     adjusted to spawn any number of ring particle systems for repeating ring effects.
    12.     Use this feature carefully so as not to adversely impact framerate.  
    13.    
    14.     Assign this script to the transform at the location where the ring effect will be
    15.     centered.  The ring will be generated in the plane specified by the script transform's
    16.     red axis (right) and centered around the green axis (up).  
    17.    ------------------------------------------------------------------------------------------------------ */
    18.  
    19. // -- ringEffect --
    20. // This must be set to reference the prefab that contains the particle system components.
    21. // Those components can be adjusted as usual to achieve the desired appearance of the
    22. // particles.  Typical "expanding ring" effects are achieved in combination with this script by:
    23. //  - Starting with default component settings, then
    24. //  - Particle emitter:
    25. //      Emit: OFF
    26. //      Simulate in Worldspace: ON
    27. //      One Shot: ON
    28. //  - Particle Renderer:
    29. //      Materials: Your favorite particle material 8^)
    30. //  - Particle Animator:
    31. //      Autodestruct: ON (Prevents accumulation of used-up particle systems!)
    32. public GameObject ringEffect;
    33.  
    34. // The expansion speed of the ring.
    35. public float speed = 2.0f;
    36.  
    37. // The inner and outer radii determine the width of the ring.
    38. public float innerRadius = 0.5f;
    39. public float outerRadius = 1.5f;
    40.  
    41. // How many ring systems to spawn.  "Infinite" by default.
    42. public int numberOfRings = 9999999;
    43.  
    44. // How often a new ring should be spawned.  In seconds.
    45. public float spawnRate = 5.0f;
    46.  
    47. /* ------------------------------------------------------------------------------------------------------*/
    48. // Time at which the last spawn occurred.  
    49. private float timeOfLastSpawn = 0.0f;
    50.  
    51. // Count of rings spawned so far.
    52. private int spawnCount = 0;
    53. private bool isSpawned = false;
    54.  
    55. /* ------------------------------------------------------------------------------------------------------
    56.     -- SpawnRing --
    57.    
    58.     This function spawns a new particle effect system each time it's called.  The system
    59.     spawned is the prefab referenced by the public ringEffect variable.
    60.    ------------------------------------------------------------------------------------------------------- */
    61. private void SpawnRing () {
    62.        
    63.     // Instantiate the effect prefab.
    64.     GameObject effectObject = ((Transform) Instantiate(ringEffect.transform, this.transform.position, this.transform.rotation)).gameObject;
    65.    
    66.     // Parent the new effect to this script's transform.  
    67.     effectObject.transform.parent = this.gameObject.transform;
    68.    
    69.     // Get the particle emitter from the new effect object.
    70.     ParticleEmitter emitter = effectObject.particleEmitter;
    71.    
    72.     // Generate the particles.
    73.     emitter.Emit();
    74.    
    75.     // Extract the particles from the created emitter.  Notice that we copy the particles into a new javascript array.
    76.     // According to the Unity docs example this shouldn't be necessary, but I couldn't get it to work otherwise.  
    77.     // Below, when the updated p array is reassigned to the emitter particle array, the assignment failed when p was
    78.     // simply assigned the value "emitter.particles".
    79.     Particle[] p = new Particle[emitter.particles.Length];
    80.    
    81.     // Loop thru the particles, giving each an initial position and velocity.
    82.     for (var i=0; i < p.Length; i++) {
    83.         p[i] = emitter.particles[i];
    84.         // Generate a random unit vector in the plane defined by our transform's red axis centered around the
    85.         // transform's green axis.  This vector serves as the basis for the initial position and velocity of the particle.
    86.         Vector3 ruv = RandomUnitVectorInPlane(effectObject.transform, effectObject.transform.up);
    87.            
    88.         // Calc the initial position of the particle accounting for the specified ring radii.  Note the use of Range
    89.         // to get a random distance distribution within the ring.
    90.         Vector3 newPos = effectObject.transform.position
    91.                 + ((ruv * innerRadius) + (ruv * Random.Range(innerRadius, outerRadius)));
    92.         p[i].position = newPos; //emitter.particles[i].position;
    93.         p[i].angularVelocity = Random.Range(30f, 60f);
    94.            
    95.         // The velocity vector is simply the unit vector modified by the speed.  The velocity vector is used by the
    96.         // Particle Animator component to move the particles.
    97.         p[i].velocity = ruv * speed; //emitter.particles[i].velocity;
    98.     }
    99.     // Update the actual particles.
    100.     emitter.particles = p;
    101.     emitter.worldVelocity = new Vector3(0f, Random.Range(10f, 20f), 0);
    102. }
    103.  
    104. void LateUpdate() {
    105.     // Check to see if it's time to spawn a new particle system.
    106.     float timeSinceLastSpawn = Time.time - timeOfLastSpawn;
    107.     if (timeSinceLastSpawn >= spawnRate  spawnCount < numberOfRings) {
    108.         SpawnRing();
    109.         timeOfLastSpawn = Time.time;
    110.         spawnCount++;
    111.     }
    112. }
    113.  
    114. private Vector3 RandomUnitVectorInPlane(Transform xform, Vector3 axis) {
    115.     // Rotate the specified transform's axis thru a random angle.
    116.     xform.Rotate(axis, Random.Range(0.0f, 360.0f), Space.World);
    117.    
    118.     // Get a copy of the rotated axis and normalize it.
    119.     Vector3 ruv = new Vector3(xform.right.x, xform.right.y, xform.right.z);    
    120.     ruv.Normalize();
    121.     return (ruv);
    122. }
    123.    
    124. }
    125.  
    126.  
    127.  
     
  21. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    Can this be made to work with new Shuriken Particle System?