Представляю ещё один свой проект, на этот раз, — opensource (лицензия GPLv3).
QML Particle Editor — редактор частиц, десктопное приложение, написанное целиком на QML.
Не знаю, как вы, а я Qt Quick Designer (известный также, как qml2puppet) обычно не использую, глючный он, да и руками мне удобнее писать. Беглый обзор показал, что для работы с частицами QML до сих пор ничего специфичного нет и не ожидается, поэтому за время новогодних праздников запилил свой редактор.
Зачем это нужно? Удобнее изменять свойства и тут же видеть результат, чем вслепую править код и гадать, почему внешне ничего не изменилось. Само собой, для того, чтобы делать крутые штуки вроде тех, что лежат в демо-приложенях, придётся вникнуть во взаимосвязь компонентов и разобраться в свойствах, без этого не обойтись. Хотя, основу, например, можно набросать в редакторе, а плюшки вроде ColorAnimation on color
прописать уже руками, так как всё, что делает мой редактор — позволяет создать сцену и получить её QML код, который сразу можно использовать в любом проекте.
Подробности реализации и ссылка на репозиторий — под катом.
Для начала — схема компонентов модуля QtQuick.Particles 2.0, с которыми придётся иметь дело:
Всё просто: есть система частиц и 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.
Большинство атрибутов являются числовыми или текстовыми, но есть и такие, которые задаются объектами (например, 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