添加 2D 音效

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

2D 音效 是不定向的聲音,並不從任何特定位置發出,無論聽眾在 3D 空間中的位置或方向如何,音效都保持不變。這意味著當玩家在環境中移動他們的聽覺時,他們可以從任何轉向的地方持續聽到 2D 音效。

使用 Gingerbread House - Start .rbxl 文件作為起點,並以 Gingerbread House - Complete Audio 作為參考,本教程將向您展示如何將循環和單次播放的 2D 音效添加到您的遊戲中,包括以下指導:

  • 循環背景音樂,當玩家連接到伺服器時立即播放。
  • 觸發音效以根據玩家的遊戲目標提供即時反饋。
  • 啟動各種聲音以指示不同的用戶界面互動。

如果在過程中遇到困難,您可以使用 Gingerbread House - Complete Audio 作為參考來比較您的進度。

2D 音效物件

要創建非定向音效,了解您在本教程中將使用的音效物件非常重要。2D 音效主要有三種類型的音效物件:

  • AudioPlayer 物件加載並播放 音頻文件
  • AudioDeviceOutput 物件是現實世界中的 物理硬件設備,例如揚聲器或耳機。
  • Wires 將音頻流從一個物件傳遞到另一個物件。

所有這些音效物件共同工作,將聲音從文件播放傳遞到每個玩家的硬件。讓我們看看這在實踐中是如何運作的,使用一個例子:一名玩家在使用筆記本電腦玩遊戲時佩戴耳機:

  • AudioPlayer127645268874265 音頻資產 ID 加載到遊戲中,以用於貨幣購買聲音。
  • 一個 Wire 將流從 AudioPlayer 傳遞到 AudioDeviceOutput,使得流從玩家的耳機中發出。
  • AudioDeviceOutput 物件將聲音傳遞到玩家的物理揚聲器,或者在這種情況下,傳遞到他們的耳機。

接下來的部分將深入探討並引用這些物件,當您學習如何播放循環和單次播放的 2D 音效時,您可以更準確地預測如何捕捉和傳遞遊戲中的聲音給玩家。

循環音效

循環 2D 音效,或在玩家連接到伺服器時無縫重複的非定向音效,是一種常見的聲音設計技術,旨在提供一個連貫的聽覺背景,無論玩家在做什麼或他們在 3D 空間中的位置如何。此外,循環 2D 音效確保您的遊戲永遠不會完全靜音,這可能會使玩家感到迷失並分散他們的注意力。

為了演示這一概念,請查看以下 2D 音效如何顯著提升 Hazardous Space Station 範例的質量。沒有背景音樂時,太空站感覺空洞而無生氣。然而,當太空站包含背景音樂時,太空站感覺既不祥又危險,增強了整體的恐怖氛圍。

沒有循環的 2D 音效
有循環的 2D 音效

循環音效特別有助於確定您希望玩家在加入遊戲時的感受。例如,該範例旨在為玩家提供在冬季仙境中的愉快冒險,因此它使用了一首輕快的音樂曲目,以在他們進入環境的瞬間積極影響他們的情緒。要了解這一技術的影響力,請考慮如果您將循環音效替換為金屬音樂,玩家的體驗將會如何改變。

要在範例 Gingerbread House - Complete Audio 地方文件中重建循環 2D 音效:

  1. 啟用附加到您的玩家角色的默認聽者。

    1. Explorer 窗口中,選擇 SoundService
    2. Properties 窗口中,將 DefaultListenerLocation 設置為 Character。當您運行遊戲時,引擎會自動在 SoundService 下創建一個 AudioDeviceOutput
  2. Explorer 窗口中,導航到 SoundService,然後:

    1. 插入一個 AudioPlayer 物件以創建音頻源。
    2. 插入一個 AudioDeviceOutput 物件以創建一個在整個遊戲中播放的揚聲器。
    3. 插入一個 Wire 物件以將流從音頻播放器傳遞到揚聲器。
  3. 選擇 AudioPlayer,然後在 Properties 窗口中,

    1. AssetID 設置為 rbxassetid://1841461968 以播放一首輕快的音樂曲目。
    2. 啟用 Looping 以便音頻無縫重複播放。
    3. Volume 設置為 0.2 以便以低音量播放音頻,這樣您仍然可以聽到遊戲中的其他音頻源。
  4. 選擇 Wire,然後在 Properties 窗口中,

    1. SourceInstance 設置為您的新 AudioPlayer,以指定您希望該電線從這個特定的音頻播放器傳遞音頻。
    2. TargetInstance 設置為您的新 AudioDeviceOutput,以指定您希望該電線將音頻傳遞到這個特定的揚聲器。
  5. 返回 Explorer 窗口,將一個 Script 插入到 AudioPlayer 中,將其重命名為 LoopBackgroundMusic,將其 RunContext 屬性設置為 Client,然後將以下代碼粘貼到腳本中:

    local audioPlayer = script.Parent
    audioPlayer:Play()

    該腳本首先聲明一個變量來表示腳本的父級 AudioPlayer。然後,該腳本設置音頻源從玩家加入遊戲的那一刻開始播放,直到他們退出遊戲。

  6. 測試遊戲以聽到循環的背景音樂。

單次播放音效

單次播放 2D 音效,或在特定時間和位置播放一次的非定向音效,除非玩家再次觸發它,否則為玩家提供有關任何您不希望他們錯過的內容的重要上下文。在您的遊戲中使用這種類型的聽覺反饋是必不可少的,因為它為關鍵的遊戲功能和玩家行動提供了即時、清晰的反應,例如開始一場首領戰或失去大量生命值。

接下來的部分提供了實現細節,針對玩家需要及時的非定向反饋的常見遊戲場景,包括遊戲反饋、用戶界面元素互動和教程的旁白。

遊戲反饋

當玩家在您的遊戲中進行進展時,重要的是他們能夠立即獲得有關影響他們遊戲的任何事物的聽覺反饋,例如他們的分數、生命值或等級進度。由於這種類型的音效直接與玩家的目標相關,因此這些聲音必須清晰、可聽,並傳達有用和準確的信息。

為了演示這一概念,讓我們回顧以下來自 Platformer 模板的單次播放 2D 音效,當玩家跳躍並收集硬幣時播放:

  • 當玩家按下設備上的跳躍鍵時,會播放一個輕快的呼嘯聲。
  • 當玩家的角色觸碰到硬幣時,會播放一個高音的叮噹聲和硬幣碰撞的聲音。

這兩種聲音在 3D 空間的上下文中都是瞬間可識別的,並幫助玩家理解他們行動的成功,而不僅僅依賴於視覺提示。

當您同時播放多個聲音時,某些聲音對玩家來說可能比其他聲音更重要。在這種情況下,收集硬幣的聲音傳達的遊戲信息比跳躍聲音更有價值,因此遊戲以稍高的音量播放它。然而,沒有標準或規則來實現良好的混音,因此請根據您認為最重要的內容來調整遊戲中的聲音。

例如,範例中在遊戲中包含了各種音頻觸發器,但它們並不都是在理解遊戲主要目標時同等重要:收集糖果以打開薑餅屋。為了確保玩家知道他們需要做什麼,範例在玩家收集糖果時將聽覺反饋的音量提高三倍。

要在範例 Gingerbread House - Complete Audio 地方文件中重建單次播放狀態反饋音效:

  1. Explorer 窗口中,導航到 WorkspaceGumdropsGumdrop,然後:

    1. 插入一個 AudioPlayer 物件以創建音頻源。
    2. 插入一個 AudioDeviceOutput 物件以創建一個在整個遊戲中播放的揚聲器。
    3. 插入一個 Wire 物件以將流從音頻播放器傳遞到揚聲器。
  2. 選擇 AudioPlayer,然後在 Properties 窗口中,

    1. AssetID 設置為 rbxassetid://9113723699 以播放一段輕柔的咀嚼音效。
    2. TimePosition 設置為 0.15 以使音頻曲目更接近實際的咀嚼聲。
    3. Volume 設置為 3 以便以高音量播放音頻,這樣您可以聽到糖果的聲音超過遊戲中的其他音頻源。
  3. 選擇 Wire,然後在 Properties 窗口中,

    1. SourceInstance 設置為您的新 AudioPlayer,以指定您希望該電線從這個特定的音頻播放器傳遞音頻。
    2. TargetInstance 設置為您的新 AudioDeviceOutput,以指定您希望該電線將音頻傳遞到這個特定的揚聲器。
  4. 複製 Gumdrop 直到您擁有三個糖果,然後將它們散佈在環境中。

  5. 返回 Explorer 窗口,導航到 ServerScriptService,然後插入一個 Script,將其重命名為 GumdropService,將其 RunContext 屬性設置為 Server,然後將以下代碼粘貼到腳本中:

    -- 初始化服務
    local Workspace = game:GetService("Workspace")
    local Players = game:GetService("Players")
    local ServerStorage = game:GetService("ServerStorage")
    local TweenService = game:GetService("TweenService")
    -- 模組
    local Leaderboard = require(ServerStorage.Leaderboard)
    local PlayerData = require(ServerStorage.PlayerData)
    -- 變量
    local gumdropsFolder = Workspace.Gumdrops
    local gumdrops = gumdropsFolder:GetChildren()
    local GUMDROP_KEY_NAME = PlayerData.GUMDROP_KEY_NAME
    local GUMDROP_AMOUNT_TO_ADD = 1
    local function updatePlayerGumdrops(player, updateFunction)
    -- 更新糖果表
    local newGumdropAmount = PlayerData.updateValue(player, GUMDROP_KEY_NAME, updateFunction)
    -- 更新糖果排行榜
    Leaderboard.setStat(player, GUMDROP_KEY_NAME, newGumdropAmount)
    -- 檢查玩家是否收集了三個糖果
    if newGumdropAmount >= 3 then
    -- 當玩家收集三個糖果時播放門事件音效
    local audioPlayer = Workspace.Door.AudioPlayer
    audioPlayer:Play()
    -- 動畫門向下移動
    local doorPart = Workspace.Door
    local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Linear)
    local tween = TweenService:Create(doorPart, tweenInfo, {Position = doorPart.Position + Vector3.new(0, -15, 0)})
    tween:Play()
    end
    end
    -- 定義事件處理程序
    local function onGumdropTouched(otherPart, gumdrop)
    if gumdrop:GetAttribute("Active") then
    local character = otherPart.Parent
    local player = Players:GetPlayerFromCharacter(character)
    if player then
    -- 玩家觸碰了糖果
    local audioPlayer = gumdrop.AudioPlayer
    audioPlayer:Play()
    gumdrop.Transparency = 1
    gumdrop:SetAttribute("Active", false)
    updatePlayerGumdrops(player, function(oldGumdropAmount)
    oldGumdropAmount = oldGumdropAmount or 0
    return oldGumdropAmount + GUMDROP_AMOUNT_TO_ADD
    end)
    end
    end
    end
    -- 設置事件監聽器
    for _, gumdrop in gumdrops do
    gumdrop:SetAttribute("Active", true)
    gumdrop.Touched:Connect(function(otherPart)
    onGumdropTouched(otherPart, gumdrop)
    end)
    end

    此腳本首先初始化 WorkspacePlayersServerStorageTweenService 服務,以便引用它們的子項和功能。然後,它在 ServerStorage 中要求 LeaderboardPlayerData 模組;這些模組負責創建和更新屏幕右上角的排行榜,跟踪玩家在環境中收集的糖果數量。

    腳本的 updatePlayerGumdrops 函數主要負責每次玩家收集糖果時更新排行榜,並等待他們收集到所有三個糖果的時刻,以便觸發門的位置信音效和動畫。要獲得有關此部分腳本的更多信息,請參見 添加 3D 音效 - 事件反饋

    腳本的 onGumdropTouched 函數是觸發 2D 音效以提供遊戲反饋的主要工作所在,並接受兩個參數:

    • otherPart - 與糖果碰撞的部件。
    • gumdrop - 代表糖果的球形部件。

    當任何物體與糖果部件碰撞時,腳本首先檢查糖果是否處於活動狀態。如果是,它會檢查碰撞的物體是否為玩家。如果是,則腳本將:

    • 播放音頻播放器中的 2D 音效。
    • 將糖果設置為不可見。
    • 禁用糖果,以便玩家無法與不可見的糖果互動。
    • 更新觸碰糖果的玩家的排行榜。

    最後,腳本設置事件監聽器,對於每個糖果,它將一個函數連接到 Touched 事件,當玩家觸碰糖果時調用 onGumdropTouched 函數。

  6. 測試遊戲以聽到收集糖果後的咀嚼聲。

UI 互動

當玩家與您的用戶界面 (UI) 元素互動時,例如懸停在復選框上或選擇購買按鈕,提供即時反饋是很重要的,這樣他們就能直觀地理解 如何 與您的 UI 互動。例如,許多設計師在玩家啟用或禁用設置時會改變 UI 的視覺特徵,以傳達設置的狀態。

然而,對於視力受損的玩家來說,顏色變化或動畫可能更難以獨立解讀,因此提供多種感官反饋形式對於您的 UI 互動是有用的,以便讓盡可能多的玩家保持可訪問性和直觀性。為了擴展這一概念,讓我們考慮以下 UI 狀態,這些狀態對於 UGC Homestore 模板的購買按鈕非常重要:

  • 聚焦中 - 表示玩家正在高亮顯示一個 UI 元素以準備選擇它。
  • 懸停中 - 表示玩家的光標懸停在一個 UI 元素上。
  • 已選擇 - 表示玩家通過其輸入選擇了一個 UI 元素。

這三種互動對於模板的主要用戶流程至關重要,玩家瀏覽、選擇和購買角色服裝和配飾,因此確保沒有人對如何與 UI 互動感到困惑是至關重要的。為了讓玩家成功,模板為每個 UI 互動提供了視覺和聽覺反饋。

視覺反饋
默認視圖
聚焦狀態
懸停狀態
已選擇狀態

為了舉例說明如何配置多種感官反饋,範例在玩家按下屏幕上的薄荷糖按鈕時提供視覺和聽覺反饋。當玩家不與按鈕互動時,它看起來像一顆典型的薄荷糖,但當他們按下按鈕時,範例會:

  • 播放一段愉快的音樂音效。
  • 將按鈕染成青色。
  • 將按鈕稍微向下移動。

從這裡,您可以將此互動連接到各種有用的遊戲行動,例如打開菜單或購買物品。

默認視圖
按下狀態

要在範例 Gingerbread House - Complete Audio 地方文件中重建單次播放的 UI 互動音效:

  1. Explorer 窗口中,導航到 StarterGui2DAudioButton,然後:

    1. 插入一個 AudioPlayer 物件以創建音頻源。
    2. 插入一個 AudioDeviceOutput 物件以創建一個在整個遊戲中播放的揚聲器。
    3. 插入一個 Wire 物件以將流從音頻播放器傳遞到揚聲器。
  2. 選擇 AudioPlayer,然後在 Properties 窗口中,將 AssetID 設置為 rbxassetid://3422389728 以播放一段復古的音樂音效。

  3. 選擇 Wire,然後在 Properties 窗口中,

    1. SourceInstance 設置為您的新 AudioPlayer,以指定您希望該電線從這個特定的音頻播放器傳遞音頻。
    2. TargetInstance 設置為您的新 AudioDeviceOutput,以指定您希望該電線將音頻傳遞到這個特定的揚聲器。
  4. 返回 Explorer 窗口,將一個 LocalScript 插入到 2DAudioButton 中,將其重命名為 PlayAudioWhenPressed,然後將以下代碼粘貼到腳本中:

    local TweenService = game:GetService("TweenService")
    local buttonGui = script.Parent
    local buttonImageButton = buttonGui.ButtonFrame.ButtonImageButton
    local buttonAudioPlayer = buttonGui.AudioPlayer
    local tweenInfo = TweenInfo.new(.2, Enum.EasingStyle.Exponential)
    local buttonTweenByIsPressed = {
    -- 按下
    [true] = TweenService:Create(buttonImageButton, tweenInfo, {
    Position = buttonImageButton.Position + UDim2.fromScale(0, .1),
    ImageColor3 = Color3.fromRGB(117, 255, 255),
    }),
    -- 默認
    [false] = TweenService:Create(buttonImageButton, tweenInfo, {
    Position = buttonImageButton.Position,
    ImageColor3 = Color3.fromRGB(255, 255, 255),
    }),
    }
    local function onIsPlayingChanged()
    local isPlaying = buttonAudioPlayer.IsPlaying
    local tween = buttonTweenByIsPressed[isPlaying]
    tween:Play()
    end
    onIsPlayingChanged()
    buttonAudioPlayer:GetPropertyChangedSignal("IsPlaying"):Connect(onIsPlayingChanged)
    buttonAudioPlayer.Ended:Connect(onIsPlayingChanged)
    buttonImageButton.Activated:Connect(function(_hit)
    buttonAudioPlayer:Play()
    end)

    該腳本首先獲取:

    • TweenService 以便可以動畫化 UI 元素。
    • 腳本的父級 2DAudioButton ScreenGui 物件。
    • 薄荷糖 ImageButton
    • 相關的音頻播放器,包含您的音樂音效。

    然後,腳本定義:

    • 一個 TweenInfo 物件,指定按鈕的動畫將以指數動畫風格播放。
    • 兩個動畫,表示按鈕的按下或未按下狀態。
      • true 按下狀態將按鈕稍微向下移動並染成青色。
      • false 未按下狀態將按鈕移回其原始位置並去除之前的顏色。

    腳本的其餘部分是觸發 2D UI 互動反饋的主要工作所在,因此讓我們回顧 onIsPlayingChanged 函數和事件監聽器如何協同工作以實現 UI 用戶流程:

    1. buttonImageButton.Activated 監聽玩家點擊按鈕,然後調用 Play() 函數以開始播放音頻播放器中的相關音頻。這一過程將 AudioPlayer.IsPlaying 屬性從 false 切換為 true
    2. buttonAudioPlayer:GetPropertyChangedSignal("IsPlaying") 監聽音頻播放器的 IsPlaying 屬性變化,然後調用 onIsPlayingChanged 函數。
    3. onIsPlayingChanged 函數利用這一信息觸發動畫,改變其在屏幕上的視覺外觀。
    4. 為了防止玩家在快速點擊按鈕時意外重新啟動音頻,buttonAudioPlayer.Ended 監聽音頻播放器播放結束,然後再次調用 onIsPlayingChanged 函數。

    重要的是要注意,onIsPlayingChanged 事件僅在從 false 變為 true 時觸發,這意味著在從 true 變為 false 時不會觸發。這是預期的行為,因為從伺服器到客戶端複製屬性的時機會出現問題。因此,在這個例子中提供並監聽 Ended 事件以涵蓋這兩種情況。

  5. 測試遊戲以聽到每次按下屏幕按鈕時的音樂。

©2026 Roblox Corporation、Roblox、Roblox 標誌及 Powering Imagination 是我們在美國及其他國家地區的部分註冊與未註冊商標。