Мысли программиста о локализации игры
Приветствую! В продолжении рассказа о том как я делаю коммерческую инди-игру публикую данный пост. Пост технический, местами банален, но всё-таки он результат моего продолжительного размышления на тему "как локализовать игру на X языков с минимальными затратами".
Первый пост, который описывает проект над которым я работаю, лежит вот тут:
Заметки кудесника джойстика об игроразработческом деле. Часть вводная
Итак, с самого начала я решил, что игра должна быть локализована на несколько языков. Очень не хотелось заниматься копанием кода под каждую локаль, перекомпилировать его и тем более отлавливать баги, появление которых неизбежно. Решил, что лучшее решение — это выделение всех локализуемых ресурсов во внешние файлы (банально, правда? :)).
Все текстыхранятся в XML-документе, который имеет примерно следующую структуру:
<section name="main_menu">
<text id="start">Start Game</text>
<text id="load">Load Game</text>
<text id="options">Options</text>
<text id="exit">Exit</text>
</section>
<section name="stat">
<text id="strength">Strength</text>
<text id="dexterity">Dexterity</text>
<text id="speed">Speed</text>
</section>
Здесь две секции с именами main_menu и stat. Эти секции содержат элементы text с аттрибутом id и непосредственно текстом, который должен отоброжаться в игре. Суть в том, что где-то в коде игры, когда нужно вывести на экран надпись, например, 'Load Game', вместо того, чтобы писать эту строку в коде, мы делаем ссылку на элемент text с аттрибутом id = 'load' из секции main_menu.
То есть мы создали словарь. id — это то, что будет запрашивать код игры, взамен получая строку, которая соответствует этому id.
Теперь, если мы заходим перевести игру, например, на русский, то нужно отредактировать наш словарь:
<section name="main_menu">
<text id="start">Начать игру</text>
<text id="load">Загрузить игры</text>
<text id="options">Настройки</text>
<text id="exit">Выход</text>
</section>
<section name="stat">
<text id="strength">Сила</text>
<text id="dexterity">Ловкость</text>
<text id="speed">Скорость</text>
</section>
Приём прост, но, почему-то, мало кто его использует (а посмотрел я мнооого исходников игр).
Задумайтесь о локализации в самом начале разработки. Возможно, вам кажется, что игре ни к чему переводиться на другой язык, но ведь реализовать чтение словря наподобие описанного выше дело не долгое.
Поверьте, если уже к моменту релиза проекта вы захотите сделать его локализуемым — потратите много сил и времени, потому, что иногда чтобы сделать игру локализуемой нужно менять её архитектуру... А кто это любит? :))
- 20 октября 2010, 20:03
- 03
о, опечаточка:
Специальные символы html(не помню, как правильно по-русски называются)
& lt; (без пробела) =
Символ & для вывода "как есть" кодируется связкой &, поэтому можно было обойтись без пробелов и дополнительных инструкций написав &lt; для вывода <
да, не подумал что-то)
А я просто как-то нажал кнопочку "Новый пост" и само всё сделалось. Похоже на магию. :))
За замечание спасибо, исправил.
Отличное логичное и, вобщем-то, интуитивно понятное решение.
Если проект под винду, то в ресурсные файлы *.rc внутри себя содержат механизм локализации строк, диалогов и всего прочего. Хотя xml конечно демократичнее и удобнее! Впрочем, ресурсы обычно прячут от шаловливых ручек упаковывая в один большой ресурсный файл - тут преимущество xml слегка сдуется.
В любом случае предусмотрение локализации немного усложняет читабельность кода, т.к. константы выносятся отдельно. Раньше я всегда выносил константы в отдельные перечисления\файлы\классы, но сейчас точку зрения немного поменял - в небольших проектах без локализации или вообще где константы используются только в одном месте иногда лучше обойтись прямой вставкой.
Например вот такой вариант:
XmlElement xmlNode = xmlDoc.CreateElement("map-descriptor")
...читается лучше, чем:
XmlElement xmlNode = xmlDoc.CreateElement(Common.XmlTags.MapEditor.MapDescriptor)
Хотя второй подход формально правильней - константы с именами xml-тэгов, например, хранятся в одном файле\сборке\пространстве имён и их можно править кучей, у первого подхода появляется серьёзное преимущество - читабельность! А если создание этого тега единственное, то вот тут-то и пришлось мне пересмотреть былую педантичность с константами. :)
Проект под винду, но ресурсные файлы плохи тем, что редактировать их может только тот, у кого есть редактор ресурсов. XML текстовой и логичный. А еще в *.rc ресурсах нельзя поделить на секции и группы (main_menu - всё, что относиться к главному меню, stat - всё, что относиться к характеристикам игрока).
Константы, если их хранить непосредственно в коде - усложняют читабельность, да. Однако я отделил логику от ресурсов: есть XML-файл с локализуемым текстом и есть ресурс, который описывает форму с кнопками. В этом ресурсе каждой кнопе назначен идентификатор из словаря.
Так все ссылки на словари предоставлены тем, кто в них нуждается. И в коде чистота :).
P.S. В файле, где описывается форма с кнопками также описываются и обработчики событий. Обработка ведётся в Lua-скриптах и обработчик - это просто имя функции в скрипте.
P.P.S. В общем всё максимально отдельено друг от друга.
О! Lua это то, что я собирался, но так и не освоил. Сильно помогает?
Сначала планировал на питоне скрипты, но после некоторых мыслей решил всё-таки взять Lua. Помогает, но связывать Си++ со скриптом не самое благородное дело. Я пока не дошёл до связи игровых объектов, с GUI всё более-менее просто.
Интересно прочитать эти некоторые мысли (Lua видел только "на картинках", потому даже предположений нет, чем оно может быть лучше Пайтона).
Ничего не мешает просто запихнуть строки в текстовый файл безо всякого xml, грузить их из нужного файла при старте, потом уже создавать словарь/список/кортеж... IMHO.
XML хорош тем, что можно одно вкладывать в другое. Удобно разделять ключи по секциями и группам. В обычном текстовом файле древовидность сделать, на мой вкус, гемморойно. XML нагляднее и кошернее :).
Мм, cfg, ini?)
В общем, дело вкуса :-)