Godot
Godot 4.x · GDScript
먼저 문장 하나를 화면에 표시해 보세요. 이 작은 예제는 실제 항구 내보내기 파일을 직접 읽으며, 완전한 대화 재생기는 아닙니다. 이후 데이터를 게임 UI에 연결하세요.
1 · 파일 및 장면 준비
루트가 Label인 장면을 만들고 저장하세요. 전체 항구 내보내기 파일을 res://story/에 넣으세요. Label에 FirstText.gd를 연결하고 F6로 장면을 실행하세요.
2 · 첫 번째 텍스트 표시
extends Label
const TEXT_ID = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf"
var story: Dictionary
func _ready() -> void:
var parser = JSON.new()
var error = parser.parse(FileAccess.get_file_as_string("res://story/story.json"))
if error != OK or not parser.data is Dictionary:
text = "Cannot read story/story.json"
return
story = parser.data
show_language("en")
func show_language(locale: String) -> void:
var record: Dictionary = story["content"]["texts"][TEXT_ID]
var translation: Dictionary = story["content"]["translations"].get(locale, {}).get(TEXT_ID, {})
var message: Dictionary = translation.get("message", record["sourceMessage"])
var line := ""
for segment in message["segments"]:
if segment["kind"] != "text":
text = "This example needs text-only segments"
return
line += segment["text"]
text = line
예상 출력은 “Welcome to the harbour. I am Mira.”입니다. locale = "de" 또는 언어 매개변수 de를 사용하면 “Willkommen im Hafen. Ich bin Mira.”가 표시됩니다. 없는 언어는 원문을 사용합니다. 이 예제는 텍스트 세그먼트를 지원하며, 자리표시자를 알림 없이 무시하지 않습니다.
3 · 한 문장에서 대화
위의 고정 텍스트 ID는 첫 번째 테스트용입니다. 게임에서는 story-index.json에서 flowRef/entryRef를 선택하고 execution.entries[entryRef].nodeRef, 이어서 execution.nodes[nodeRef]를 읽으세요. 현재 대화 노드는 text.textRef와 speakerRef를 제공합니다. 다음 진행 방식은 노드 종류에 따라 달라집니다.
이름과 대사: Label.text. 답변: Button.text와 pressed 신호를 사용하고 선택지 ID를 유지하세요. End에서는 공통 Control 컨테이너를 hide()로 숨깁니다. 예제의 show_language("de")는 노드를 진행하지 않고 같은 텍스트의 언어만 바꿉니다.
- Continue와 End: 연결을 따라 진행하고 대화창 닫기
- 선택지: 답변 ID, 표시 순서, 선택한 답변의 다음 진행
- 조건과 변수: 10 또는 2 골드
- 언어: 같은 ID로 새 언어의 콘텐츠 가져오기
- 명령: 아이템을 주고 가게를 엽니다.
- Call/Return: 하위 이야기로 이동했다가 돌아오기
이 프로그래밍 언어로 답변과 금화 검사 살펴보기
선택지 데이터 읽기
로딩 후 story를 사용할 수 있는 위치에 이 코드를 넣으세요. RPG Maker에서는 const story = $gameTemp.vnleExample.story;를 사용합니다. 확인용으로 ID를 출력하며, 실제 게임에서는 이 출력을 답변 버튼으로 바꾸세요. 항구의 두 답변과 이후 금화 검사를 다루는 예제일 뿐, 범용 해석기는 아닙니다.
# story is the Dictionary loaded above. These Harbour options have no conditions.
var choice: Dictionary = story["execution"]["nodes"]["42edfff8-b8fe-46bf-ae0d-9e2347b6e726"]
for option_id in choice["optionOrder"]:
var option: Dictionary = choice["options"][option_id]
print(option_id, " ", option["text"]["textRef"])
# Resolve each text and bind its option_id to a Button's pressed signal.
var branch: Dictionary = story["execution"]["nodes"]["c1c3c372-0a73-4cd0-851d-ede59d5709bb"]
var gold := 10 # Repeat with 2.
var next: Dictionary = branch["whenTrue"] if gold >= branch["condition"]["right"]["value"]["value"] else branch["whenFalse"]
print(next["nodeRef"])금화가 10개이면 next는 “Pay five gold”, 2개이면 “Not enough gold”를 가리킵니다. 실제 게임에서는 선택한 경로가 이 노드에 도달했을 때만 검사하세요. 각 답변은 자신의 다음 진행 정보를 제공합니다.
4 · 자신의 이미지 연결하기
이 추가 예제는 현재 대화 객체 node와 주석에 적힌 UI 요소가 있다고 가정합니다. C++와 MonoGame에서는 speakerRef를 이미 SpeakerId 또는 speakerId로 읽은 상태입니다. 키는 미라의 실제 캐릭터 ID이며, 이미지 이름과 위치는 게임에서 정합니다. 표시된 위치에 코드를 넣으세요.
# Put mira.png at res://portraits/mira.png and add a TextureRect named Portrait.
var portraits = {"807b2957-7bab-4a28-83a4-1f3d1589bbc2": preload("res://portraits/mira.png")}
# node is the current dialogue dictionary, not a Godot scene node.
$Portrait.texture = portraits.get(node.get("speakerRef", ""))화자 이름도 대사처럼 content.characters[speakerRef].nameTextRef로 구하세요. 이미지 연결이 없으면 이전 초상화를 숨기거나 대체 이미지를 표시하세요. 이미지는 언어에 따라 선택되지 않습니다.
5 · 게임과 함께 파일 배포하기
FileAccess를 사용할 때는 내보내기에 원본 JSON을 보존하세요. 사용할 수 있다면 Keep File을 선택하고, 아니면 적절한 비리소스 파일 내보내기 필터를 사용하세요. 이미지는 가져온 Texture2D 리소스를 사용하거나 원본 PNG를 명시적으로 포함하세요. 내보낸 빌드도 실행해 보세요.
결과 확인
- 영어와 독일어 인사말이 올바르게 표시되고, 사용할 수 없는 언어를 선택하면 영어 원문이 표시되어야 합니다.
- 진행 로직을 추가했다면 두 답변, 금화 10개와 2개, 하위 이야기에서 돌아오기, End를 시험하세요.
- 빌드한 게임을 프로젝트 폴더 밖에서 실행하세요. JSON, 글꼴, 초상화가 그곳에서도 제공되어야 합니다.
공식 문서
API 및 이 접근 방식을 위한 설정 참조: