Пользователь
3,2
рейтинг
13 мая 2015 в 12:13

Разработка → 2D-платформер от Qt 5.2 до Qt 5.4

image Привет, Хабр. Эта статья должна была быть написана еще зимой, но по объективным причинам пишу ее сейчас.

Решил я как-то год назад заняться ГеймДевом. Поздновато, конечно, но история не об этом. Сразу решил, что надо писать для мобильных устройств. Направление перспективное и для меня оказалось очень интересным.

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

Достал книгу на русском, Внимательно прочитал половину, сделал детскую игру «Быки и Коровы». Здесь не о чем говорить, это был тестовый проект.

Почитал еще, обнаружил, что у Qt очень хорошая документация на родном сайте и в ней легко найти описание необходимых объектов. И это не может радовать.

Теперь стал вопрос о том, чтобы сделать проект немного посерьёзней. Везде советуют начинающим браться сначала за что-то простое, так сказать попробовать, научиться на своих ошибках и т.д. Я уже начал подготавливаться, чтобы написать старую и всем знакомую Lines, но вот тут стала необходимость для одного проекта написать что-нибудь на Android. И так родилась идея написать платформер. И вот, собственно говоря, история как раз об этом.

Решено было писать на С++, хотелось посмотреть, насколько адекватно оно будет потом работать на Android.
И сразу определился, что писать буду с использованием графической библиотеки Qt, потому что по ней достаточно много хорошего мануала, как говорилось раньше. Я не собираюсь описывать процесс создания платформера, этого добра в мировой сети достаточно на разных языках.

Начал писать это чудо в конце сентября на Qt 5.2, знаю, что уже была 5.3, но лень было заниматься обновлением. В начале ноября всё уже было готово, но по определённым причинам, мероприятие, для которого игра писалась, не состоялось и было перенесено на весну. Выкладывать для мира проект раньше времени нельзя. Было достаточно времени поработать над мелкими доработками и перенести её в Qt 5.4.

Кратко процесс реализации описал, теперь, собственно говоря, с какими проблемами я столкнулся во время разработки и переходом от одной версии к другой.

Графическая библиотека:

Графическая библиотека
Начнём с косяков.
Нативная библиотека Qt кушает очень много памяти. Пользовался компонентом QImage. При загрузке в память картинки размером 780 байт объём используемой памяти увеличивался не на пару килобайт, а на пару десятков, а иногда и сотен килобайт. Данный факт меня не очень радовал, а иногда раздражал.

Чтобы как-то уменьшить объемы используемой памяти, все графические элементы поместил в один файл. Но это было связанно еще и с удобством использования. Объем используемой памяти сразу уменьшился на 10М.

Второе, что бросилось в глаза, Это насколько сильно грузится процессор. Не 100%, но более 50%. Может, для игр это и нормально, но дальше было интересней.

При выходе Qt 5.4 компания-разработчик утверждала, что они улучшили графическую библиотеку.
Я подтверждаю, что-то они улучшили :). При переносе на 5.4 стало еще меньше использоваться оперативной памяти и процессор уже загружен был менее, чем на 50%. Эти все параметры смотрел в Windows, как дела обстоят на андроиде — не в курсе.

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

Во-первых — гладкого масштабирования не получилось, процесс отрисовки сразу увеличивался в 20-30 раз. Но от этого можно и отказаться, не такой уж это серьёзный проект, где надо много внимания уделять графике. Но для себя отметил, что надо готовить картинки для разных разрешений экрана.

Вторая проблема заключалась в следующем. Как ранее говорилось, все графические элементы были помещены в один файл. Надо было просто указать область, которую перерисовать на игровой экран. При увеличении данной области почему-то захватывался на 1 пиксель больше указанного.

Решением проблемы является то, что между элементами надо оставлять немного свободного места в 1-2 пикселя. Или сами элементы делать чуть меньшего размера, чем сама область. У меня получился 2-й вариант.

И последнее, что мне не понравилось. Это отсутствия возможности работать с картинками с маленькой цветовой гаммой (16 и 256). В QIMage реализовано якобы 256 бит, но каждый бит надо прописать заранее.

В остальном библиотека меня порадовала. Удобно с ней работать, поддерживает разные форматы картинок, можно сохранить полученное изображение на диск. Разнообразный размер инструментов


Работа со звуком

Работа со звуком
В книге описана работа с мультимедиа для версии 4.8. Но с тех пор всё поменялось. И компоненты, и работа с ними. Немного гугления и чтения документации привели к успеху. В итоге оказалось всё не так сложно. Описывать подробно не стану, на сегодня этой инфы достаточно на форумах и документация есть. Но если кому лень разбираться, пишите, отвечу.

Собственно говоря, с какими проблемами столкнулся. Файлы WAV больших размеров не терпят. Больших — имеется в виду дольше 3-х сек. MP3-файлы тоже не особо жалует. Более 5MB не получилось подключить. И не хотело собираться, когда итоговый размер медиа был более 10MB. Может, это ограничение как-то и регулируется, но я не нашел, как. Я уменьшил качество аудио MP3 файлов и всё пошло.

В остальном компоненты по управлению звуками работали достойно. Можно управлять уровнем громкости, MUTE'ировать звук без остановки аудио. Пускать музыку/звуки на фоне, не останавливая основной поток воспроизведения. Только если вы запустили в отдельном потоке звук, то он будет звучать, пока не закончится, и остановить принудительно его нельзя.

Еще столкнулся с проблемой в 5.2 — не работали внешние кнопки регуляции уровня звука. Пришлось допиливать Activity. О том, как я это делал, на Хабре статью написал. В версии 5.4 уже всё работает, ничего допиливать не надо.


Тачскрин

Тачскрин
Вот тут у меня самое большое недоразумение случилось. А суть заключается в следующем.

В версии 5.2 я изучил подробно работу с событиями тачскрина. Есть контейнер, который хранит координаты и состояние всех «пальцев» на экране. Есть события, которые реагируют на первое прикосновение (первый «палец»), событие на изменение (передвижение «пальцев» или изменение их количества на экране), и событие, которое сообщает о завершении тача (когда все «пальцы» убираются с экрана).

По сути, если у Вас в приложении будет использоваться мультитач, то события мышки можно даже и не обрабатывать. Всё прекрасно работает на событиях Тачскрина. Но по определённым надобностям мне пришлось обрабатывать и события мышки. Впоследствии это мне и помогло разобраться в проблемах.

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

Зачем-то разработчики Q, поменяли логику работы событий тачскрина и мышки! Теперь это работает как-то по-чудному. При первом касании «пальца», генерируются события MouseButtonPress и TouchBegin. Но потом, когда генерируется событие MouseMove а TouchUpdate не генерируется. Но в контейнере тача точка остаётся, но координата и состояние ее не меняется. И когда генерируется событие MouseButtonRelease, событие TouchEnd не генерируется и получается, что виртуально у вас всегда на экране «висит» один «палец».
Эта проблема решается следующим образом: при событии TouchBegin копируете контейнер состояния в свой, а при MouseButtonRelease очищаете его до следующего TouchBegin.

После того как на экране появляется второй «палец», генерация событий мышки отключается. И после этого, сколько бы вы пальцев ни ставили на экран или сколько бы ни оставляли, всегда генерируются события TouchUpdate. Когда все «пальцы» убираются с экрана, генерируется событие TouchEnd, а MouseButtonRelease нет. Проблем можно избежать, отреагировав на событие TouchEnd так же, как и на MouseButtonRelease. Но дело в том, что при следующей генерации TouchBegin события, MouseButtonPress не генерируется и вы будете дальше работать с событиями тачскрина. Вот тут-то и затаилась самая большая проблема.

MouseButtonPress не будет генерироваться до тех пор, пока не будет события MouseButtonRelease. Если MouseButtonRelease вызывать искусственно, то всё равно ничего не получится. Нужно поставить на экран и убрать только один «палец», после этого системно будет генерироваться MouseButtonRelease.
Эту проблему решал следующим образом. Вместе с TouchBegin искусственно вызывал событие MouseButtonPress. В функции обработке этого события вначале проверял состояние глобальной переменной, если она false, тогда ей присваивалось true и выполнялся код функции, если же она true значит, мы только что обрабатывали это событие, и просто выходим из функции. При TouchEnd или MouseButtonRelease этой переменной присваивался false.

Если бы в 5.4 ничего не поменялось в работе тачскрина, то этой части текста здесь могло бы и не быть. А так я очень остался недоволен. Раз в «пятилетку» баг выскакивает в работе тачскрина, но не могу его воспроизвести и как следствие — понять, почему он возникает. Как только это случится, то обязательно здесь отпишусь.


Что еще

Еще добавил перевод на английский, но там проблем не возникло, и инфы по интернационализации приложений в Qt достаточно.

Итоги

Игра была написана и успешно запущенна в проекте. Свои первоначальные предназначения она выполнила — мне набраться опыта в геймдеве и стать одним из заданий в городском квесте. Теперь она будет выполнять своё второстепенное предназначение — быть частью моего портфолио.

Спасибо Вам, за то, что Вы это читали.
Олег Михалевич @Mihasik1984
карма
10,0
рейтинг 3,2
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (14)

  • +2
    QImage — для ввода\вывода, обработки, рез рисования.
    QPixmap — для отрисовки на экран, работает гораздо шустрее, по памяти не в курсе.
    • –2
      Сейчас не вспомню почему выбрал QImage. Но в следующий раз обязательно попробую QPixmap, и тогда сравним.
    • 0
      QPixmap позволяет создавать обёртку над внешней памятью? Я помню, когда-то мне тоже нужно было рисовать картинку на графической сцене, но данные (буфер памяти) приходили из другой библиотеки, поэтому я использовал QImage просто как обёртку над этой памятью. QPainter умеет рисовать как QImage, так и QPixmap.
      • 0
        QPixmap::loadFromData(http://doc.qt.io/qt-5/qpixmap.html#loadFromData) инициализирует QPixmap изображениеим из сырых данных

        Но это не является именно обёрткой, внутри он производит преобразования и копирование данных себе.
        • 0
          Мне нужна была именно обёртка, чтобы не было копирования данных, так как данные постоянно изменялись извне (естественно без изменения размера), и эти изменения нужно было отображать на экране в реальном времени. Преобразование и копирование в QPixmap на корню убило бы всю производительность в этом случае, а QImage вполне справлялся с достаточной производительностью при разумном разрешении экрана (размере буфера).
    • 0
      А еще лучше QGLPixelBuffer. И нет ничего удивительного в том, что распакованные картинки в памяти занимают больше места.
  • +5
    А о чём статья?! Или даже, а зачем статья?!
    • –2
      О работе с 3-я компонентами Qt, их плюсы и минусы.
      • +2
        А обязательно в хаб «Разработка под Android» помещать было?
        А то что-то мне не нравится фраза:
        При переносе на 5.4 стало еще меньше использоваться оперативной памяти и процессор уже загружен был менее, чем на 50%. Эти все параметры смотрел в Windows, как дела обстоят на андроиде — не в курсе.

        Может, всё-таки, под Windows?
  • +3
    80% cтатьи — вода. Без скриншотов самой игры так вообще бесполезная затея.
    • –1
      Нужны нескучные скриншоты?
      • 0
        А куда без них, ты шо? Любой текст длиннее 100 символов без картинки смотрится СЫРО.
  • +2
    Google тоже попробовали на Qt'e игрушку написать — VoltAir. Если внимательно почитать все ридми, то можно заметить, что производительностью они не особо довольны, как и загрузкой ЦП.
    Для игр тяжеловата обвязка в общем…
    • 0
      По мне так это логично. Qt — фрэймворк для создания интерфейсов, а не для работы с реалтаймовой графикой. Для игр есть отдельные движки, специально для этого заточенные. На них, кстати, обычно не очень удобно создавать интерфейсы, что, впрочем, никого не удивляет )

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.