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. 音声出力の実装パターン(発展系)

あなたのアイデア次第で色々な方法で提示が可能です。
楽しみながら試してみよう。

  1. 会話型NPC(選択肢つき)
    選択肢ボタン→選んだテキストをTTS。選択肢ごとに短い音声でテンポUP。
  2. 全体アナウンス
    ラウンド開始・ボス出現・注意喚起をサーバーから各クライアントで発信。
  3. チュートリアル&アクセシビリティ
    重要UIに読み上げボタンを付け、視覚に頼らない導線を用意。
  4. ツイート型
    モジュールスクリプトにセリフを配置してランダムで読み上げ。

画像では分かりませんが、音声を発しています。


5. つまずきやすいQ&A


Q. すべての言語に対応?
A. 現状は英語のみ。今後拡張予定で言語や種類も増えていく流れ。
Q. 不適切ワードは?
A. ガイドラインに反するテキストは生成されない/エラーに。入力テキストは自前のフィルタでも事前検査を。
Q. 他の人が実行するたびに音が聞こえる?
A.基本はローカル運用がされており他の人の実行は届かない。


今まで文字のみだったものが音でも聞けるようになったので幅広い年齢層にもチュートリアルなどで訴求が可能になってきました。
まだ英語のみなので日本語としてはこれからというところですが、大きな一歩かなと思います。
ぜひ自分のゲームにも取り入れて運用してみよう!


合わせて読みたい

プライバシーや制限

– お子様が安心してご利用するための設定

– 子供が勝手に課金をしない為に

– ロブロックスのギフトカードを贈ろう

– 嫌がらせ行為があった場合の報告


設定や操作方法

– ゲームの操作方法

– アバターの設定、変更方法

– Robloxゲーム言語設定

– フレンドが遊んでいるゲームに参加する方法

用語集

– obby(オビー)とは

– tycoon(タイクーン)とは

– story(ストーリー)とは

– フリーUGCとは

– Noob(ヌーブ)とは

アバター

– ROBLOX アバターウェア&アイテム

– Roblox[コレクタブル]アイテムとは/リミッテッドやUの意味

– ROBLOXオリジナルアイテムをゲットできるゲーム集

– アバターアイテムをえらぶ

– プロフィール画像にポーズをつけよう

ロブロックススタジオ(ゲーム制作)

– ロブロックスアバターに着せるTシャツや服の作り方

– ロブロックスのTシャツや服の公開、販売の方法

【AIで自作】Robloxで3Dアクセサリを販売する方法

エモートの作成方法と販売方法

ロブロックス公式案内