Floating Lightning Effect Implement multiple moving jagged lines using Godot

靜態的閃電 (Jagged Line) 作法很單純,做一條直線,亂數在中間取幾個點,在取得的點上加上亂數的振幅,重複上面步驟就可以做出各種效果。

而流動感的閃電效果相對麻煩了些,下面是我在 Godot 做的 demo。

如何做的?

Step 1: Base Loop Jagged Line

影片中左邊數來第一條線就是 Jagged Line,我們不只是要做單純的 Jagged Line,我們要讓它可以無限循環 (loop,,換句話說就是頭尾要相連。

第一種寫法是用亂數完成,亂數雖然簡單方便,不過有時候產生的效果不如己意。

第二種做法是手繪,寫一個小工具,紀錄自己手繪線條跟參考線的震幅,然後輸出成文字檔。

我使用的是第二種方法。

在儲存 Jagged Line 時,不需要真的用座標方法儲存,只要跟 WAV 檔一樣紀錄震幅就好,像是:

(0,0) (1,2), (2,-1), (3,-2)

只要記錄 [0,2,-1,-2],這樣不管是要放大縮小或取內插中間值都很夠用。更重要的,只要做一條就可以產生很多條不同的 Jagged Line,可以將開頭設為中間某個點,可以倒敘取震幅值,可以正負相反做鏡像線,或是混合上面三種參數等等。

我的例子是手繪了單一一條六千多個震幅的線,其他就任意取值選自己喜歡的。

Step 2: Tranform from One Jagged Line to Another

影片中的第二條線是在二條不同的 Jagged Line 變換的示範,純粹是向量和比例的計算。

像是我如果是要畫一條從 pt1(0, 0) 到 pt2(300, 300) 的流動閃電,首先要知道 normalized vector 和長度,用來知道每個參考點 (也就 pt1 – pt2 的直線點) 的座標

我知道 normalized vector 中文叫 “正規化向量”,但說真的這名字看了也沒人懂是甚麼東西,叫 “單位向量” 還比較好懂一點。

下面是在 Jagged Line 上取點的 Pseudo-code,我覺得很直覺所以就不解釋了,關於向量,單位向量,向量轉 90 度等等數學問題,應該分另一篇寫。

float total_length = (pt2 - pt1).length()
vec2 unit_vec = (pt2 - pt1).normalized()

for idx in range(0, total_length)
  vec2 ref_pt = pt1 + unit_vec * idx
  vec2 jagged_pt = jagged_line.get_pt( ref_pt, ratio_in_line )

Step 3: Combine S1 and S2 with many Jagged Line

影片的第三條是結合了第一條 (會動的線),和第二條 (會變形的線),然後變形的線增加到六條的效果。當然為了看起來像閃電 (或雷射) 需要有發光效果,發光效果請看我之前的 Blog。

Step 4: Stick start point and end point

最後在遊戲中使用時,一般我們都要固定閃電的起點和終點,像是當飛行武器或是魔法效果時,總要從自己的座標打到對方的座標。

第四條就是修改第三條,在越靠近頭尾時,震幅照比例縮小,到頭尾時震幅變成零。