Урок 22 SFML работа с Tiled Map Editor (редактор карт для игр)

В этом уроке коснемся принципа работы с редакторами карт на примере Tiled Map Editor.

Для начала скачайте редактор и установите:

Ссылка на сайт редактора: http://www.mapeditor.org/

Видеоверсия tiled map editor sfml урок 22

Внимание! Есть изменения в коде level.hpp, смотрите примечание внизу в конце урока.

После установки запустим редактор. Нажимаем “Файл”->”Создать”->(ортогональная,xml,размер 50*27, тайлы 32*32):

урок 22 tiledmapeditor sfml
урок 22 tiledmapeditor sfml

Как видите – выбрал ортогональную ориентацию. К слову она бывает ещё и изометрической. В своем примере я пока не буду её рассматривать. Вкратце знайте, -это 2d похожее на 3d.
Например в этой статье можно понять суть этой ориентации http://habrahabr.ru/post/131755/

или вот ещё нашел картиночку 

Возможно под ваш проект подходит именно изометрическая карта, смотрите сами.

Немного отступления – карта будет в формате xml. Этот формат имеет теги, прям как html. Очень часто применяется в крупных проектах. Посмотрите, вот живой пример – в среде разработки intellij idea я, используя сборщик проектов maven, прописал зависимость в xml файле проекта и этот сборщик автоматически загрузит нужные библиотеки в проект (остается справа вверху нажать “авто-импорт”).

examplexmlidea

После того, как вы создали карту (наша карта имеет расширение .tmx-это формат файлов XML) – самое время загрузить ваш тайлсет. Для себя я взял вот такой простой, для урока пойдёт:

Tileset для sfml урока 22
Tileset для sfml урока 22

Вверху нажимаем “Карта”->”Новый набор тайлов”->”Обзор”, выбираем наш тайлсет.

урок 22 sfml пример загрузки тайлсета
урок 22 sfml пример загрузки тайлсета

Галочка “использовать цвет прозрачности” может понадобиться вам, если ваш тайлсет лежит не на прозрачном фоне, а, например, на синем. Пипеткой снимаете фон (код цвета) в паинте (в ранних уроках так делали) и выбираете этот цвет. Лучше иметь прозрачный тайлсет.

После загрузки тайлсета вы увидите справа результат. Вы можете загружать несколько тайлсетов и в редакторе выбирать из какого рисовать. Новые тайлсеты будут появляться во вкладке “наборы тайлов”(я буду работать с одним набором тайлов и код будет написан для одного набора,чтобы работать с двумя код из урока надо отредактировать или соединить два набора тайлов в один с помощью фотошопа например):

tileset sfml 22 урок
tileset sfml 22 урок

Теперь просто выбираете ту kychk’у тайлов, которую хотите нарисовать (зажимая лев. кл. мыши) и рисуете. Нарисуйте пару тайликов, сохраните в папке с проектом рядом с файлом main.cpp (у меня имя карты будет map формат tmx). Теперь откройте сохраненный файл карты редактором типа блокнота и посмотрите на него.

sfml урок 22 пример карты в блокноте
sfml урок 22 пример карты в блокноте

Вот на нужном месте стоят тайлы 193-й,194-й, 195-й. Это именно символ тайла, а не координаты или еще что то. Аналогично символу “0” из 9 урока

Ясно, что первый tile gid , который мы увидим в блокноте – это левый верхний угол на карте соответственно. Вот я поставил тайлик с плиткой в левый верхний угол и в блокноте картина будет такая:

tmx в блокноте
tmx в блокноте

Вот в начале этого файлы мы можем наблюдать все настройки, которые мы сделали в процессе создания карты. Сейчас мы рисуем на одном слое. Слои нужны для того, чтобы наложить одну картинку на другую. Аналогичные слои можем наблюдать во многих графических редакторах, в том же фотошопе.




Итак, воспользуемся возможностью лепить слои и добавим поверх нашего тайла ещё один тайл . Справа на панельке (в её верхней части) нажимаем добавить слой:

новый слой в tiledmapeditor
новый слой в tiledmapeditor

После добавления нового слоя тайла, нарисуем карту. Если вас не устроил тайл – вверху есть инструмент ластик, который стирает тайл на выбранном слое.
Если слой 2 находится в списке выше слоя 1, то всё, что будет нарисовано на 2 ом слое будет поверх первого слоя.
Если слой 2 будет в списке слоев ниже 1 ого слоя, то всё, что будет нарисовано на 2 ом слое будет позади первого слоя.

Кстати, во вкладке вид вверху можете настроить для себя различные удобства. например можно подсвечивать только активный слой тайлов. мне это показалось не совсем удобным т.к при рисовании я не очень вижу таким образом общую картину.

Так же карту тайлов можно сместить. Там где вы выбираете нужный квадрат-тайл, и чуть ниже (рядом с иконкой мусорки) слева, есть кнопка “параметры набора тайлов”. Появляется свойство и тут вам надо задать смещение рисования по Х или/и по Y.

Тайлы мы рисуем при помощи инструмента “Штамп”. Используя инструмент “Заливка” можно закрасить весь фон каким то цветом или тайлом. Или же можно просто указать в свойстве карты “фоновый цвет” (наш код ещё не заточен на снятие фона).

Тайлы можно поворачивать и отражать – клавиши X и Z. Так же работают все стандартные комбинации типа ctrl+a,ctrl+c,+x,+v и тд.

Сейчас давайте создадим слой объектов, назовем его “Collision”, он нужен для взаимодействия карты с персонажем и врагом. Будем создавать невидимые в игре прямоугольники поверх тайлов и персонаж будет на них стоять. (как на земле “0” раньше из прошлых уроков). Чтобы создать слой объектов нужно нажать туда же , где создавали слой тайлов и выбрать “создать слой объектов”. В свойствах даем ему имя “collision”. Теперь рисуем один прямоугольник поверх нашей земли. Выбираем слева “выбрать объекты” (или нажимаем S) и выбираем нарисованный прямоугольник. Растягиваем его как надо, даем ему имя в свойствах справа внизу – “solid” . Далее копируем его и вставляем , так рисуем все препятствия для персонажа, с которыми он должен столкнуться. Аналогичным образом нарисуйте прямоугольник где будет появляться игрок и назовите его “player” .

Я сильно не заморачивался и вот что у меня получилось:

sfml tiled map editor пример
sfml tiled map editor пример

Как видите объекты расставлены и создан объект для врага – “easyEnemy”. Размер прямоугольника врага я сделал равным размеру спрайта в игре (так он точно появится в нужном месте, для игрока это не так важно т.к он имеет притяжение к земле,а с врагом такого нет и может быть пустота между ним и землей). Теперь сохраним карту.

В редакторе есть расстановка тайлов по правилам. Вы создаете некое правило – например поставить этот тайл именно с таким-то слоем и поверх него с таким то тайлом. Нужно лишь для больших карт и уровней. В целом – создаете файл txt, в котором указываете название второго файла карты. Вот уже во втором файле карты вы рисуете это правило. Например на тайле куста вешаете тайл ягоды и все кусты на исходной карте при расстановке по этому правилу будут с ягодами. Если не понятно – на форум и там решим. Или просите – я сделаю короткий урок про правила. Просто не думаю, что это имеет спрос.

После того, как нарисуете карту необходимо будет её считать в нашей игре. Библиотека, позволяющая это сделать – TinyXML. Её можете скачать в конце урока вместе с проектом к этому уроку. Закинете папку библиотеки в папку с main.cpp, а затем слева в visual studio добавите содержимое этой папки (файлы исходного кода-> добавить-> существующий элемент).

Ок. Теперь создадим новый заголовочный файл level.h, который будет считывать нашу карту в игру. Код файла я взял из этой статьи: http://habrahabr.ru/post/199064/ и из урока своего братюни FamTrinli http://www.youtube.com/watch?v=T6o5OlgsCew

Дополнение от читателя, которое возможно поможет решить проблемы, которые могли у Вас возникнуть: https://vk.com/sfml_cpp?w=wall-96695804_2719

Оригинал кода и его обсуждение хранятся тут http://en.sfml-dev.org/forums/index.php?topic=3023.0 (автор кода планирует сделать или уже сделал работу с несколькими наборами тайлов и тд, насколько помню – изометрическую карту код может не поддерживать, но пробуйте)

 

Теперь вернемся к нашему main.cpp. Подключим на будущее:

 

Далее в Entity создаем вектор объектов (объекты – это прямоугольники с именем solid, например) нашей карты:

Так же в этот класс добавим ф-цию, которая возвращает координаты и размеры прямоугольника спрайта (в ближайшее время она понадобится нам для проверки столкновения с объектом карты):

Теперь в int main() создам объект класса Level и загружу в него карту:

 

Далее у нас небольшие изменения в классе Player:

(Я перенес имя в начало конструктора, у всех классов) Мы передаем в его конструктор по ссылке экземпляр lev класса Level, это нужно для взаимодействия персонажа с картой. Чуть дальше присваиваем экземпляру объекта (выше создавали вектор в Entity) все объекты карты. Теперь мы сможем сделать столкновение персонажа с картой.

Наша функция checkCollisionWithMap() немного изменится. Я поставлю комментарии на весь код , имеющий отношение к старой карте из прошлых уроков, а в следующем уроке удалю этот код.

 

Как видно – логика не поменялась, поменялась лишь реализация. Сначала мы проходимся по всем объектам и если встречаем объект с именем solid, то дальше всё как раньше.

Теперь изменим немного класс врага:

Все тоже самое что и у класс игрока, все те же изменения. Тольк здесь мы получаем не все объекты, а пока только “solid” прямоугольники. Зачем врагу все объекты? Он ведь не будет есть монетки, например. По мере совершенствования игры, возможно, придется изменять эти вещи.

Измененная функция checkCollisionWithMap():

Обратите внимание, что в данном случае условие “Если имя объекта == solid”  – можно убрать. Ведь мы получаем лишь “solid” объекты. У себя я пока просто закомментирую. Потом пригодится, возможно.

Теперь самое время поставить нашего врага и игрока так, как они стоят на карте. То есть в то же самое место, где есть объекты прямоугольники с именами player и easyEnemy.

Вот , создал их в int main() , перед созданием игрока и врага.
У этих объектов есть возможность снимать координаты, поэтому передадим их координаты в класс игрока и врага:

 

И вот конец нашего int main – рисование объектов:

Внимание! Поскольку у нас новая карта-уделите внимание камере. В моем случае, чтобы не было пустого поля внизу я поправил код для нижней части экрана в файле view.h:

Остальное пока закомментировал за ненадобностью. Чтобы камера не показывала слева пустую местность мы можем теперь просто добавить прямоугольник solid и не позволить персонажу идти левее. Например вот так:

collisionwithendmap

Скидываю весь проект, поскольку урок большой и кому-то будет удобно поковыряться в самом проекте.

скачать проект 22 урока sfml

Скриншот урока:

урок 22 sfml tiled map editor
урок 22 sfml tiled map editor

 

На следующем уроке запилим несколько врагов, используя “списки” – list.

Внимание! Внизу один из учеников допилил код level.hpp , поскольку Предыдущий файл level.hpp неактуален, т.к. не поддерживает парсинг современных версий TME. Код будет внизу.

Код урока:

main.cpp

 

view.h

level.h

Новый level.hpp

комментарий автора:

  • Максимально упростил, всё те же недостатки, что и у оригинального level.hpp – например, не поддерживает несколько тайлсетов, для безболезненной замены. Увы, не знаю, что с видеоверсией урока делать
  •  Всё, что требуется для использования этого тайлмапа : 1) tmx-карта , сохранённая в csv формате(по умолчанию во всех современных версиях TME)
  •  2) Отрисовка, просто передавая карты в вызов функции как обычный спрайт: window.draw(map);
  •  В остальном абсолютно аналогично оригиналу

Более свежие файлы для обработки xml

tinyxml2.cpp

tinyxml2.h

 

Буду благодарен, если поделитесь:
SFML вопросы, прошу, задавайте на форуме.
    1. чет комментировать не получилось(

      Так вот: полный путь до моего map.tmx мне ввести не дает, но заметил что когда запускаешь в VS release и запускаешь просто exe в папке release результат разный. Создал тему на форуме. Похожих не нашел, поиска тоже). Скрины сделал.

      Вложение: 322

  1. Игрок не отображается. Точней при запуске отображается на секунду и исчезает, иногда вообще не отображается, а иногда отображается, но на черном фоне.Всё делал правильно. Думаю, у меня не успевает погружаться метод checkCollisionWithMap. Даже не знаю что делать

    Вложение: safhngf

      1. Проблему не решил, но понял что не успевает погружаться взаимодействие с картой. Поставил гравитацию dy = dy + 0.0005*time и стало работать, но слишком медленно падаю)

  2. С официального сайта сейчас доступен TME только версии 0.15, в этой версии нет возможности выбрать формат слоя тайлов XML (вместо этого CSV можно выбрать). В итоге если я указываю путь к карте, нарисованной в этой версии, она не прогружается (персонаж падает бесконечно вниз), если использовать карту из проекта автора, то всё работает нормально. Что делать? Может всё таки можно где-то достать tiled map editor 0.11?

  3. Разобрался, во время создания карты нельзя сделать формат слоя тайлов XML. Но когда карта уже создана можно поменять с CSV на XML. И у меня карта не прогружается, когда она расположена внутри папки, которая расположена там же где и main. Если вынуть оттуда, то всё нормально работает.

  4. Помогите пожалуйста!! Работаю на code::blocks в линуксе и вот с чем столкнулся. Я проверил у меня ошибка именно в загрузке файла карты то есть когда я коментирую строчку lvl.LoadFromFile(“map.tmx”); то все работает (ну кроме карты) а когда убираю коментарий выдает ошибку!

    Вложение: 123321

  5. Добрый день!
    Ругается на файл tinyxml.cpp, а конкретно на метод

    TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
    {
    for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
    {
    if ( strcmp( node->name.c_str(), name ) == 0 )
    return node;
    }
    return 0;
    }

    точка останова на цикле for
    перерыл весь форум и гугл
    решения не нашел
    сижу второй день, прошу помощи!

    1. У меня была такая же проблема, это неправильно создан файл карты *.tmx, если открыть карту автора кода и новую карту то можно увидеть различие перед расположением тайликов, на второй строчке кода map.tmx значение параметра nextobjectid, у автора он равен 60, при создании карты у меня был равен 68, после изменения этого параметра эта ошибка пропала

Добавить комментарий