1.ロブロックスText-to-Speech APIとは?(TTS)
RobloxのTTSとは、テキストをリアルタイムで音声に変換して再生できる公式APIが正式リリースです。
難しそうな横文字はおいといて、とにかく言葉をNPCなどが音声として言葉を発生させるのに簡単に拵えることのできるシステムが正式に公開されました。
ベータと違い制限が大幅に緩和され実用的な運用が可能になり、イベントやNPC会話を常用できる水準になりました。
録音や外部編集をしなくても、ゲーム内で台詞を差し替えるだけで今日の告知などを音声で流せます。
コードで生成→すぐ再生。チュートリアルや日替わりヒント、ダイナミックなNPC台詞に最適。
今までテキストとしての表示しかできなかったのが一変します。
注意点として、現在英語にしか対応しておらず、仮に文言を日本語にしたり、ローマ字でも反応せず音声出力しません。
2. NPCがしゃべるクイックスタート(コピペOK):近プロ→吹き出し付き
スタジオでも試せるようにコードを用意しました。
お試し用とは言え、チュートリアルの案内ぐらいなら実用的かと思います。
近接プロンプトをトリガーとしたシステムです。
NPCの任意の場所に近接プロンプトを設置。
以下のコードをLocalScriptとしてStarterPlayerScriptsに配置。
任意の文言をコードに書き込めば音声でも喋り、吹き出しもでてくる作りにしました。
👉 ここをクリックしてコードを表示
-- NPCが一言しゃべる
-- 音声の種類はVOICE_IDで1から10のどれかを配置
local Players = game:GetService("Players")
local ProximityPromptService = game:GetService("ProximityPromptService")
local TextChatService = game:GetService("TextChatService")
-- ===== 表示/音声設定 =====
local DIALOG_EN = "Welcome! This is Roblok Village."
local VOICE_ID = "9" -- "1"〜"10"
local BUBBLE_DURATION_SEC= 8.0 -- ★ 吹き出しの表示秒数
local COOLDOWN_SEC = 2.0 -- 連打抑制
local TALK_TIMEOUT_SEC = 20.0 -- 取り逃し用の最大片付けタイムアウト
-- ========================
-- 起動時にバブル設定(クライアントのみ影響)
do
local cfg = TextChatService:FindFirstChildOfClass("BubbleChatConfiguration")
if not cfg then
cfg = Instance.new("BubbleChatConfiguration")
cfg.Parent = TextChatService
end
cfg.BubbleDuration = BUBBLE_DURATION_SEC
-- 必要なら下も調整可能(コメント解除して使う)
-- cfg.MaxBubbles = 1
-- cfg.MaxDistance = 100
-- cfg.TailVisible = true
end
-- 出力デバイスを使い回し
local deviceOutput: AudioDeviceOutput?
local function getDeviceOutput(): AudioDeviceOutput
if deviceOutput and deviceOutput.Parent then return deviceOutput end
local out = Instance.new("AudioDeviceOutput")
out.Name = "LocalDeviceOutput"
out.Parent = workspace
deviceOutput = out
return out
end
-- 吹き出しの付け先(Head優先)
local function pickChatPart(model: Model): BasePart?
if model.PrimaryPart and model.PrimaryPart:IsA("BasePart") then return model.PrimaryPart end
local head = model:FindFirstChild("Head")
if head and head:IsA("BasePart") then return head end
for _, d in ipairs(model:GetDescendants()) do
if d:IsA("BasePart") then return d end
end
return nil
end
-- 失敗時のASCII保険
local function asciiFallback(s: string): string
local cleaned = s:gsub("[^%w%p%s]", " ")
cleaned = cleaned:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
return cleaned ~= "" and cleaned or "Hello there!"
end
-- 安全な片付け
local function safeCleanup(tts: Instance?, wire: Instance?)
if wire and wire.Parent then pcall(function() wire:Destroy() end) end
if tts and tts.Parent then pcall(function() tts:Destroy() end) end
end
-- TTS(ピッチ/速度変更なし、喋りきりで片付け)
local function speakTTS(textForTTS: string)
local tts = Instance.new("AudioTextToSpeech")
tts.Name = "NPC_TTS"
tts.Text = textForTTS
tts.VoiceId = VOICE_ID
tts.Parent = workspace
local out = getDeviceOutput()
local wire = Instance.new("Wire")
wire.SourceInstance = tts
wire.TargetInstance = out
wire.Parent = workspace
local snd: Sound? = tts:FindFirstChildOfClass("Sound")
if snd then
local endedConn: RBXScriptConnection? = nil
endedConn = snd.Ended:Connect(function()
if endedConn then endedConn:Disconnect() end
safeCleanup(tts, wire)
end)
task.delay(TALK_TIMEOUT_SEC, function()
if tts and tts.Parent then
if endedConn then endedConn:Disconnect() end
safeCleanup(tts, wire)
end
end)
snd:Play()
else
-- 実装差保険
if (tts :: any).Play then
(tts :: any):Play()
elseif (tts :: any).SpeakAsync then
(tts :: any):SpeakAsync()
end
task.delay(TALK_TIMEOUT_SEC, function()
safeCleanup(tts, wire)
end)
end
end
-- 失敗時フォールバック(ASCII化)
local function safeSpeak(text: string)
local ok = pcall(function() speakTTS(text) end)
if ok then return end
speakTTS(asciiFallback(text))
end
-- 近プロの連打クールダウン
local cooldownUntilByPrompt: { [Instance]: number } = {}
ProximityPromptService.PromptTriggered:Connect(function(prompt: ProximityPrompt, who: Player)
if who ~= Players.LocalPlayer then return end
local npc = prompt:FindFirstAncestorOfClass("Model")
if not npc then return end
if who.Character and npc == who.Character then return end
local now = os.clock()
local untilTs = cooldownUntilByPrompt[prompt] or 0
if now < untilTs then return end
cooldownUntilByPrompt[prompt] = now + COOLDOWN_SEC
local part = pickChatPart(npc)
if not part then return end
-- 英語の吹き出し(表示8秒)
TextChatService:DisplayBubble(part, DIALOG_EN)
-- 英語のTTS
safeSpeak(DIALOG_EN)
end)
チュートリアルやショップなどの案内で活用が可能です。
簡単に設置できますので試しに使ってみてください。
3. 声の種類と選び方
初期で複数のVoiceIdが用意されています。
男女・アクセント違いなどがあり、好みや雰囲気で使い分けよう。
方法としてはコード内のVoiceIdを変更するだけでok。
今の所は10種類の英語のみ。今後、より多くの種類が展開予定されています。日本語にも対応した声もすぐできるのではと思います。
- 案内役:落ち着いた男女は1から8で奇数が男性、偶数が女性。これは好みになります。
- ロボット音声:ID9と10は独特なロボット音声です。個人的に10が好みです。
- 文字数上限:一発で長く読ませない。短い台詞の連結で演出がおすすめ。
コツ:短文構成&句読点で区切ると自然。長文は2〜3文に分け、スペースを挟むと聞き取りやすいです。
4. 音声出力の実装パターン(発展系)
あなたのアイデア次第で色々な方法で提示が可能です。
楽しみながら試してみよう。
- 会話型NPC(選択肢つき)
選択肢ボタン→選んだテキストをTTS。選択肢ごとに短い音声でテンポUP。 - 全体アナウンス
ラウンド開始・ボス出現・注意喚起をサーバーから各クライアントで発信。 - チュートリアル&アクセシビリティ
重要UIに読み上げボタンを付け、視覚に頼らない導線を用意。 - ツイート型
モジュールスクリプトにセリフを配置してランダムで読み上げ。


画像では分かりませんが、音声を発しています。
5. つまずきやすいQ&A
Q. すべての言語に対応?
A. 現状は英語のみ。今後拡張予定で言語や種類も増えていく流れ。
Q. 不適切ワードは?
A. ガイドラインに反するテキストは生成されない/エラーに。入力テキストは自前のフィルタでも事前検査を。
Q. 他の人が実行するたびに音が聞こえる?
A.基本はローカル運用がされており他の人の実行は届かない。
今まで文字のみだったものが音でも聞けるようになったので幅広い年齢層にもチュートリアルなどで訴求が可能になってきました。
まだ英語のみなので日本語としてはこれからというところですが、大きな一歩かなと思います。
ぜひ自分のゲームにも取り入れて運用してみよう!
合わせて読みたい
プライバシーや制限
– お子様が安心してご利用するための設定
– 子供が勝手に課金をしない為に
– ロブロックスのギフトカードを贈ろう
– 嫌がらせ行為があった場合の報告
設定や操作方法
用語集
– obby(オビー)とは
– tycoon(タイクーン)とは
– story(ストーリー)とは
アバター
– Roblox[コレクタブル]アイテムとは/リミッテッドやUの意味
– プロフィール画像にポーズをつけよう
ロブロックススタジオ(ゲーム制作)