MonoGame
MonoGame 3.8 · DesktopGL · C#/.NET
Начните с вывода одной фразы. Этот небольшой пример напрямую читает реальные данные экспорта гавани, но ещё не является полноценной системой диалогов. Затем подключите данные к интерфейсу своей игры.
1 · Подготовка файлов и сцены
Начните с проекта MonoGame DesktopGL. Поместите story.json в Content/ и настройте копирование исходного файла в выходную папку (см. конфигурацию проекта ниже). Добавьте ReadWelcome в Game1. В Content Pipeline Tool создайте SpriteFont с именем DialogueFont, соберите контент и загрузите его через Content.Load
story.json · Назначение файлов экспорта
2 · Выведите первый текст
<ItemGroup>
<None Update="Content/story.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>Добавьте поля SpriteFont _dialogueFont; и string _dialogueLine = ""; в Game1. В LoadContent используйте _dialogueFont = Content.Load
// 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 текста выше нужен только для первого теста. В игре выберите flowRef/entryRef из story-index.json, прочитайте execution.entries[entryRef].nodeRef, затем execution.nodes[nodeRef]. Текущий диалог содержит text.textRef и speakerRef. Дальнейший путь зависит от типа узла.
Имя и диалог: SpriteBatch.DrawString внутри Begin/End. Обработайте перенос строк и наличие нужных символов в шрифте для длинного текста. Области ответов и ввод мышью или клавиатурой реализует игра; храните ID, а не переведённый текст. End: отключите вывод и ввод через dialogueOpen = false, а не Game.Exit().
- Continue и End: переходы по связям и закрытие окна диалога
- Выбор: ID ответа, порядок и выбранное продолжение
- Условия и переменные: десять или две золотые монеты
- Язык: те же ID, заново полученный текст
- Command: выдать предмет или открыть магазин
- 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 и элементы интерфейса, указанные в комментариях. В 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, остальные платформы — отдельно.
Проверьте свой результат
- Приветствия на английском и немецком отображаются правильно; при выборе недоступного языка используется английский.
- Добавив выполнение сюжета, проверьте оба ответа, 10 и 2 золотых, возврат из подыстории и End.
- Запустите собранную игру за пределами папки проекта. JSON, шрифты и портреты должны быть доступны и там.
Официальная документация
Документация по API и настройке для этого подхода: