top of page

Chain Lightning - Unreal

Click for more detail

I started the animation implementation triggered by a left-mouse click in the blueprint.  The animation is from Mixamo, and required some retargeting and modification of the base skeleton. 

retargeting_1.PNG

The next step was getting a particle effect to trigger at the same time as the animation. This meant timing and repositioning it in a natural way. The default Niagara burst emitter is used here as a placeholder. The animation will need some refining later in the process.

Next, I spent a few days in Blueprint working out the mechanics. Right now, each Niagara system is attached to its own BP, which ideally will be combined later on if possible.

BP_Enemy & the "chain"

ThirdPersonCharacterBP

linetraceEx_2.PNG

The main function of the Third Person Character BP (other than the movement & animation) is to control the line trace, which determines the outcome of the attack. The line trace needs an origin point and an end point. The collision of the line trace needs to detect the hitbox of an Enemy, but not its outgoing shock radius, requiring specific collision settings on the capsule collision. (See the trace going through the red sphere, and hitting the green capsule)

 

It also determines the spawn point for the Niagara systems. This meant locating it at the character's hands in the right time of the animation, and aligning it with the character's forward vector.

hitbox_collisionsettings.PNG
linetrace_vector.PNG

hitbox collision

The outcome of the line trace determines a couple things: if there was a collision, what the trace collided with, and the point of intersection. These factors are used to dictate how the effect should be spawned. There are 3 versions of the initial attack:

1 - an Enemy was hit

2 - the attack hit something, but not an Enemy (ex: wall)

3 - there was no collision

 

This will really affect the look of the effect than the mechanics in the case of no collision, but on a collision the distinction is important. The initial attack is directed not in the path of the line trace, but at the target (the way lightning is attracted to conductors). At the moment this is a direct path adjustment (facing rotation). If the line trace hits a wall, this won't work since it will point at the origin of the mesh. In this case, the attack will point in the direction of the line trace.

thirdperson_enemyctl.PNG

sending information to BP_Enemy

determine actor type (Enemy or not)

One big step for the mechanic was figuring out how the "chain" should be calculated. There were a few factors that went into my decision to drive it by each individual actor rather than through the Third Person BP or another BP. The way the mechanic works is by finding every other enemy in the vicinity of the shocked enemy, and knowing which chain number we're on (how many times has the attack chained). Keeping this within Third Person BP would complicate the tracking number of each attack and enemy.

enemy_viewport.PNG

Components:

mesh

hitbox

outward shock radius

Variables:

chain number (i) - attack index (range 0-2)

ActiveShocked (b) - true/false

HitShocked (b) - true/false

Events:

BecomeShocked

FindSurroundingEnemies

enemyBP_1.PNG

When the first enemy is hit, the chain number is set to 0 (representing index). The first time an Enemy's BecomeShocked event is called, this is checked to make sure only a max 3 hits happen, otherwise it could chain forever. Then, it checks if the enemy is already shocked. If so, it cannot be hit again, or chain to other enemies, thus not triggering the FindSurroundingEnemies event.

The BP then spawns a Niagara system at the actor location representing being "shocked". If this is the 3rd enemy in the chain (the max, tested against chain number) there is another system created making a big explosion. This state lasts for 4 seconds, then the system dies and the actor is no longer shocked. 

Find Surrounding Enemies - logic
enemyBP_3.PNG
  • Delay 0.2 sec 

    • without this, all chains would activate at once, instead of looking like a fluid transition​

  • ComponentOverlapActors

    • Takes the outward shock radius component and creates a list of actors that it overlaps ​

    • ignore self, otherwise the current actor will be triggered

    • I only want the actor if its hitbox is overlapped by this radius. Right now, this includes the overlap of the other actor's shock radius. This is handled later.

For Each Loop 1 - iterate through each actor and make an array of valid surrounding enemies

  • GetComponentsByClass

    • makes an array of any components that are of the capsule collision class (which hitbox is)​

 

 

 

 

For Each Loop 2 - iterate through  capsule components

  • IsOverlappingComponent

    • tests if the hitbox component of the other Enemy actor is overlapping the outward shock radius of the current Enemy actor​

    • this filters out any actors previously mentioned that don't fit the overlap criteria

  • Cast

    • on failure, nothing happens, preventing a chain to a non-Enemy class​

  • Check for ActiveShocked condition

    • shocked state

  • Check for HitShocked condition

    • represents if the target has already been targeted by another enemy, preventing a chain happening multiple times from different Enemy actors. This is needed because the ActiveShocked only becomes true when the bolt hits the target, the delay between fire and collision creating the potential for it to be targeted multiple times

  • Set HitShocked to true

    • provided the previous conditions are met, this target cannot be targeted again by subsequent chains 

  • Add Actor to SurroundingEnemies Array

For Each Loop 3 - iterate through through SurroundingEnemies

  • Check ChainNumber

    • important!! This is where the main iteration of subsequent hits happens. ​

    • The if statement after prevents another chain happening. If true, it is out of range, HitShocked is reset and the target can be retargeted

  • Create Transform information for the next Niagara system representing the "chain"

    • use current actor as start location​

    • get facing rotation between current actor and actor it is chaining to

Connect to Niagara System

  • Set Niagara Variable By String

    • this node sets up this Blueprint Actor to receive particle data from the Niagara System

  • Event Receive Particle Data

    • on a collision event, the system sends information to this actor based on the setup above

    • it triggers the BecomeShocked event in the target it hits, connected by the Target Enemy object linked on its spawn

    • this setup allows for the timing to be more fluid and activate the effects when the targets are hit (this made me redo the mechanics of BP_Enemy however)

Mixamo Animation on UE4 Character

Mechanics Development

Mechanic Functionality in Game:

enemyBP_7.PNG
enemyBP_8.PNG
enemyBP_9.PNG
enemyBP_10.PNG
aftershocksBP_1.PNG

Each of the Niagara systems are placeholders simply to give a visual indication of how the effect will be timed later, and were used in Blueprint as I built the mechanics. This is not all of the systems/emitters I will make.

Building the Effects

With a good base to work from and visualize the effect, I can start to build and refine the actual look of the effect and make it pretty. I already did some research on the lightning and what approach I should use. A popular method is beams, but I find these hard to control, and it's very hard to make them look correct. A lot of the time they end up looking stringy, curvy, and messy. I found a different method which should give me more control over the look and movement of the lightning. It is done by actually creating meshes and cycling through them. 

Examples of this:

BP_Aftershocks
basicoutgoingniagara.PNG

The temporary Niagara System communicates with the BP_Aftershocks Actor (which is the visual sent from one Enemy to another when chaining) by using a user parameter called BPCallback, representing the object the system can communicate with. When a collision event is triggered, the Actor is notified.

"Mesh Flipbook" method:

The process I tried first was this mesh flipbook, which, through a material, alternates the visibility of meshes through their assigned vector color. This is definitely a good method for a more stylized lightning bolt as it gives you control over the base look of the lightning, but problems start to come up when you need to adjust for the distance between two objects. For example, a target could be 2 meters away or 5, but because this is a mesh, it has a fixed size. You could scale it on its local X axis, though it might look a little weird and obvious when targets get vey far or very close. Another possibility is making a set of bolts for set distances, which is much more involved.

Another consideration is the actual look. As I said, this is a great method for stylized lightning, but I was wanting something more on the realistic side with respects to noise and movement. The first example I gave actually modeled the bolts with an animation in mind so it looked more natural, which would be preferable. For the look I want, the actual lightning meshes would need a lot more work, and would probably need to be used in conjunction with other particle systems.

lightningmeshmat_1.PNG

This is the part of the material graph controlling the opacity of the meshes. I tried following the method of the first example, though I'm still struggling to get the look I want (flash frequency, etc). I haven't worked with vertex colors too much, I assign them in Maya where I made the temporary meshes used below. 

Resulting opacity mask

Vector Color (red channel variance by ~0.1-0.2)

Using Beams

Since the meshing method would take a lot of tweaking, I decided to give beams a try. They are definitely more flexible when it comes to blueprints, but it is harder to control. Below is a sample of the main bolt attack with only 4 emitters (one per bolt) and an emissive color. It is manipulated by noises and jitters.

This definitely took less time to achieve, I just worry about how far I'll be able to develop it, as lightning is notoriously difficult with just beams.

best reference

Since the meshing method would take a lot of tweaking, I decided to give beams a try. They are definitely more flexible when it comes to blueprints, but it is harder to control. Below is a sample of the main bolt attack with only 4 emitters (one per bolt) and an emissive color. It is manipulated by noises and jitters.

This definitely took less time to achieve, I just worry about how far I'll be able to develop it, as lightning is notoriously difficult with just beams.

This represents the isolated effect of just the attack from the player. I tried to replicate the variation of thickness in the strikes, primarily focusing on a thick beam in the center. The hardest part to finesse is the curves and shape of the bolts. I used a variety of noises to create the jittered look of lightning and control the movement. I also liked the sparks left over after the bolts die.  

An issue I discovered was that because the shape is determined by noise, the frequencies affect the beam differently at when they get shorter or longer. It needs to be adaptable.

Lightning_PNS_bigEmitter.PNG
Lightning_PNS_bigEmitter_curlnoise.PNG
Lightning_PNS_bigEmitter_applyinit.PNG
Lightning_PNS_bigEmitter_userparams.PNG

I use a curl noise to alter the position of the beam from its starting shape (basically a line). The influence of the noise wanes as the Age of the system increases, visualized on the curve. This is how there are bulges in some areas of the beam while the ends stay in one place, and also why the noise intensity dies down as the effect dies. In some other systems, I also use jitter position to create a more jerky line. 

 

I don't want it to uniformly affect the beam, so the initial forces, what makes the beam receive these forces on spawning, are controlled along the length/link order. The ends are relatively held down, so it feels anchored. 

These are the user parameters for this system. BeamLength stores the total length of the beam in units. LightningColor is self explanatory, and also allows the user to define a custom color in the blueprint. LocalBeamEnd, probably the most important, determines the endpoint of the beam. This places the end on an enemy or other hit point in the world, defined by the blueprint using linetrace and GetActorLocation. NormalizedLength takes the BeamLength in the blueprint and normalizes it to a 0 to 1 range, so that it can be used as a curve index. This is helpful to control the frequencies of some of the bolt emitters that are highly affected by length variation.

LightningBolt_bP_variabledefine.PNG
Lightning in Chain

I used this same technique to make the additional emitters for the big strike on hit 3. The focus here was to emphasize impact. I will also add camera shake later to further this feeling. There is also a slightly developed "shocked" effect which plays out as the enemy is shocked, about 3 seconds.

In Context
Sample Final Breakdown
bottom of page