畫形狀、加粒子、調時間、匯出。這篇把整條路走完,包含匯出那一步最容易出事的地方。
幾乎所有攻擊特效都是從一筆畫開始的。先畫出武器揮過去的那道弧線,其他什麼都不要加。 如果單一幀看起來就夠清楚,動起來一定好看;如果不清楚,加再多粒子也救不回來。
沿著筆畫加火花,在命中點加一次閃光,通常就夠了。最常見的錯誤是整個畫面到處噴粒子, 結果把一道清楚的刀光變成雜訊。
持續型特效(下雨、餘燼、一直循環的增益光環)的粒子數量意義不一樣。
一次性爆發時,數量是「總共發射幾顆」;循環特效時,是「畫面上同時維持幾顆」,
發射率等於 數量 ÷ 平均壽命。循環特效還需要預熱幾十幀,
否則第 0 幀是一片空白。
多數攻擊特效在 12 到 20 幀之間最好看。再長就會顯得飄, 除非那是蓄力或持續燃燒。
真正需要做決定的地方在這裡。三種格式不能互換。
| 格式 | 什麼時候用 | 要注意 |
|---|---|---|
| PNG 序列 | 要最好的品質,或特效有柔邊、煙霧、霧氣。 這是唯一有真正逐像素透明度的格式。 | 檔案很多。多數引擎最後還是要你打包成圖集。 |
| 精靈圖集 | 要匯入引擎。一張貼圖、一次 draw call,而且每個引擎都內建播放方式。 | 貼圖壓縮(DXT/BC/ASTC)需要 2 的次方尺寸——要壓縮就把圖集補齊。 |
| 動態 GIF | 要給人看的時候——發文、開發日誌、丟 Discord。不要拿來上遊戲。 | 完全沒有半透明。看下面的警告。 |
rgb × a + 底色 × (1 − a)),存成實色,同時讓 alpha 低於門檻的地方維持全透明。
這樣柔和的層次回來了,GIF 背景也還是透明的。
真的需要半透明輸出,就只能用 PNG 序列,GIF 沒有任何變通辦法。
純 2D 動畫的話:匯入圖集,設定 Sprite Mode: Multiple,
在 Sprite Editor 裡按格子尺寸切開,再把切出來的幀拖到 Animator。
粒子驅動的特效要用 Particle System:把圖集指定給使用 Particles/Standard Unlit 著色器的材質,在發射器上啟用 Texture Sheet Animation,Tiles X/Y 設成你的格子數。 發光類的材質混合模式選 Additive,煙霧和碎片選 Alpha Blended。
匯入圖集後,在 Niagara 的發射器加上 SubUV Animation 模組,
sub-image 數量設成你的格子數。材質裡要用 SubUV_Function 節點——
直接把貼圖接進去的話,每顆粒子會顯示整張圖集,而不是一次一幀。
2D 最快的做法是 AnimatedSprite2D:建一個 SpriteFrames 資源,
加入圖集,設定橫向/縱向格數。粒子則用 GPUParticles2D,
在 CanvasItemMaterial 啟用 Particles Animation,
H Frames 和 V Frames 對應格子數。
3D 的話用 GPUParticles3D,StandardMaterial3D 設成
Billboard: Particle Billboard 並啟用 Particles Anim。
用 this.load.spritesheet(key, url, { frameWidth, frameHeight }) 載入圖集,
再用 this.anims.create({ key, frames, frameRate, repeat }) 建立動畫。
如果匯出時有一起產生 TexturePacker 格式的 JSON,改用
this.load.atlas(),幀名稱會自動帶過去。
如果特效在淺色背景上出現一圈暗暈,原因是完全透明的像素其實還是帶著 RGB 值, 而 canvas 匯出時那個值通常是純黑。引擎在過濾貼圖時,會把那些黑色往內混進來。
解法是 alpha 溢色:在量化或存檔之前,把透明像素的 RGB 從最近的實體像素往外填。 alpha 仍然是 0,看起來沒有任何差別,但過濾時就會往正確的顏色混合。
發光半徑、粒子大小、筆畫粗細通常是用像素寫死的。匯出 2 倍時整體會跟著縮放, 但只要流程裡有任何一段是用絕對像素、其他部分卻會縮放,就會出現用眼睛很難察覺的不一致。 做法是各匯出一張 1× 和 2× 的測試幀,把其中一張縮放到跟另一張一樣大,直接對比。
現在做一個 → VFX Studio 在瀏覽器裡跑,不用安裝、不用訂閱。免費使用,只有匯出時才需要點數。