Редактор частиц QML

в 16:10, , рубрики: game development, Gamedev, open source, particles system, QML, qt, qt quick, Qt Software, qt5, частицы, метки: , , , , , , ,

Представляю ещё один свой проект, на этот раз, — opensource (лицензия GPLv3).
QML Particle Editor — редактор частиц, десктопное приложение, написанное целиком на QML.
image
Не знаю, как вы, а я Qt Quick Designer (известный также, как qml2puppet) обычно не использую, глючный он, да и руками мне удобнее писать. Беглый обзор показал, что для работы с частицами QML до сих пор ничего специфичного нет и не ожидается, поэтому за время новогодних праздников запилил свой редактор.

Зачем это нужно? Удобнее изменять свойства и тут же видеть результат, чем вслепую править код и гадать, почему внешне ничего не изменилось. Само собой, для того, чтобы делать крутые штуки вроде тех, что лежат в демо-приложенях, придётся вникнуть во взаимосвязь компонентов и разобраться в свойствах, без этого не обойтись. Хотя, основу, например, можно набросать в редакторе, а плюшки вроде ColorAnimation on color прописать уже руками, так как всё, что делает мой редактор — позволяет создать сцену и получить её QML код, который сразу можно использовать в любом проекте.

Подробности реализации и ссылка на репозиторий — под катом.

Для начала — схема компонентов модуля QtQuick.Particles 2.0, с которыми придётся иметь дело:

image

Всё просто: есть система частиц и 3 основные сущности в ней:

  • Painter — описывает внешний вид группы частиц
  • Emitter — испускает логические частицы
  • Affector — задаёт изменение атрибутов частиц

Компоненты Direction задают векторы скорости и ускорения, Shape — область действия аффектора или эмиттера. Есть ещё TrailEmitter, который испускает частицы из других частиц (так, к примеру, можно реализовать дымящиеся огненные шары), но его пока трогать не будем.

Из всего этого, на данный момент, редактор поддерживает следующее:

  • Emitter со всеми возможными Directions, нет TrailEmitter
  • Affectors (Age, Attractor, Friction, Gravity, Turbulence, Wander), нет GroupGoal и SpriteGoal
  • Создание и редактирование ImageParticle, нет CustomParticle и ItemParticle

В ближайшие дни планирую добавить поддержку Shapes и ItemParticle.

Как с ним работать?
После запуска, необходимо задать размер сцены и установить цвет фона или фоновое изображение. Далее в меню Particles -> Manage particles создаёте одну или несколько групп частиц (группы перечисляются через запятую без пробелов), после чего добавляете на сцену эмиттер, задаёте группу и собственно вот они, частицы, прямо перед вами. С помощью аффекторов можно добиться изумительных эффектов, они выглядят точно так же, как и эмиттеры, только цвет рамки, задающей область, у них не зелёный, а красный (на выходе, разумеется, никаких рамок нет). С кодом сцены можно ознакомиться в меню File -> Show code.

image

Большинство атрибутов являются числовыми или текстовыми, но есть и такие, которые задаются объектами (например, velocity и acceleration у Emitter'а), основная сложность заключалась в их переключении. В итоге я пришёл к концепции слоёв, которые устанавливаются в один компонент (OptionsView.qml), реализующий интерфейс доступа к настройкам объекта. Дальше всё просто:

    function changeProperty(propertyName, propertyValue) {
        var currentItem = peScene.currentItem
        if (!currentItem) return

        var propertyList = propertyName.split(".")
        if (propertyList.length > 1) {
            currentItem[propertyList[0]][propertyList[1]] = propertyValue
        } else {
            currentItem[propertyName] = propertyValue
        }
    }

Ещё один неоднозначный момент: настройка групп. У ParticlePainter и аффекторов есть свойство groups, которое задаётся объектом типа list<string>. Эмиттер испускает частицы какой-то одной группы, соответственно, у него есть поле group типа string. По умолчанию groups === [] и group === "", эмиттер испускает все частицы, группа которых не задана. Аффектор, в свою очередь, по умолчанию так же действует на все группы частиц. Что происходит, когда пользователь нажимает на поле для ввода текста, желая изменить свойство groups? Правильно — groups становится равным [""] и перестаёт действовать на что-либо вообще. Я решил это следующий образом:

        onTextChanged: {
            var groupsArray = text.split(",")
            if (groupsArray.length === 1) {
                if (groupsArray[0] === "") propertyChanged("groups", []);
                else propertyChanged("groups", groupsArray)
            } else propertyChanged("groups", groupsArray)
        }

Вообще, там местами встречаются интересные, на мой взгляд, решения, но, так как я не являюсь знатоком JavaScript, наверняка, некоторые из них покажутся кому-то костылями. В любом случае, буду рад любому проявлению интереса — от комментариев до сообщений о багах.

Кстати, если вы удалите частицы (в Manage Particles) группы, которая в данный момент присутствует на сцене, приложение упадёт. Оно и понятно — кому придёт в голову такое при разработке игры, а вот в редакторе оно оказалось возможным. Ещё более неочевидный случай: создаёте частицы группы «a», создаёте для этой группы эмиттер, меняете group на что-то другое, удаляете частицы группы «a», задаёте любому эмиттеру group «a»… и снова ловите сегфолт. На данный момент я уверен, что проблема не в моём коде, но мало ли, с багрепортом пока решил повременить.

Репозиторий: https://bitbucket.org/wearyinside/qml-particle-editor (лицензия, напомню, GPLv3)
Работает приложение через qmlscene, .pro файл пока не прикладываю, будет позже. Если кому-то очень нужно, готов предоставить бинарные сборки для Linux/X11 и Windows.

Автор: epicfailguy93

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js