VNLEWIKI이야기를 만들고, 세계를 연결하세요.
한국어
VNLE 사용 설명서

MonoGame

← 게임에 콘텐츠 연결하기

MonoGame 3.8 · DesktopGL · C# / .NET

먼저 문장 하나를 화면에 표시해 보세요. 이 작은 예제는 실제 항구 내보내기 파일을 직접 읽으며, 완전한 대화 재생기는 아닙니다. 이후 데이터를 게임 UI에 연결하세요.

1 · 파일 및 장면 준비

MonoGame DesktopGL 프로젝트로 시작하세요. story.json을 Content/에 넣고 출력 폴더에 원본 파일로 복사하도록 설정하세요. 아래 프로젝트 설정을 참고하세요. Game1에 ReadWelcome을 추가하세요. Content Pipeline Tool에서 DialogueFont라는 SpriteFont를 만들고 콘텐츠를 빌드한 뒤 다음 코드로 불러오세요: Content.Load("DialogueFont").

story.json · 내보낸 파일 설명

2 · 첫 번째 텍스트 표시

<ItemGroup>
  <None Update="Content/story.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

Game1에 SpriteFont _dialogueFont;와 string _dialogueLine = ""; 필드를 추가하세요. LoadContent에서 사용할 코드: _dialogueFont = Content.Load("DialogueFont"); _dialogueLine = ReadWelcome("en");. Draw의 기존 SpriteBatch 블록 안에서 _spriteBatch.DrawString(_dialogueFont, _dialogueLine, new Vector2(24, 24), Color.White);를 사용하세요. SpriteBatch가 없다면 LoadContent에서 new SpriteBatch(GraphicsDevice)로 만들고 Draw에서 Begin()/End()를 사용하세요.

// Game1.cs: add using System.IO; using System.Text.Json; using System.Text;
// Place this method inside the existing Game1 class.
private string ReadWelcome(string locale)
{
    using var stream = TitleContainer.OpenStream("Content/story.json");
    using var document = JsonDocument.Parse(stream);
    var content = document.RootElement.GetProperty("content");
    const string id = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf";
    var message = content.GetProperty("texts").GetProperty(id).GetProperty("sourceMessage");
    if (content.GetProperty("translations").TryGetProperty(locale, out var table)
        && table.TryGetProperty(id, out var translation))
        message = translation.GetProperty("message");
    var line = new StringBuilder();
    foreach (var segment in message.GetProperty("segments").EnumerateArray())
    {
        if (segment.GetProperty("kind").GetString() != "text")
            throw new InvalidDataException("Text-only example");
        line.Append(segment.GetProperty("text").GetString());
    }
    return line.ToString();
}

예상 출력은 “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를 제공합니다. 다음 진행 방식은 노드 종류에 따라 달라집니다.

이름과 대사는 Begin/End 사이에서 SpriteBatch.DrawString으로 그립니다. 긴 텍스트의 줄바꿈과 글꼴이 지원하는 문자를 확인하세요. 답변 영역과 마우스 및 키보드 입력은 게임에서 구현하며 번역된 텍스트 대신 ID를 유지합니다. End에서는 Game.Exit()가 아닌 dialogueOpen = false로 표시와 입력을 끄세요.

  1. Continue와 End: 연결을 따라 진행하고 대화창 닫기
  2. 선택지: 답변 ID, 표시 순서, 선택한 답변의 다음 진행
  3. 조건과 변수: 10 또는 2 골드
  4. 언어: 같은 ID로 새 언어의 콘텐츠 가져오기
  5. 명령: 아이템을 주고 가게를 엽니다.
  6. Call/Return: 하위 이야기로 이동했다가 돌아오기
이 프로그래밍 언어로 답변과 금화 검사 살펴보기

선택지 데이터 읽기

로딩 후 story를 사용할 수 있는 위치에 이 코드를 넣으세요. RPG Maker에서는 const story = $gameTemp.vnleExample.story;를 사용합니다. 확인용으로 ID를 출력하며, 실제 게임에서는 이 출력을 답변 버튼으로 바꾸세요. 항구의 두 답변과 이후 금화 검사를 다루는 예제일 뿐, 범용 해석기는 아닙니다.

// Inside ReadWelcome while document is alive; inspect data before returning.
var nodes = document.RootElement.GetProperty("execution").GetProperty("nodes");
var choice = nodes.GetProperty("42edfff8-b8fe-46bf-ae0d-9e2347b6e726");
foreach (var idToken in choice.GetProperty("optionOrder").EnumerateArray())
{
    string optionId = idToken.GetString();
    var option = choice.GetProperty("options").GetProperty(optionId);
    System.Console.WriteLine(optionId + " " + option.GetProperty("text").GetProperty("textRef").GetString());
}
var branch = nodes.GetProperty("c1c3c372-0a73-4cd0-851d-ede59d5709bb");
int gold = 10; // Repeat with 2.
int minimum = branch.GetProperty("condition").GetProperty("right").GetProperty("value").GetProperty("value").GetInt32();
var next = branch.GetProperty(gold >= minimum ? "whenTrue" : "whenFalse");
System.Console.WriteLine(next.GetProperty("nodeRef").GetString());
// Copy strings/values you need later before disposing JsonDocument.

금화가 10개이면 next는 “Pay five gold”, 2개이면 “Not enough gold”를 가리킵니다. 실제 게임에서는 선택한 경로가 이 노드에 도달했을 때만 검사하세요. 각 답변은 자신의 다음 진행 정보를 제공합니다.

4 · 자신의 이미지 연결하기

이 추가 예제는 현재 대화 객체 node와 주석에 적힌 UI 요소가 있다고 가정합니다. C++와 MonoGame에서는 speakerRef를 이미 SpeakerId 또는 speakerId로 읽은 상태입니다. 키는 미라의 실제 캐릭터 ID이며, 이미지 이름과 위치는 게임에서 정합니다. 표시된 위치에 코드를 넣으세요.

// Game1 class field, so both LoadContent and Draw can access it:
private readonly System.Collections.Generic.Dictionary<string, Texture2D> portraits = new();
// Inside LoadContent(): import/build mira.png as portraits/mira.
portraits["807b2957-7bab-4a28-83a4-1f3d1589bbc2"] = Content.Load<Texture2D>("portraits/mira");
// Inside a SpriteBatch Begin/End in Draw; speakerId comes from speakerRef:
if (portraits.TryGetValue(speakerId, out var portrait))
    _spriteBatch.Draw(portrait, new Vector2(24, 120), Color.White);

화자 이름도 대사처럼 content.characters[speakerRef].nameTextRef로 구하세요. 이미지 연결이 없으면 이전 초상화를 숨기거나 대체 이미지를 표시하세요. 이미지는 언어에 따라 선택되지 않습니다.

전체 내보내기의 이미지 참조 사용하기

5 · 게임과 함께 파일 배포하기

이 예제에서는 JSON을 Content.Load로 읽지 마세요. TitleContainer가 원본 파일을 열며 csproj가 파일을 복사합니다. SpriteFont와 텍스처는 Content Pipeline으로 빌드하세요. 먼저 DesktopGL에서 사용하고 다른 플랫폼은 별도로 확인하세요.

결과 확인

  1. 영어와 독일어 인사말이 올바르게 표시되고, 사용할 수 없는 언어를 선택하면 영어 원문이 표시되어야 합니다.
  2. 진행 로직을 추가했다면 두 답변, 금화 10개와 2개, 하위 이야기에서 돌아오기, End를 시험하세요.
  3. 빌드한 게임을 프로젝트 폴더 밖에서 실행하세요. JSON, 글꼴, 초상화가 그곳에서도 제공되어야 합니다.

공식 문서

API 및 이 접근 방식을 위한 설정 참조: