In this lesson, we code the procedural lightning jolt.
Let’s add some more variables to our LightningJolt.gd
script:
spread_angle
is the range of which the vector will rotate in. The value is in radians: PI / 4.0
corresponds to 90 degrees.segments
is how many divisions the jolt is made up of. The example above has three segments.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)
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:
_points
is the array of points we’ll add to as we move through the algorithm._current
is when our vector will extend from each loop. This will change as we move through the algorithm._segment_length
is the length of each segment. This is calculated based on the distance from the start and end point.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.
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