Particles Creation Series - Chaos Wave

edited February 2015 in Tutorials

Table of content

Introduction

This is taken from the project I'm currently working on. The basic idea behind this particle system was that this projectile is a cyclone/tornado in xy-axis travel forward with certain amount of velocity. If you don't have any basic in particle editor, please go to this link first. Before you read further, here is the finished product.

image

Don't worry too much about the statue model, I put it there just to check height reference before porting into the map itself. There are many ways to approach this but here is how I approach it.

Wave
- Render sprites
- Lifespan decay
- Movement basic
- Remap control point to velocity (CP1)
- Rotation orient to 2d direction (Roll)
- Rotation from CP forward orientation (Yaw)
- Radius scale
- Ramp scale linear simple (Yaw)
- Ramp scale linear simple (Radius)
- Noise vector
- Alpha fade out simple
- Alpha fade in simple
- Position within sphere random
- Color random
- Sequence random
- Rotation random
- Remap control point to scalar (Radius, CP2)
- Position modify offset random
- Remap control point to scalar (Life Duration, CP3)
Electric charge
- Render sprites
- Movement basic
- Radius scale
- Lifespan Decay
- Alpha fade and decay
- Lifetime random
- Color random
- Rotation random
- Sequence random
- Position from parent particles
- Remap control point to scalar (Radius, CP2)
- Alpha random
- Position modify offset random
- Emit continuously
Ground (optional)
- Render sprites
- Remap control point to velocity (CP1)
- Lifespan decay
- Movement basic
- Radius scale
- Alpha fade and decay
- Movement place on ground
- Position within sphere random
- Color random
- Remap control point to scalar (Life Duration, CP3)
- Remap control point to scalar (Radius, CP2)
- Alpha random
- Emit continuously

Part one: Wave particle

Now let's start making this particle system.

  • Open particle editor and create new Particle.
  • Add "Render sprites" in Renderer.
  • Add "Emit continuously" in Emitter.
  • Add "Lifespan Decay" in Operator.

Now don't worry too much about particle count yet. That can be adjusted later before you actually finish this particle system. Let's change the value of Render sprites to:

Render sprites

Field Value
texture materials/particle/juggernaut/juggernaut_blade_fury.vtex
orientation type World-Z align

Since that texture is a sequence texture, I want to alternate the use of each sequence. This can be done by the following:

  • Add "Sequence random" in Initializer.

Now let's adjust the sequence we want. Since it's a cyclone/tornado with space in the middle, we might want something similar to sequence #3 to #6. So we change the following values:

Sequence random

Field Value
sequence min 3
sequence max 6

Now it's time to place this particle somewhere.

  • Add "Position within sphere random" in Initializer.

We don't need to change anything here since it's just reference point for emitter. Now your particle should look like this.

image

Well it shouldn't keep lying on the floor like that. Now we want to rotate it to the direction that it should face. But before we get to that, we have to set up something first.

  • Add "Movement basic" in Initializer.
  • Add "Remap control point to velocity" in Initializer. (Default control point will be 1)

I will leave these two functions as default since I don't need anything special about velocity in this system. Now if we adjust the Control Point #1 on the right hand side, you can freely adjust the velocity as if it is a control point in-game, so you can see result immediately. My particle now moves but it faces upward, and I don't want that. Let's rotate our particle with following functions.

  • Add "Rotation orient to 2d direction" in Operator.
  • Add "Rotation from CP forward orientation" in Operator.

With following values:

Rotation orient to 2d direction

Field Value
rotation offset 90.0
rotation field Roll

Rotation from CP forward orientation

Field Value
control point number 1
rotation field Yaw
rotation offset 45.0

These two functions will automatically adjust your sprite so it faces the direction it's moving all the time. I chose not to use 90.0 in second function because at 90 degree, your particle will be very hard to see from the top, so I adjust them down a bit. Now you should see result like this.

image

Now basic functionality is done, I will adjust the outlook of the particle by following function.

  • Add "Color random" in Initializer.
  • Add "Rotation random" in Initializer.
  • Add "Position modify offset random" in Initializer.

Now change the color to the color you like, leave the rotation random as is, and adjust third function as follow:

Position modify offset random

Field Value
offset min 0.0 0.0 100.0
offset max 0.0 0.0 100.0

This is so that our particles will start in the air instead of on the ground. You can pull reference model up to adjust the height as you like.

Now that is done, we will start assigning the rest of the control points as followed:

  • Add "Remap control point to scalar" in Initializer.
  • Add "Remap control point to scalar" in Initializer. (Yes twice)

And adjust the value to the following.

Remap control point to scalar #1

Field Value
input control point number 2
output field Radius
input minimum 0.0
input maximum 9999.0
output minimum 0.0
output maximum 9999.0

Remap control point to scalar #2

Field Value
input control point number 3
output field Life Duration
input minimum 0.0
input maximum 10.0
output minimum 0.0
output maximum 10.0

Now put these values into the control points on right.

Field Value
Control Point #1 1000 0 0
Control Point #2 300 0 0
Control Point #3 3 0 0

You should see something like this.

image

Now those are all the initializers you need, let's now adjust the detail while our particles are traveling in operator.

Since I feel like the tornado should grow larger as it goes and there should be fade in and out effect, I add the following functions to the system.

  • Add "Radius scale" in Operator.
  • Add "Alpha fade out simple" in Operator.
  • Add "Alpha fade in simple" in Operator.

Adjust these values as you like. I left them as default except one which is:

Radius scale

Field Value
radius start scale 0.0

Now your particle should look like this. (I just adjust the color random, so it will look a bit different from previous image.)

image

Since it is kinda power wave, I want to add the feeling of being unstable to the system. So I add these functions.

  • Add "Ramp scalar linear simple" in Operator.
  • Add "Ramp scalar linear simple" in Operator. (Yes twice)
  • Add "Noise vector" in Operator.

Adjust its value to the following:

Ramp scalar linear simple #1

Field Value
ramp rate 15.0
ramp field Yaw

Ramp scalar linear simple #2

Field Value
ramp rate 2500
end time 9999.0
ramp field Radius

Noise vector

Field Value
output field Position
output minimum -100.0 -100.0 -100.0
output maximum 100.0 100.0 100.0
additive true

Now your wave particle is done. It should look similar to the following:

image

What I said about "done" is actually a lie. You still need to adjust your particle count. My advice is that keep the count at minimum to suit the purpose of your system. Currently, the particle count should be at around 300 all the time and it's not good for overall performance. Since my particles will be used somewhat as a projectile, I don't want high particle counts. To reduce this I change the following setting.

Base Properties

Field Value
max particles 60

Emit continuously

Field Value
emission duration 2.0
emission rate 30.0

With this, the particle count should be below 60 at all time since I want them to emit only for 2 seconds, 30 particles each, and the memory allocated is only enough for 60 particles. Now your base wave particles are done. Very important, don't forget to save.

Part two: Spark Particle

Now that I have my wave particle working, I feel like it needs something like an electric spark during the duration. However, since this particle is based on the wave particle, we need to make some adjustments to the wave particle.

  • Create new particle for static and save it.
  • In wave particle, add newly created particle as a children.

First off as usual, you want to start rendering your sprite and emitter and decay.

  • Add "Render sprites" in Renderer.
  • Add "Emit continuously" in Emitter.
  • Add "Lifespan decay" in Operator.

Change your render sprites' texture to,

materials/particle/electrical_arc_smooth/electrical_arc_smooth.vtex

Now think about the actual electric spark, it needs to be fast, colorful, looks different all the time, and a little bit of transparency. From those idea, I add following functions.

  • Add "Lifetime random" in Initializer.
  • Add "Color random" in Initializer.
  • Add "Rotation random" in Initializer.
  • Add "Sequence random" in Initializer.
  • Add "Alpha random" in Initializer.

Adjust the color accordingly for Color random, and leave Rotation random as default. For other functions, change the value to following.

Lifetime random

Field Value
lifetime min 0.03
lifetime max 0.07

Sequence random

Field Value
sequence min 0
sequence max 3

Alpha random

Field Value
alpha min 150
alpha max 175

Now you should have something similar to this.

image

When that's done, we want to change our radius accordingly as we already had control point in wave particles and make the spark scatter from the center.

  • Add "Remap control point to scalar" in Initializer.
  • Add "Position modify offset random" in Initializer.

Now we adjust the value to the following:

Remap control point to scalar

Field Value
input control point number 2
output field Radius
input maximum 999.0
output maximum 999.0

Position modify offset random

Field Value
offset min -0.3 -0.3 -0.3
offset max 0.3 0.3 0.3
control point number 0
offset proportional to radius true

image

As you can see, now our particles are huge! Sparks are supposed to be small so let's resize it with this, add a little bit more movement to our sparks, and also add some fade decay to our particle.

  • Add "Movement basic" in Operator.
  • Add "Radius Scale" in Operator.
  • Add "Alpha fade and decay" in Operator.

Adjust the values to the following.

Movement basic

Field Value
gravity 0.0 0.0 300.0
drag 0.05

Radius scale

Field Value
radius start scale 0.07
radius end scale 0.14
scale bias 0.65

Alpha fade and decay

Field Value
start fade in time 0.0
end fade in time 0.2
start fade out time 0.4
end fade out time 1.0
start alpha 0.0
end alpha 0.0

Now your spark should look something like this.

image

With the wave particles, it looks like this.

image

Now we want the spark to follow the wave, we add this function to the spark particle.

  • Add "Position from parent particles" in Initializer.

Leave the value as default, you can adjust it to your taste though. Now we are almost done, we have to reduce particle count in the system. Change the values of the following function.

Base Properties

Field Value
max particles 64

Emit continuously

Field Value
emission duration 4.0
emission rate 200.0

Now that's done, you should see something like the following in your wave particle.

image

With this, your spark particle is done. Feel free to adjust the value to your taste.

Part three: Ground Particle (Optional)

You may wonder why I list this part as optional. It is not a requirement since it doesn't really make you see what's happening in the particle editor. When you head into the game, if the place has light color background, it will become very hard to see bright color particle. With this ground particle, I basically layout the dark particle under the wave particle to make it more visible to the user.

This particle borrows most of the value from wave particle except one function. I will list all of the functions and its adjusted value below. For more detail on each of the functions, please go back to read in wave particle section.

Base Properties

Field Value
max particles 60.0

Renderer: Render Sprites

Field Value
orientation type World-Z Align
texture materials/particle/dirt/ground_decay/ground_decay01.vtex

Operator: Remap control point to velocity

Operator: Lifespan decay

Operator: Movement basic

Operator: Radius Scale

Field Value
radius start scale 0.2
radius end scale 1.2

Operator: Alpha fade and decay

Operator: Movement place on ground

Initializer: Position within sphere random

Initializer: Color random

Initializer: Remap control point to scalar

Field Value
input control point number 3
output field Life Duration
input maximum 10.0
output maximum 10.0

Initializer: Remap control point to scalar

Field Value
input control point number 2
output field Radius
input maximum 9999.0
output maximum 9999.0

Initializer: Alpha random

Field Value
alpha min 30
alpha max 50

Initializer: Emit continuously

Field Value
emission duration 2.0
emission rate 30.0

Don't forget to save your file. Now that's done, let's combine all the works together.

Part four: Finalize the system

Our system is almost finished. Now we are going to add multiple layer of wave.

  • Open your wave particle.
  • Remove the children.
  • Save as a new particle for an outer layer (this should have no children).
  • Save as a new particle again for the outline (this should also have no children).

These three layer will behave the same, there are only three different between each layer.

  1. Radius
  2. Color
  3. Sequence number

Let's set our 3 layers (or more if you want to) as following.

For the inner most layer, our core layer, adjust the color to become very bright, have radius end scale in Radius scale as 0.6, and sequence min/max set to 7 and 8.

For the outer layer, second layer, adjust the color to be between the very bright color and black, have radius end scale in Radius scale as 1.0, and sequence min/max set to 7 and 8.

For the outline layer, last layer, adjust the color to be black and have radius end scale in Radius scale as 1.2.

Now we combine the two outer layer into our core layer by adding children. Your screen should look like this.

image

If you don't have ground particle, you should be done at this point. However, if you have ground particle then:

  • Create new particle.
  • Add ground particle as children.
  • Add wave particle as children.

It is important that ground particle is above wave particle. This is the order in which your particle will be rendered. If ground particle is below wave particle, it will be on top of wave particle and that's not how we want it.

Implement in-game

Now that the particle is ready, we have to put it to use in game. Note that this particle is not fully compatible with projectile. Therefore, we mimic the projectile as following:

KV npc_abilities_custom.txt

In the ability you want to use, put these lines in.

"precache"
{
    "particle"      "particles/custom/tutorial/cyclone.vpcf"
}

Now when you want to launch particles in lua, you do the following

local info = {
    ...
    EffectName = "",
    vVelocity = keys.caster:GetForwardVector() * ProjectileSpeed,
    fDistance = Distance,
    fStartRadius = Radius,
    fEndRadius = Radius,
    ... 
}

local projectile = ProjectileManager:CreateLinearProjectile(info)

-- Create particle
local tornadoFxIndex = ParticleManager:CreateParticle( "particles/custom/tutorial/cyclone.vpcf", PATTACH_CUSTOMORIGIN, caster )
ParticleManager:SetParticleControl( tornadoFxIndex, 0, keys.caster:GetAbsOrigin() )
ParticleManager:SetParticleControl( tornadoFxIndex, 1, keys.caster:GetForwardVector() * ProjectileSpeed )
ParticleManager:SetParticleControl( tornadoFxIndex, 2, Vector( Radius, 0, 0 ) )
ParticleManager:SetParticleControl( tornadoFxIndex, 3, Vector( Distance / ProjectileSpeed, 0, 0 ) )

Timers:CreateTimer( 6.0, function()
        ParticleManager:DestroyParticle( tornadoFxIndex, false )
        ParticleManager:ReleaseParticleIndex( tornadoFxIndex )
        return nil
    end
)       

With those implemented, your particles should show up in-game now.

This concludes my tutorial on making Chaos Wave particles. If you have any comment, question, or improvement to the guide, please do not hesitate to leave a comment or contact me. Let me know what you want to see created next!