テキスト読み上げは、テキスト文字列を人工音声を使用して音声に変換する支援技術の一形態です。視覚、運動、または認知障害を持つプレイヤーにとってゲームのアクセシビリティを向上させるだけでなく、TTSを使用することで、すべての可能な物語のシナリオのために音声を事前に録音する必要がなく、動的に音声を生成することができます。
Gingerbread House - Start .rbxlファイルを出発点として、Gingerbread House - Text-to-Speechを参照しながら、このチュートリアルでは、基本的なTTS音声とコンテキストに応じたTTS音声をゲームに追加する方法を示します。以下のガイダンスが含まれています:
- UIの操作やチュートリアルなど、決して変わらない一般的なゲームプレイシナリオのためにTTSをトリガーする方法。
- プレイヤーの行動、環境の状態、または柔軟な目標に適応するようにTTSを構成する方法。
プロセスのどの時点でも行き詰まった場合は、Gingerbread House - Text-to-Speechを参照して進捗を比較できます。
音声オブジェクト
TTS音声を作成するには、このチュートリアル全体で使用する音声オブジェクトを理解することが重要です。TTS用の音声オブジェクトには5つの主要なタイプがあります:
- AudioTextToSpeechオブジェクトは、テキスト文字列を音声に変換します。
- AudioEmitterオブジェクトは、3D環境に音声を発信する仮想スピーカーです。
- AudioListenerオブジェクトは、3D環境から音声を拾う仮想マイクです。
- AudioDeviceOutputオブジェクトは、スピーカーやヘッドフォンなど、現実世界の物理ハードウェアデバイスです。
- Wiresは、音声ストリームをあるオブジェクトから別のオブジェクトに運びます。
これらの音声オブジェクトはすべて、プレイヤーの行動に応じてTTS音声を発信するために連携して機能します。プレイヤーがヘッドセットを装着してラップトップでゲームをプレイしている例を用いて、これが実際にどのように機能するか見てみましょう:
- AudioTextToSpeechは、プレイヤーが非プレイ可能キャラクター(NPC)の近くのパートに触れるたびにテキストを音声に読み込み、変換します。
- AudioEmitterは、NPCから3D環境にTTS音声のストリームを発信します。
- キャラクターの子であるAudioListenerオブジェクトは、その音を3D環境内で聞き取り、ヘッドセットにフィードバックします。
- AudioDeviceOutputオブジェクトは、AudioListenerからプレイヤーの物理スピーカー、またはこの場合はヘッドフォンに音を運びます。
以下のセクションでは、これらのオブジェクトをより深く掘り下げ、基本的な音声とコンテキストに応じた音声の再生方法を学びます。これらのオブジェクトを今後の技術と共にレビューすることで、ゲームからプレイヤーへの音のキャプチャとフィードバックの方法をより正確に予測できるようになります。
基本的な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音声を再現するには:
- プレイヤーキャラクターに接続されたデフォルトリスナーを有効にします。
- Explorerウィンドウで、SoundServiceを選択します。
- Propertiesウィンドウで、DefaultListenerLocationをCharacterに設定します。ゲームを実行すると、エンジンは自動的に:
- 各プレイヤーキャラクターのHumanoid.RootPartの下にAudioListenerを作成し、ゲーム内の音源の位置とスケールに応じて、実際のスピーカーから音が移動するのを聞くことができます。
- SoundServiceの下にAudioDeviceOutputを作成します。
- Explorerウィンドウで、Workspace ⟩ DialogueVolumeに移動し、次に:
- AudioTextToSpeechオブジェクトを挿入して、雪だるまの周りの音声生成器を作成します。
- AudioEmitterオブジェクトを挿入して、DialogueVolumeから位置ストリームを発信します。
- 音声生成器から音声エミッターにストリームを運ぶためにWireオブジェクトを挿入します。
- AudioTextToSpeechオブジェクトを選択し、次にPropertiesウィンドウで:
- Textを「Collect every single last gumpdrop to open my home!」に設定します。
- VoiceIdを2に設定して、人工音声をイギリス女性の声にエミュレートします。
- Volumeを3に設定して、ゲーム内の他の音声ソースの上でTTS音声が聞こえるように高音量で再生します。
- Wireを選択し、次にPropertiesウィンドウで:
- SourceInstanceを新しいAudioTextToSpeechに設定して、この特定の音声生成器から音声を運ぶようにワイヤーを指定します。
- TargetInstanceを新しいAudioEmitterに設定して、この特定の音声エミッターに音声を運ぶようにワイヤーを指定します。
- Explorerウィンドウに戻り、StarterPlayer ⟩ StarterCharacterScriptsに移動し、次に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)このスクリプトは、WorkspaceとPlayersサービスを取得して、子供や機能を参照できるようにします。ゲームにロードまたは再出現する各プレイヤーキャラクターについて、スクリプトは以下を待ちます:
- ワークスペース内のDialogueVolumeという名前のボリュームオブジェクト。
ボリュームに何かが衝突すると、Touchedイベントハンドラ関数は、衝突したBasePartがキャラクターモデルの子孫である場合、最初の祖先をModelとして取得します。もしそうであれば、関数は次のようにします:
- デバウンスをtrueに設定します。
- TTS音声を再生し、終了するのを待ちます。
- デバウンスをfalseに戻します。
デバウンスをfalseからtrueに、再生が終了した後に再びfalseに戻すことは、プレイヤーがボリュームに継続的に衝突する際に音声が繰り返しトリガーされるのを防ぐデバウンスパターンです。このデバウンスパターンの詳細については、デバウンス - 衝突を検出するを参照してください。
ゲームをプレイテストして、プレイヤーキャラクターが雪だるまの周りのボリュームに触れたときに指示キャラクターのダイアログを聞きます。
Text、VoiceID、Pitch、およびSpeedプロパティを新しい値に変更することで、この音声をさらに実験できます。生成された音声は、各シナリオのために新しい音声ファイルを録音してアップロードする必要なく、まったく異なるものになります。
コンテキストに応じたTTS
コンテキストに応じたTTSは、プレイヤー、環境の状態、またはゲームプレイの状態に関連してテキスト文字列を読み上げる、より高度な形式のテキスト読み上げです。これは、プレイヤーがTTS音声をトリガーするたびに、言葉と人工音声が言葉を読み上げる方法がそれに応じて適応することを意味します。
この形式のTTSは、方向音声の合図、目標の状態、またはユニークなNPCとのインタラクションなど、常に変化するゲームプレイシナリオに役立ちます。したがって、コンテキストに応じたTTSが正確であるためには、プレイヤーが環境を移動し、ゲームプレイの目標を達成する際にその状態を追跡できるように、ゲームプレイ要素を構成する必要があります。
このタスクを達成する方法は多くありますが、サンプルでは、プレイヤーがジンジャーブレッドハウスに入るために収集しなければならない各ガムドロップの色と位置を追跡するためにカスタム属性を使用します。属性に関する詳細は、プロパティと属性を参照してください。



サンプルのGingerbread House - Text-to-Speechプレースファイルでコンテキストに応じた3D TTS音声を再現するには:
Explorerウィンドウで、Workspace ⟩ GumDropsに移動します。
黄色のガムドロップを追跡するために3つのカスタム属性を構成します。
- 黄色のガムドロップを選択し、PropertiesウィンドウでAttributesセクションに移動し、プラスアイコンをクリックします。ポップアップダイアログが表示されます。
- NameフィールドにColorDescriptionを入力します。
- Typeドロップダウンメニューでstringを選択します。
- Saveボタンをクリックします。
- 新しいColorDescription属性をyellowに設定します。
- このプロセスを使用して、以下の値を使用してさらに2つの属性を作成します。
名前 タイプ 値 HintOrder number 0 LocationDescription string 滝のそば 緑のガムドロップを追跡するために3つのカスタム属性を構成します。
- Explorerウィンドウで、緑のガムドロップを選択します。
- Propertiesウィンドウで、以下の値を使用して3つの属性を作成します。
名前 タイプ 値 ColorDescription string green HintOrder number 1 LocationDescription string ledgeの上 赤のガムドロップを追跡するために3つのカスタム属性を構成します。
- Explorerウィンドウで、赤のガムドロップを選択します。
- Propertiesウィンドウで、以下の値を使用して3つの属性を作成します。
名前 タイプ 値 ColorDescription string red HintOrder number 2 LocationDescription string フェンスの後ろ Explorerウィンドウで、Workspace ⟩ HintVolumeに移動し、次に:
- AudioTextToSpeechオブジェクトを挿入して、トナカイの周りの音声生成器を作成します。
- AudioEmitterオブジェクトを挿入して、HintVolumeから位置ストリームを発信します。
- 音声生成器から音声エミッターにストリームを運ぶためにWireオブジェクトを挿入します。
Wireを選択し、次にPropertiesウィンドウで:
- SourceInstanceを新しいAudioTextToSpeechに設定して、この特定の音声生成器から音声を運ぶようにワイヤーを指定します。
- TargetInstanceを新しいAudioEmitterに設定して、この特定の音声エミッターに音声を運ぶようにワイヤーを指定します。
Explorerウィンドウに戻り、StarterPlayer ⟩ StarterCharacterScriptsに移動し、次に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 "残りのガムドロップは1個です。それは" .. 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)このスクリプトは、WorkspaceとPlayersサービスを取得して、子供や機能を参照できるようにします。ゲームにロードまたは再出現する各プレイヤーキャラクターについて、スクリプトは以下を待ちます:
- ワークスペース内のHintVolumeという名前のボリュームオブジェクト。
スクリプトのgetRemainingGumdrops()関数は、Gumdropsフォルダー内のガムドロップPartオブジェクトのリストを返し、プレイヤーが収集したパートをフィルタリングします。残りのガムドロップは、各ガムドロップのHintOrder属性に従って特定の順序でソートされます。
スクリプトのgetReindeerHint(remainingGumdrops)関数は、getRemainingGumdrops()からのリストを受け取り、プレイヤーが見つける必要がある残りのガムドロップの色と位置の説明を含む文字列メッセージを返します。ただし、プレイヤーが環境内のすべてのガムドロップを収集した場合、文字列メッセージは、環境内のすべてのガムドロップを収集した後に次に行くべき場所を説明します。
ボリュームに何かが衝突すると、Touchedイベントハンドラ関数は、衝突したBasePartがキャラクターモデルの子孫である場合、最初の祖先をModelとして取得します。もしそうであれば、関数は次のようにします:
- デバウンスをtrueに設定します。
- 残りのガムドロップのリストと、プレイヤーが見つける必要がある次のガムドロップを説明する文字列メッセージを取得します。
- 文字列をAudioTextToSpeechオブジェクトを使用して音声に変換し、音声を再生し、音声が終了するのを待ちます。
- デバウンスをfalseに戻します。
デバウンスをfalseからtrueに、コンテキストに応じたTTS音声の再生が終了した後に再びfalseに戻すことは、プレイヤーがボリュームに継続的に衝突する際に音声が繰り返しトリガーされるのを防ぐデバウンスパターンです。このデバウンスパターンの詳細については、デバウンス - 衝突を検出するを参照してください。
ゲームをプレイテストして、プレイヤーキャラクターがトナカイの周りのボリュームに触れたときにコンテキストに応じたヒントを聞きます。TTS音声は、プレイヤーキャラクターがすでに環境内で見つけたガムドロップの数と色に応じて変化します。