← 開發日誌

M6:視聽回饋(juice)——粒子、程式合成音效與螢幕震動

到 M5 為止,遊戲玩法完整,但體驗很「乾」——砍中沒火花、死亡無聲、鏡頭不動、受傷沒感覺。這一篇講怎麼把「乾」變「爽」。這層東西業界叫 juice

粒子:單一 THREE.Points 池

所有粒子特效(命中火花、死亡消散、BOSS 爆裂、升級光柱)共用一個 THREE.Points,內含約 600 顆粒子,CPU 每幀更新位置,用 cursor 循環覆蓋最舊的——零持續記憶體配置。

burst(pos, count, { color, color2, speed, spread, gravity, size, life });

不同事件呼叫 burst 給不同參數:

  • 命中 → 橘黃小爆,數量隨傷害
  • 殺怪 → 白灰中爆(骨骸消散感)
  • BOSS 死 → 多色大量爆裂
  • 升級 → 玩家腳下金色上升光柱

用 additive blending + 圓形 alpha 衰減(在 shader 裡 discard 圓外的點),讓粒子發光。關鍵巧思:粒子的 dt 已經乘過 timeScale,所以 hit-stop / 升級暫停時粒子會自然凍結,不用特別處理。

音效:零音檔,全程式合成

這是這款最特別的決定之一——不下載任何音效檔,全部用 Web Audio API 即時合成。呼應整個專案「零素材」的精神。

// 揮砍 = 高頻噪音掃頻下降
noise(0.18, 0.35, 'highpass', 1800, 600);
// 命中 = 方波短爆 + 低頻
tone(180, 0.12, 'square', 0.18, 90);
// 升級 = 上升琶音
[523, 659, 784, 1047].forEach((f, i) => setTimeout(() => tone(f, 0.25, 'triangle'), i * 70));

用振盪器(Oscillator)+ 噪音 buffer + 濾波器 + ADSR 包絡,合出揮砍、命中、受傷、技能、升級、BOSS 吼、拾取、UI 音。音色偏電子合成風,但零授權疑慮、零檔案、零載入時間

兩個實務細節:

  • 自動播放限制:瀏覽器規定要有使用者互動才能出聲。所以 AudioContext 建好後保持 suspended,綁在首次點擊/按鍵才 resume()
  • 節流:群怪被 AOE 同時打中時,同類音效在 ~16ms 內不重複觸發,否則會爆音。

螢幕震動:trauma 模型

不要一受擊就「啪」地硬震。用一個 0–1 的 trauma 值,受擊時累加,每幀指數衰減,實際位移 = trauma²。平方讓小震柔、大震猛,衰減讓震動自然收尾。

trauma = min(1, trauma + amount);      // 受擊累加
trauma *= exp(-k * dt);                // 每幀衰減
const mag = trauma * trauma * MAX;     // 平方 → 位移量
cam.position.add(randomVec * mag);     // 只動鏡頭位置,lookAt 不變(不暈)

受傷中震、BOSS 倒下大震、技能命中多目標累加 → AOE 砍進人堆會有滿足的「轟」。

低血紅暈與受擊閃屏

純 CSS 的全螢幕 radial-gradient 疊層(不進 3D):

  • 受傷瞬間紅色快閃,再淡出
  • 血量低於 30% → 持續紅暈 + 緩慢脈動 + 心跳音

這個視覺訊號比盯著血條更直覺——你「感覺」到自己快死了。


加上這層 juice 之後,同樣的玩法體感完全不同了。最後一篇技術日誌:效能優化與打包,讓它在一般筆電也能 60fps。

← 回開發日誌立即遊玩 →

看更多開發日誌 →