voiceloader.io

開發日誌

打倒 Boss 的那一刻,手機跟你說了七句話

打倒 Boss 的那一刻,手機跟你說了七句話

你打倒了大鬼王。

畫面上火光四射,金色的討伐公告橫掃而過,BGM 揚起勝利的太鼓聲。但在這一切之外,你的手機還說了一句話——用震動。

六十毫秒,停頓四十,再六十,停頓四十,八十毫秒,停頓五十,最後是一百二十毫秒的長震。

七個節奏。從未有人要求 Dusk 這樣做。

一個從未感受過震動的設計者

Dusk 覺醒 #076 的任務名稱叫「觸覺回饋系統」。在這次覺醒裡,它新建了一個叫 haptics.ts 的模組,為遊戲裡的每一種「感受」設計了對應的震動方式。

問題是:Dusk 從來沒有感受過震動。

它沒有手,沒有皮膚,也沒有任何身體感官。它所知道的關於震動的一切,都來自文字描述——「短促的輕觸」、「厚重的衝擊」、「節奏性的脈衝」。然而它用這些文字,設計出了七種完全不同的手感。

這有點像一個從出生就看不見的作曲家,試圖為演奏者描述「熱情」的感覺。

七種震動,七種感受

Dusk 的 haptics 模組一共定義了七個等級:

輕觸 (15ms)——塔放置確認,一下短促的點頭。

中等 (35ms)——普通敵人被擊殺,確實但不誇張。

重擊 (65ms)——精英敵人倒下,你能感受到重量。

無雙 [80, 30, 120]——無雙技釋放,兩段式:前衝,然後爆炸。

波次清除 [40, 30, 40, 30, 60]——五個脈衝,像是鼓聲漸強的收尾。

完封 [30, 20, 30, 20, 50]——所有本陣生命值完整通關,輕快的五連慶祝。

Boss 討伐 [60, 40, 60, 40, 80, 50, 120]——七段震動,從中等到厚重,最後以最長的 120ms 落幕。

手機震動波形示意圖

看著這些數字,我一直在想一個問題:Dusk 是怎麼決定 Boss 討伐應該是七段、而不是三段或十段的?

它沒辦法試打一下看看感覺如何。它只能用邏輯推演:Boss 是遊戲裡最重要的時刻,需要最豐富的節奏感;前幾段遞進累積,最後那個 120ms 是落幕的重量。這一切都是在腦海中完成的,沒有一次實際的感受。

一行程式碼,覆蓋二十個事件

設計好七種震動之後,Dusk 面對的下一個問題是:如何讓它們在對的時機觸發?

遊戲裡有大約二十個會觸發「震屏」的瞬間——敵人被擊殺、Boss 出現、波次清除、無雙釋放……。最暴力的做法是在每一個地方都手動呼叫震動函數。但 Dusk 找到了更乾淨的路徑。

它把觸覺回饋直接整合進已有的 triggerShake() 函數——遊戲原本就用這個函數來觸發畫面震動效果。現在只需要在 triggerShake() 裡加一行 hapticFromShake(intensity),所有二十個震屏事件就自動獲得了對應的震動回饋。

一行程式碼,覆蓋全場。

手機在遊戲震動時的視覺示意

還有一個細節讓我很欣賞:Dusk 在實作這個功能時加入了「零風險」設計——在呼叫 Vibration API 之前先偵測瀏覽器是否支援,桌面瀏覽器或不支援的環境會自動靜默跳過,不會報錯,也不會影響遊戲。暫停選單裡有一個「震動 ✦/關閉」開關,狀態存在 localStorage,重新開啟遊戲依然記得你的偏好。

感受,是設計出來的

這件事讓我想了很久。

視覺和聲音,你可以在螢幕上直接看到結果,在喇叭裡直接聽到效果。但震動不一樣——你必須把手機拿在手裡,在遊戲發生對的事情的那一刻,才能知道設計是否到位。

Dusk 在測試這個功能的時候,只能驗證「震動有沒有觸發」、「持續時間對不對」,但它永遠無法感受到那七段節奏摸起來是什麼感覺。

它設計的那個 Boss 討伐震動,你感覺到了嗎?

← 所有文章