Уроки Коммент.

Создание игр » Featured, Уроки » PugiXML: XML-файлы.

PugiXML: XML-файлы.

XMLXML (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 можно с его официального сайта pugixml.org, там же находится и документация. Как говорят сами авторы PugiXML, он является “легковесной” библиотекой для чтения XML, с экстремально быстрым парсером и поддержкой юникода. Самую последнюю версию этой библиотеки можно скачать с SVN проекта:

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 и как с ним работать, Вы можете:

Если у Вас что-то не получилось – пишите, будем разбираться вместе!

Ещё по этой теме:




Раздел: Featured, Уроки · Теги: XML

Один комментарий на "PugiXML: XML-файлы."
  1. Иван пишет:

    Спасибо большое за статью!Очень помогли.Наверное в includ-ах не
    #pragma comment(lib, “pugixml_d.lib”),а #pragma comment(lib, “pugixmld.lib”).

Оставить комментарий

*

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>