Skip to main content

Chaos Wave Particle

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.

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.

```lua 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

FieldValue
texturematerials/particle/juggernaut/juggernaut_blade_fury.vtex
orientation typeWorld-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

FieldValue
sequence min3
sequence max6

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.

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

FieldValue
rotation offset90.0
rotation fieldRoll

Rotation from CP forward orientation

FieldValue
control point number1
rotation fieldYaw
rotation offset45.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.

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

FieldValue
offset min0.0 0.0 100.0
offset max0.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

FieldValue
input control point number2
output fieldRadius
input minimum0.0
input maximum9999.0
output minimum0.0
output maximum9999.0

Remap control point to scalar #2

FieldValue
input control point number3
output fieldLife Duration
input minimum0.0
input maximum10.0
output minimum0.0
output maximum10.0

Now put these values into the control points on right.

FieldValue
Control Point #11000 0 0
Control Point #2300 0 0
Control Point #33 0 0

You should see something like this.

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

FieldValue
radius start scale0.0

Now your particle should look like this. (I just adjust the color random, so it will look a bit different from previous 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

FieldValue
ramp rate15.0
ramp fieldYaw

Ramp scalar linear simple #2

FieldValue
ramp rate2500
end time9999.0
ramp fieldRadius

Noise vector

FieldValue
output fieldPosition
output minimum-100.0 -100.0 -100.0
output maximum100.0 100.0 100.0
additivetrue

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

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

FieldValue
max particles60

Emit continuously

FieldValue
emission duration2.0
emission rate30.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

FieldValue
lifetime min0.03
lifetime max0.07

Sequence random

FieldValue
sequence min0
sequence max3

Alpha random

FieldValue
alpha min150
alpha max175

Now you should have something similar to this.

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

FieldValue
input control point number2
output fieldRadius
input maximum999.0
output maximum999.0

Position modify offset random

FieldValue
offset min-0.3 -0.3 -0.3
offset max0.3 0.3 0.3
control point number0
offset proportional to radiustrue

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

FieldValue
gravity0.0 0.0 300.0
drag0.05

Radius scale

FieldValue
radius start scale0.07
radius end scale0.14
scale bias0.65

Alpha fade and decay

FieldValue
start fade in time0.0
end fade in time0.2
start fade out time0.4
end fade out time1.0
start alpha0.0
end alpha0.0

Now your spark should look something like this.

With the wave particles, it looks like this.

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

FieldValue
max particles64

Emit continuously

FieldValue
emission duration4.0
emission rate200.0

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

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

FieldValue
max particles60.0

Renderer: Render Sprites

FieldValue
orientation typeWorld-Z Align
texturematerials/particle/dirt/ground_decay/ground_decay01.vtex

Operator: Remap control point to velocity

Operator: Lifespan decay

Operator: Movement basic

Operator: Radius Scale

FieldValue
radius start scale0.2
radius end scale1.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

FieldValue
input control point number3
output fieldLife Duration
input maximum10.0
output maximum10.0

Initializer: Remap control point to scalar

FieldValue
input control point number2
output fieldRadius
input maximum9999.0
output maximum9999.0

Initializer: Alpha random

FieldValue
alpha min30
alpha max50

Initializer: Emit continuously

FieldValue
emission duration2.0
emission rate30.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.

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!