The Lightning Jolt Script

In this lesson, we code the procedural lightning jolt.

Let’s add some more variables to our LightningJolt.gd script:

extends Line2D

export (float, 0.5, 3.0) var spread_angle := PI/4.0
export (int, 1, 36) var segments := 12

As this is an effect we want to be independent of its parent, we set it as top-level to not inherit its parent’s rotation or position.

func _ready() -> void:
    set_as_toplevel(true)

Generating the jolt procedurally

Let’s flesh out the create() method now. The LightningBeam will call this method and pass it the weapon’s position and the jolt’s target position.

In our create() function, we need to:

First, we define some temporary variables:

func create(start: Vector2, end: Vector2) -> void:

    var _points := []
    var _current := start
    var _segment_length := start.distance_to(end) / segments

We kick things off by adding the start point to the _points array.

For each segment, we get a random rotation based on our spread_angle.

We then create a new vector starting from our _current vector. direction_to() returns a unit vector towards our end point, so we multiply it by the _segment_length. We also use the vector method rotated() to rotate this new vector by the _rotation chosen above.

We add this vector to _points, update our _current vector, and repeat for as many segments we need.

Finally, we set the Line2D points to _points and set our sparks’ global position to the end point.

    _points.append(start)

    for segment in range(segments):
        var _rotation := rand_range(-spread_angle / 2, spread_angle / 2)
        var _new := _current + (_current.direction_to(end) * _segment_length).rotated(_rotation)
        _points.append(_new)
        _current = _new

    _points.append(end)
    points = _points

    sparks.global_position = end

We can test our function by calling the create() function in _ready(). Doing so runs our algorithm when the scene enters the scene tree to see how it works.

func _ready() -> void:
    set_as_toplevel(true)
    create(Vector2.ZERO, Vector2(400, 400))

Press F6 to run the LightningJolt scene, and you’ll see something like this, which is a jolt from (0,0), to (400, 400).

That’s great, but we need to make it look more appealing. In the next part, we’ll improve the lighting jolt’s visuals and use the AnimationPlayer to tie everything together.

Final LightningJolt.gd script

extends Line2D

export (float, 0.5, 3.0) var spread_angle := PI/4.0
export (int, 1, 36) var segments := 12

onready var sparks := $Sparks


func _ready() -> void:
    set_as_toplevel(true)


func create(start: Vector2, end: Vector2) -> void:

    var _points := []
    var _current := start
    var _segment_length := start.distance_to(end) / segments

    _points.append(start)

    for segment in range(segments):
        var _rotation := rand_range(-spread_angle / 2, spread_angle / 2)
        var _new := _current + (_current.direction_to(end) * _segment_length).rotated(_rotation)
        _points.append(_new)
        _current = _new

    _points.append(end)
    points = _points

    sparks.global_position = end