Создание игр » Featured, Уроки » PugiXML: XML-файлы.
PugiXML: XML-файлы.
XML (eXtensible Markup Language) это расширяемый язык разметки. XML представляет из себя текстовый формат, предназначенный для хранения структурированных данных (например, взамен файлов баз данных), для обмена информацией между программами, а также для создания на его основе более специализированных языков разметки (XHTML как пример). Формат спецификации XML был утверждён в 1998 году, хотя черновой вариант был готов уже в 1996.
В наше время XML используется повсеместно – в вебе, в СУБД, для обмена данными между приложениями, в клиент-серверном ПО и много где ещё. Такую популярность этот формат завоевал благодаря его простоте и, одновременно с этим, удобству и гибкости. Я бы даже сказал больше – по гибкости, как и по простоте ему, наверное, вообще нет равных.
Синтаксис XML
XML это описанные в текстовом формате иерархические данные. ХМЛ можно использовать для хранения любых данных. Визуально структура данных формата может быть представлена как дерево элементов, а сами элементы описываются тегами.
Вот как выглядит типичный XML:
<?xml version="1.0" encoding="UTF-8"?> <enemy name="vrag"> <title>Враг</title> <health>3</health> <armor type="ceramic"></armor> <editprops> <pos>10 200 -93</pos> <color>255 128 128</color> <!-- Комментарий --> </editprops> </enemy> |
По-моему достаточно просто и вполне даже понятно, даже с первого взгляда.
Чем читать XML
Существует достаточно много библиотек, позволяющих читать и записывать XML-файлы – это и tinyxml и MSXML, и pugixml и многие другие. Каждая из этих библиотек имеет как свои плюсы, так и минусы – потому именно вам решать, на какой из них Вы остановите свой выбор. Однако, в данном уроке я хочу познакомить вас именно с pugixml, т.к., даже при его некоторых неудобствах, у него есть как минимум один существенный плюс – он действительно быстро читает XML.
PugiXML
Скачать PugiXML можно с его официального сайта
svn checkout http://pugixml.googlecode.com/svn/tags/latest pugixml |
После скачивания в папке /scripts вы найдёте проекты для Visual Studio, с помощью которых можно будет осуществить сборку (компиляцию) PugiXML. Я сделал обычную сборку (проект pugixml_vs2008.vcproj ). Процесс компиляции занимает всего несколько секунд, в результате чего появляется файл vs2008/x32/pugixml.lib – эту библиотеку надо будет подключать к вашим проектам, которые будут использовать PugiXML.
Чтение XML с помощью PugiXML
PugiXML предоставляет несколько различных функций для чтения (загрузки в парсер) данных: для чтения из файлов, чтения из потоков и чтения из памяти. Вот как выглядит чтение XML-документа из заранее загруженных в переменную source (указатель на данные) данных:
pugi::xml_document doc; pugi::xml_parse_result result = doc.load_buffer_inplace(source, source_len); if (result) ... нет ошибок else ... ошибка в result.description() |
Не забудьте добвить в вшу программу хидер и библиотеку PugiXML:
#include <pugixml.hpp> #ifdef _DEBUG #pragma comment(lib, "pugixml_d.lib") #else #pragma comment(lib, "pugixml.lib") #endif |
XML и PugiXML в игре
Для чего же нужен ХМЛ в игре? Я его чаще всего использую для хранения конфигов игры, хранения уровней игры. Этот формат легко менять, в него легко добавлять нужные данные, причём, только там, где они реально нужны, его легко читать и легко записывать. Он так же может помочь для создания сейвов игры.
Несомненно, работа с XML значительно медленнее, чем работа непосредственно с бинарными данными. Однако, никто не мешает нам разрабатывать всё с помощью ХМЛ, а во время релиза перегнать все данные в бинарные форматы, если это вообще понадобится, конечно – как правило, “тормоза” возникают лишь при объёмах документов в десятки тысяч строк, а такие объёмы информации редко встречаются в небольших играх. Да и для пользователя обычно не проблематично подождать лишние 1-3 секунды загрузки. Другое дело, если парсинг конфигов и уровней будет занимать по 5-15 секунд и больше – тогда их точно придётся перегонять в бинарные форматы, ибо у пользователя рано или поздно “закончится терпелка” и он просто закроет игру, которая через каждые 2 минуты геймплея грузит данные по 40 секунд.
Иными словами, прежде чем отказываться от этого, несомненно, очень удобного и во всех отношениях приятного формата, только по той причине что “он тормозит”, я прошу вас убедиться, что реально тормозит и тормозит именно он. Из своей практики могу сказать, что почти никогда чтение данных не является главным ботнеком программы и обычно есть целая куча других причин “торможения” проги, в том числе и на этапе загрузки – ведь чтение конфигов это далеко не единственное и не главное, что делает игра во время её загрузки или загрузки очередного уровня.
Итак, давайте научимся загружать данные из XML-конфигов в нашу игру. Я решил, что первым делом надо реализовать хотя бы один конфиг: настройки управления.
Загрузка конфигурации игры
Вот такой конфиг хотелось бы грузить, что бы получать из него управление:
<?xml version="1.0" encoding="windows-1251"?> <left>0x25</left> <right>0x27</right> <fire>0x20</fire> |
Давайте попробуем:
int g_keyLeft = 0x25; int g_keyRight = 0x27; int g_keyFire = 0x20; bool LoadGameConfig() { const std::string config = GetFileAsString("config.xml"); pugi::xml_document doc; pugi::xml_parse_result result = doc.load_buffer_inplace( (void*)config.c_str(), config.length()); if (!result) return false; // Ошибка парсинга данных // ищем нужные нам XML-ноды pugi::xml_node nodeLeft = doc.child("left"); pugi::xml_node nodeRight = doc.child("right"); pugi::xml_node nodeFire = doc.child("fire"); // load defaults g_keyLeft = 0x25; g_keyRight = 0x27; g_keyFire = 0x20; // читаем конфиг из XML-нод if (nodeLeft) stringstream(nodeLeft.child_value())>>std::hex>>g_keyLeft; if (nodeRight) stringstream(nodeRight.child_value())>>std::hex>>g_keyRight; if (nodeFire) stringstream(nodeFire.child_value())>>std::hex>>g_keyFire; return true; } |
Вроде бы, работает )))
На этом урок закончен. Более подробно почитать о формате XML и как с ним работать, Вы можете:
Если у Вас что-то не получилось – пишите, будем разбираться вместе!
Спасибо большое за статью!Очень помогли.Наверное в includ-ах не
#pragma comment(lib, “pugixml_d.lib”),а #pragma comment(lib, “pugixmld.lib”).