添加文字轉語音

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

文字轉語音是一種輔助技術,將文本字符串轉換為語音聲音,使用人工語音。除了改善視力、行動或認知障礙玩家的遊戲可及性外,TTS還允許您動態生成語音,這樣您就不必為所有可能的敘事場景預先錄製音頻。

使用 Gingerbread House - Start .rbxl 文件作為起點,並以 Gingerbread House - Text-to-Speech 作為參考,本教程將向您展示如何將基本和上下文感知的 TTS 音頻添加到您的遊戲中,包括以下指導:

  • 觸發 TTS 以應對不會改變的常見遊戲場景,例如 UI 互動和教程。
  • 配置 TTS 以便它能夠適應玩家行為、環境狀態或靈活目標。

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

音頻對象

要創建 TTS 音頻,了解您在本教程中將使用的音頻對象非常重要。TTS 有五種類型的主要音頻對象:

  • AudioTextToSpeech 對象將文本字符串轉換為語音聲音。
  • AudioEmitter 對象是一個 虛擬揚聲器,將音頻發射到 3D 環境中。
  • AudioListener 對象是一個 虛擬麥克風,從 3D 環境中接收音頻。
  • AudioDeviceOutput 對象是現實世界中的 物理硬件設備,例如揚聲器或耳機。
  • Wires 將音頻流從一個對象傳輸到另一個對象。

所有這些音頻對象共同工作,以響應玩家行為發出 TTS 聲音。讓我們看看這在 3D 音頻中的實際運作方式,以一個玩家在玩遊戲時佩戴耳機的例子為例:

以下部分將深入探討並引用這些對象,幫助您學習如何播放基本和上下文感知的音頻。在您回顧這些對象及即將到來的技術時,您可以更準確地預測如何捕捉和傳遞遊戲中的聲音給玩家。

基本 TTS

基本 TTS 是最常見的文字轉語音形式,其中人工語音無論玩家或環境上下文如何都會讀取文本字符串。這意味著每當玩家觸發 TTS 音頻時,單詞和人工語音讀取單詞的方式將保持一致,無論玩家的狀態、行為或環境狀態如何。

這種形式的 TTS 在大多數遊戲場景中都很有用,例如玩家與 UI 菜單、教程或常規 NPC 互動(如商販提供或敵人吼叫)。Roblox 提供以下類型的語音,您可以在這些互動中進行實驗:

VoiceID語音描述音頻示例
1英國男性
2英國女性
3美國男性 #1
4美國女性 #1
5美國男性 #2
6美國女性 #2
7澳大利亞男性
8澳大利亞女性
9復古語音 #1
10復古語音 #2
11主持人語音
101西班牙男性
102西班牙女性
201德國男性
202德國女性
301意大利男性
302意大利女性
401法國男性
402法國女性

要在示例 Gingerbread House - Text-to-Speech 地方文件中重建基本的 3D TTS 音頻:

  1. 啟用附加到玩家角色的默認聽者。
    1. Explorer 窗口中,選擇 SoundService
    2. Properties 窗口中,將 DefaultListenerLocation 設置為 Character。當您運行遊戲時,引擎會自動:
      • 在每個玩家角色的 Humanoid.RootPart 下創建一個 AudioListener,這樣您就可以根據遊戲中聲音源的位置和音量在現實世界的揚聲器中聽到聲音的變化。
      • SoundService 下創建一個 AudioDeviceOutput
  2. Explorer 窗口中,導航到 WorkspaceDialogueVolume,然後:
    1. 插入一個 AudioTextToSpeech 對象,以創建圍繞雪人的音頻語音生成器。
    2. 插入一個 AudioEmitter 對象,以從 DialogueVolume 發射位置流。
    3. 插入一個 Wire 對象,以將流從音頻語音生成器傳輸到音頻發射器。
  3. 選擇 AudioTextToSpeech 對象,然後在 Properties 窗口中:
    1. Text 設置為 "收集每一個糖果才能打開我的家!"
    2. VoiceId 設置為 2,以將人工語音設置為模仿英國女性。
    3. Volume 設置為 3,以便在遊戲中播放音頻時,您能夠聽到 TTS 聲音超過其他音頻源。
  4. 選擇 Wire,然後在 Properties 窗口中:
    1. SourceInstance 設置為您的新 AudioTextToSpeech,以指定您希望電線從這個特定的音頻語音生成器傳輸音頻。
    2. TargetInstance 設置為您的新 AudioEmitter,以指定您希望電線將音頻傳輸到這個特定的音頻發射器內。
  5. 返回 Explorer 窗口,導航到 StarterPlayerStarterCharacterScripts,然後插入一個 LocalScript,將其重命名為 PlayBasicTTSAudioWhenInVolume,並將以下代碼粘貼到本地腳本中:
local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")
local humanoid = script.Parent:WaitForChild("Humanoid")
local volumeDetector = Workspace.DialogueVolume
local trigger = humanoid:WaitForChild("Animator")
local debounce = false
local localPlayer = Players.LocalPlayer
volumeDetector.Touched:Connect(function(hit)
if debounce then
return
end
local hitCharacter = hit:FindFirstAncestorWhichIsA("Model")
local hitPlayer = Players:GetPlayerFromCharacter(hitCharacter)
if hitPlayer ~= localPlayer then
return
end
debounce = true
local audioTextToSpeech = Workspace.DialogueVolume.AudioTextToSpeech
audioTextToSpeech:Play()
audioTextToSpeech.Ended:Wait()
debounce = false
end)

此腳本首先獲取 WorkspacePlayers 服務,以便引用它們的子項和功能。對於每個加載或重生回到遊戲中的玩家角色,腳本會等待:

  • 角色的 HumanoidAnimator 對象。
  • 工作區中名為 DialogueVolume 的音量對象。

當任何物體與音量發生碰撞時,Touched 事件處理函數獲取第一個祖先,該祖先是 Model,如果與音量碰撞的 BasePart 是角色模型的子項,則應該是角色。如果是,則函數將:

  • 將 debounce 設置為 true
  • 播放並等待 TTS 音頻結束。
  • 將 debounce 設置回 false

將 debounce 從 false 設置為 true,然後在基本 TTS 音頻播放結束後再次設置為 false 是一種防抖模式,可以防止音頻在玩家不斷與音量碰撞時重複觸發。欲了解有關此防抖模式的更多信息,請參見 防抖 - 檢測碰撞

  1. 測試遊戲,以便在您的玩家角色觸摸雪人周圍的音量時聽到指導角色對話。

您可以通過修改 TextVoiceIDPitchSpeed 屬性為新值來進一步實驗此音頻。生成的語音變得完全不同,而無需為每個場景錄製和上傳新的音頻文件。

上下文感知 TTS

上下文感知 TTS 是一種更高級的文字轉語音形式,其中人工語音根據玩家、環境狀態或遊戲狀態讀取文本字符串。這意味著每當玩家觸發 TTS 音頻時,單詞和人工語音讀取單詞的方式會相應地調整。

這種形式的 TTS 對於不斷變化的遊戲場景非常有用,例如方向音頻提示、目標狀態或獨特的 NPC 互動。因此,由於上下文感知 TTS 需要轉換以保持準確性,您必須配置遊戲元素,以便在玩家在環境中導航並完成遊戲目標時跟踪其狀態。

雖然有許多方法可以完成此任務,但示例使用自定義屬性來跟踪玩家必須收集的每個糖果的 顏色位置,以便進入薑餅屋。欲了解有關屬性的更多信息,請參見 屬性和屬性


每個糖果對象都有描述其顏色和環境中位置的屬性。
黃色糖果的特寫
綠色糖果的特寫
紅色糖果的特寫

要在示例 Gingerbread House - Text-to-Speech 地方文件中重建上下文感知的 3D TTS 音頻:

  1. Explorer 窗口中,導航到 WorkspaceGumDrops

  2. 配置三個自定義屬性以跟踪黃色糖果。

    1. 選擇黃色糖果,然後在 Properties 窗口中,導航到 Attributes 部分,然後單擊加號圖標。彈出對話框顯示。
    2. Name 欄中,輸入 ColorDescription
    3. Type 下拉菜單中,選擇 string
    4. 單擊 Save 按鈕。
    5. 將新的 ColorDescription 屬性設置為 yellow
    6. 使用此過程,創建另外兩個屬性,使用以下值。
    名稱類型
    HintOrdernumber0
    LocationDescriptionstring在瀑布旁邊
  3. 配置三個自定義屬性以跟踪綠色糖果。

    1. Explorer 窗口中,選擇綠色糖果。
    2. Properties 窗口中,使用以下值創建三個屬性。
    名稱類型
    ColorDescriptionstringgreen
    HintOrdernumber1
    LocationDescriptionstring在邊緣上
  4. 配置三個自定義屬性以跟踪紅色糖果。

    1. Explorer 窗口中,選擇紅色糖果。
    2. Properties 窗口中,使用以下值創建三個屬性。
    名稱類型
    ColorDescriptionstringred
    HintOrdernumber2
    LocationDescriptionstring在圍欄後面
  5. Explorer 窗口中,導航到 WorkspaceHintVolume,然後:

    1. 插入一個 AudioTextToSpeech 對象,以創建圍繞馴鹿的音頻語音生成器。
    2. 插入一個 AudioEmitter 對象,以從 HintVolume 發射位置流。
    3. 插入一個 Wire 對象,以將流從音頻語音生成器傳輸到音頻發射器。
  6. 選擇 Wire,然後在 Properties 窗口中:

    1. SourceInstance 設置為您的新 AudioTextToSpeech,以指定您希望電線從這個特定的音頻語音生成器傳輸音頻。
    2. TargetInstance 設置為您的新 AudioEmitter,以指定您希望電線將音頻傳輸到這個特定的音頻發射器內。
  7. 返回 Explorer 窗口,導航到 StarterPlayerStarterCharacterScripts,然後插入一個 LocalScript,將其重命名為 PlayContextTTSAudioWhenInVolume,並將以下代碼粘貼到本地腳本中:

local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")
local humanoid = script.Parent:WaitForChild("Humanoid")
local volumeDetector = Workspace.HintVolume
local trigger = humanoid:WaitForChild("Animator")
local debounce = false
local localPlayer = Players.LocalPlayer
function getRemainingGumdrops(): {Part}
local gumdropsFolder = Workspace.Gumdrops
local gumdrops = gumdropsFolder:GetChildren()
local remainingGumdrops = {};
for _, gumdrop in gumdrops do
if gumdrop:GetAttribute("Active") then
remainingGumdrops[#remainingGumdrops + 1] = gumdrop
end
end
table.sort(remainingGumdrops, function(a, b)
return a:GetAttribute("HintOrder") < b:GetAttribute("HintOrder")
end)
return remainingGumdrops
end
function getReindeerHint(remainingGumdrops: {Part}): string
local remainingGumdrops = getRemainingGumdrops()
if (#remainingGumdrops == 0) then
return "沒有剩下的糖果。檢查房子裡。"
end
local nextGumdrop = remainingGumdrops[1]
local colorDescription = nextGumdrop:GetAttribute("ColorDescription")
local locationDescription = nextGumdrop:GetAttribute("LocationDescription")
local message = #remainingGumdrops > 1
and "還有 " .. #remainingGumdrops .. " 顆糖果。尋找 " .. colorDescription .. " 的糖果 " .. locationDescription .. "。"
or "還剩一顆糖果。它是 " .. colorDescription .. ",在 " .. locationDescription .. "。"
return message
end
volumeDetector.Touched:Connect(function(hit)
if debounce then
return
end
local hitCharacter = hit:FindFirstAncestorWhichIsA("Model")
local hitPlayer = Players:GetPlayerFromCharacter(hitCharacter)
if hitPlayer ~= localPlayer then
return
end
print("玩家觸摸了音量。")
debounce = true
local remainingGumdrops = getRemainingGumdrops()
local message = getReindeerHint(remainingGumdrops)
local audioTextToSpeech = Workspace.HintVolume.AudioTextToSpeech
audioTextToSpeech.Text = message
audioTextToSpeech:Play()
audioTextToSpeech.Ended:Wait()
debounce = false
end)

此腳本首先獲取 WorkspacePlayers 服務,以便引用它們的子項和功能。對於每個加載或重生回到遊戲中的玩家角色,腳本會等待:

  • 角色的 HumanoidAnimator 對象。
  • 工作區中名為 HintVolume 的音量對象。

腳本的 getRemainingGumdrops() 函數返回 Gumdrops 文件夾中糖果 Part 對象的列表,並過濾掉玩家已收集的任何部件。剩餘的糖果根據每個糖果的 HintOrder 屬性進行排序。

腳本的 getReindeerHint(remainingGumdrops) 函數從 getRemainingGumdrops() 返回的列表中返回一個字符串消息,描述玩家可以在哪裡找到剩餘的糖果,包括玩家需要收集的下一顆糖果的顏色和位置描述。然而,如果玩家已經收集了環境中的所有糖果,字符串消息將描述在收集完所有糖果後下一步該去哪裡。

當任何物體與音量發生碰撞時,Touched 事件處理函數獲取第一個祖先,該祖先是 Model,如果與音量碰撞的 BasePart 是角色模型的子項,則應該是角色。如果是,則函數將:

  • 將 debounce 設置為 true
  • 獲取剩餘糖果的列表和描述玩家需要找到的下一顆糖果的字符串消息。
  • 使用 AudioTextToSpeech 對象將字符串轉換為音頻,播放音頻並等待音頻結束。
  • 將 debounce 設置回 false

將 debounce 從 false 設置為 true,然後在上下文感知 TTS 音頻播放結束後再次設置為 false 是一種防抖模式,可以防止音頻在玩家不斷與音量碰撞時重複觸發。欲了解有關此防抖模式的更多信息,請參見 防抖 - 檢測碰撞

  1. 測試遊戲,以便在您的玩家角色觸摸馴鹿周圍的音量時聽到上下文提示。TTS 音頻根據玩家角色在環境中已經找到的糖果的數量和顏色而變化。

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