시작하기
중급 튜토리얼

텍스트 음성 변환 추가하기

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

**텍스트 음성 변환(TTS)**은 텍스트 문자열을 인공 음성을 사용하여 음성 소리로 변환하는 보조 기술의 한 형태입니다. 이는 시각, 이동성 또는 인지 장애가 있는 플레이어의 경험 접근성을 향상시키는 것 외에도 TTS를 사용하여 모든 가능한 서사 시나리오에 대한 오디오를 미리 녹음할 필요 없이 동적으로 음성을 생성할 수 있게 해줍니다.

Gingerbread House - Start .rbxl 파일을 시작점으로 하고 Gingerbread House - Text-to-Speech을 참조하여, 이 튜토리얼에서는 기본 및 상황 인식 TTS 오디오를 경험에 추가하는 방법을 보여줍니다. 여기에는 다음에 대한 지침이 포함됩니다:

  • UI 상호작용 및 튜토리얼과 같이 절대 변하지 않는 일반 게임 플레이 시나리오에 대한 TTS 트리거하기
  • 플레이어 행동, 환경 상태 또는 유연한 목표에 적응하도록 TTS 구성하기

과정 중 어느 시점에서든 막히게 된다면, Gingerbread House - Text-to-Speech를 참조하여 진행 상황을 비교할 수 있습니다.

오디오 객체

TTS 오디오를 생성하기 위해서는 이 튜토리얼 전반에 걸쳐 작업하게 될 오디오 객체를 이해하는 것이 중요합니다. TTS를 위한 주요 오디오 객체는 다음과 같이 다섯 가지입니다:

  • AudioTextToSpeech 객체는 텍스트 문자열을 음성 소리로 변환합니다.
  • AudioEmitter 객체는 3D 환경에서 오디오를 방출하는 가상 스피커입니다.
  • AudioListener 객체는 3D 환경에서 오디오를 수신하는 가상 마이크입니다.
  • AudioDeviceOutput 객체는 스피커나 헤드폰과 같은 실제 세계의 물리적 하드웨어 장치입니다.
  • Wires는 오디오 스트림을 한 객체에서 다른 객체로 전달합니다.

이 모든 오디오 객체는 플레이어 행동에 따라 TTS 소리를 방출하기 위해 함께 작용합니다. 다음은 헤드셋을 착용한 플레이어가 노트북으로 경험을 플레이할 때의 3D 오디오 작동 방식의 예입니다:

  • AudioTextToSpeech는 플레이어가 비 playable 캐릭터(NPC) 근처의 파트를 터치할 때마다 텍스트를 로드하고 음성으로 변환합니다.
  • AudioEmitter는 NPC에서 3D 환경으로 TTS 오디오의 스트림을 방출합니다.
  • WireAudioTextToSpeech에서 AudioEmitter까지 스트림을 전달하여 NPC에서 소리가 출력되도록 합니다.
  • 캐릭터의 자식 AudioListener 객체는 3D 환경 내에서 해당 소리를 듣고 이를 헤드셋으로 피드백합니다.
  • AudioDeviceOutput 객체는 AudioListener에서 플레이어의 물리적 스피커 또는 현재의 경우 헤드폰으로 소리를 전달합니다.

다음 섹션에서는 이러한 객체를 자세히 설명하고 기본 및 상황 인식 오디오 재생 방법을 배웁니다. 향후 기술과 함께 이러한 객체를 검토함으로써 경험에서 플레이어에게 소리를 캡처하고 전달하는 방식을 보다 정확하게 예측할 수 있습니다.

기본 TTS

기본 TTS는 인공 음성이 플레이어나 환경의 맥락에 관계없이 텍스트 문자열을 읽는 가장 일반적인 형태의 텍스트 음성 변환입니다. 즉, 플레이어가 TTS 오디오를 트리거할 때마다 단어와 인공 음성이 단어를 읽는 방식은 플레이어의 상태, 행동 또는 환경 상태와 관계없이 일관되게 유지됩니다.

이 형태의 TTS는 주로 플레이어가 UI 메뉴, 튜토리얼 또는 상점 제안이나 적의 외침과 같은 일상적인 NPC 상호작용을 포함할 때 유용합니다. Roblox는 다음과 같은 여러 가지 음성을 제공하여 이러한 상호작용을 위해 실험할 수 있습니다:

VoiceIDVoice DescriptionAudio Example
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 창에서 DefaultListenerLocationCharacter로 설정합니다. 경험을 실행하면, 엔진이 자동으로:
      • 각 플레이어 캐릭터의 Humanoid.RootPart 아래에 AudioListener를 생성하여 소리가 소스의 위치와 크기에 따라 실제 스피커에서 이동하도록 합니다.
      • SoundService 아래에 AudioDeviceOutput을 생성합니다.
  2. Explorer 창에서 WorkspaceDialogueVolume으로 이동한 후:
    1. AudioTextToSpeech 객체를 삽입하여 눈사람 주변의 오디오 스피치 생성기를 만듭니다.
    2. AudioEmitter 객체를 삽입하여 DialogueVolume에서 위치 기반 스트림을 방출합니다.
    3. Wire 객체를 삽입하여 오디오 스피치 생성기에서 오디오 이머터로 스트림을 전송합니다.
  3. AudioTextToSpeech 객체를 선택한 후 Properties 창에서:
    1. Text를 "Collect every single last gumpdrop to open my home!"로 설정합니다.
    2. 인공 음성을 영국 여성으로 설정하기 위해 VoiceId2로 설정합니다.
    3. 오디오가 경험 내 다른 오디오 소리보다 잘 들리게 하려면 Volume3으로 설정합니다.
  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가 캐릭터 모델의 후손일 경우 캐릭터여야 합니다. 그렇다면 함수는 다음과 같은 작업을 수행합니다:

  • 디바운스를 true로 설정합니다.
  • TTS 오디오를 재생한 후 종료되기를 기다립니다.
  • 디바운스를 다시 false로 설정합니다.

기본 TTS 오디오가 재생을 마친 후 false에서 true로 다시 false로 설정하는 것은 플레이어가 볼륨과 지속적으로 충돌하는 것을 방지하는 디바운스 패턴입니다. 디바운스 패턴에 대한 추가 정보는 Debounce - Detect collisions를 참조하십시오.

  1. 경험을 플레이하여 플레이어 캐릭터가 눈사람 주변의 볼륨에 닿을 때 지침 캐릭터 대화를 듣습니다.

이 오디오는 Text, VoiceID, Pitch, Speed 속성을 새 값으로 수정하여 더욱 실험할 수 있습니다. 생성된 음성은 각 시나리오에 대해 새로운 오디오 파일을 녹음하고 업로드할 필요 없이 완전히 달라집니다.

상황 인식 TTS

상황 인식 TTS는 인공 음성이 텍스트 문자열을 플레이어, 환경의 상태 또는 게임 플레이 상태와 연관지어 읽는 보다 발전된 형태의 텍스트 음성 변환입니다. 이는 플레이어가 TTS 오디오를 트리거할 때마다 단어와 인공 음성이 단어를 읽는 방식이 그에 따라 조정됨을 의미합니다.

이 형태의 TTS는 방향성 오디오 큐, 목표 상태 또는 독특한 NPC 상호작용과 같이 언제든지 변화하는 게임 플레이 시나리오에 유용합니다. 따라서 상황 인식 TTS가 정확하게 변환되기 위해서는 플레이어가 환경을 탐색하고 게임 플레이 목표를 완료함에 따라 상태를 추적할 수 있도록 게임 플레이 요소를 구성해야 합니다.

이 작업을 수행할 수 있는 방법은 많이 있지만, 샘플은 플레이어가 수집해야 할 각 구슬의 색상위치를 추적하기 위해 사용자 정의 속성을 사용합니다. 속성에 대한 더 많은 정보는 Properties and attributes를 참조하십시오.


각 구슬 객체에는 그들의 색상과 환경에서의 위치를 설명하는 속성이 있습니다.
노란 구슬의 클로즈업 이미지
초록 구슬의 클로즈업 이미지
빨간 구슬의 클로즈업 이미지

샘플 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. 이 과정을 사용하여 다음 두 가지 값을 사용하여 추가 속성을 생성합니다.
    NameTypeValue
    HintOrdernumber0
    LocationDescriptionstring폭포 옆
  3. 초록 구슬을 추적하기 위한 세 개의 사용자 정의 속성을 구성합니다.

    1. Explorer 창에서 초록 구슬을 선택합니다.
    2. Properties 창에서 다음 값으로 세 개의 속성을 만듭니다.
    NameTypeValue
    ColorDescriptionstringgreen
    HintOrdernumber1
    LocationDescriptionstring선반 위
  4. 빨간 구슬을 추적하기 위한 세 개의 사용자 정의 속성을 구성합니다.

    1. Explorer 창에서 빨간 구슬을 선택합니다.
    2. Properties 창에서 다음 값으로 세 개의 속성을 만듭니다.
    NameTypeValue
    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 .. "개의 구슬이 남았습니다. " .. locationDescription .. "에 " .. colorDescription .. " 구슬을 찾아보세요."
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가 캐릭터 모델의 후손일 경우 캐릭터여야 합니다. 그렇다면 함수는 다음과 같은 작업을 수행합니다:

  • 디바운스를 true로 설정합니다.
  • 남은 구슬 목록과 플레이어가 찾아야 할 다음 구슬에 대한 문자열 메시지를 가져옵니다.
  • 문자열을 AudioTextToSpeech 객체를 사용하여 오디오로 변환하고, 오디오를 재생한 후 종료되기를 기다립니다.
  • 디바운스를 다시 false로 설정합니다.

상황 인식 TTS 오디오가 재생을 마친 후 false에서 true로 다시 false로 설정하는 것은 플레이어가 볼륨과 지속적으로 충돌하는 것을 방지하는 디바운스 패턴입니다. 디바운스 패턴에 대한 추가 정보는 Debounce - Detect collisions를 참조하십시오.

  1. 플레이합니다. 경험을 테스트하여 플레이어 캐릭터가 순록 주변의 볼륨에 닿을 때 맥락적 힌트를 듣습니다. TTS 오디오는 플레이어 캐릭터가 환경에서 이미 찾은 구슬의 수와 색상에 따라 변경됩니다.

©2026 Roblox Corporation. Roblox 및 Roblox 로고, 'Powering Imagination'은 미국 및 기타 국가 내 당사의 등록 및 미등록 상표입니다.