How to create a Lightning Strike in Unity2D


After creating some Sci-Fi attacks like the Rainbow Lazer or the Ro-Cat-Paw Launcher we thought the next special attack should be something more RPG like. So this Blogpost is about how I created a cool chaining lightning strike.

The main idea behind the lightning is to have some line renderers between enemies and generate random line renderer points to get some movement into it. To get amount of points I callculate the distance from the lightning source to its target and split it into segments. After that i know how much points I need. To get the distance between our hero and the enemies I maintain a list of all alive enemies. Just add some randomness and you are almost done.

To make the line renderers look like lightnings I used a texture with a gradient. To make it even more better looking I added one more line renderer simulating a light.

For creating single lightning Bolts I created a separate class:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ChainLightning : MonoBehaviour{
    [Header("Prefabs")]
    public GameObject lineRendererPrefab;
    public GameObject lightRendererPrefab;

    [Header("Config")]
    public int chainLength;
    public int lightnings;

    private float nextRefresh;
    private float segmentLength=0.2f;

    private List LightningBolts{get; set;}
    private List Targets{get; set;}

    void Awake(){
        LightningBolts=new List();
        Targets=new List();

        LightningBolt tmpLightningBolt;
        for(int i=0;i < chainLength;i++){
            tmpLightningBolt=new LightningBolt(segmentLength, i);
            tmpLightningBolt.Init(lightnings, lineRendererPrefab, lightRendererPrefab);
            LightningBolts.Add(tmpLightningBolt);
        }
        BuildChain();
    }

    public void BuildChain(){
        //Build a chain, in a real project this might be enemies ;)
        for(int i=0;i < chainLength;i++){
            Targets.Add(new Vector2(Random.Range (-2f, 2f), Random.Range (-2f, 2f)));
            LightningBolts[i].Activate();
        }
    }

    void Update(){
        //Refresh the LightningBolts
        if(Time.time>nextRefresh){
            BuildChain();
            for(int i=0;i < Targets.Count;i++){
                if(i==0){
                    LightningBolts[i].DrawLightning(Vector2.zero, Targets[i]);
                }else{
                    LightningBolts[i].DrawLightning(Targets[i-1], Targets[i]);
                }
            }
            nextRefresh=Time.time+0.01f;
        }
    }
}

To draw the actual lightning segments I created another class:

using UnityEngine;
using System.Collections;

public class LightningBolt {

    public LineRenderer[] lineRenderer{get; set;}
    public LineRenderer lightRenderer{get; set;}

    public float SegmentLength{get; set;}
    public int Index{get; private set;}
    public bool IsActive{get; private set;}

    public LightningBolt(float segmentLength, int index){
        SegmentLength=segmentLength;
        Index=index;
    }

    public void Init(int lineRendererCount, 
            GameObject lineRendererPrefab, GameObject lightRendererPrefab){
        //Create the needed LineRenderer instances
        lineRenderer=new LineRenderer[lineRendererCount];
        for(int i=0;i < lineRendererCount;i++){
            lineRenderer[i]=(GameObject.Instantiate(lineRendererPrefab) as GameObject)
                .GetComponent();
            lineRenderer[i].enabled=false;
        }
        lightRenderer=(GameObject.Instantiate(lightRendererPrefab) as GameObject)
            .GetComponent();
        IsActive=false;
    }

    public void Activate(){
        //Active this LightningBolt with all of its LineRenderers
        for(int i=0;i < lineRenderer.Length;i++){
            lineRenderer[i].enabled=true;
        }
        lightRenderer.enabled=true;
        IsActive=true;
    }

    public void DrawLightning(Vector2 source, Vector2 target){
        //Calculated amount of Segments
        float distance=Vector2.Distance(source, target);
        int segments=5;
        if(distance > SegmentLength){
            segments=Mathf.FloorToInt( distance / SegmentLength)+2;
        }else{
            segments=4;
        }

        for(int i=0;i < lineRenderer.Length;i++){
            // Set the amount of points to the calculated value
            lineRenderer[i].SetVertexCount(segments);
            lineRenderer[i].SetPosition(0, source);
            Vector2 lastPosition=source;
            for(int j=1;j < segments-1;j++){
                //Go linear from source to target
                Vector2 tmp=Vector2.Lerp(source, target, (float)j / (float)segments);
                //Add randomness
                lastPosition=new Vector2(tmp.x+Random.Range(-0.1f, 0.1f), 
                    tmp.y+Random.Range(-0.1f, 0.1f));
                //Set the calculated position
                lineRenderer[i].SetPosition(j, lastPosition);
            }
            lineRenderer[i].SetPosition(segments-1, target);
        }
        //Set the points for the light
        lightRenderer.SetPosition(0, source);
        lightRenderer.SetPosition(1, target);
        //Set the color of the light
        Color lightColor=new Color(0.5647f, 0.58823f, 1f, Random.Range (0.2f, 1f));
        lightRenderer.SetColors(lightColor, lightColor);
    }
}

The Result

DOWNLOAD UNITY 5 SAMPLE PROJECT

As usual, we want to share a sample project with you – so, it's much easier to understand what we are talking about. Same as last time, be fair and please don't use the graphic assets in your own games.  

2 Comments

Alexander Haider

Even though Alex may be the quiet one but his godlike development skills will render you speechless for quite a while. Some people say: Wherever there's a problem there's an Alex to fix it.