Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   Общие вопросы о Flash (не затрагивающие ActionScript) (http://www.flasher.ru/forum/forumdisplay.php?f=60)
-   -   Группировка объектов (http://www.flasher.ru/forum/showthread.php?t=187201)

AlexLucas 15.11.2012 14:51

Группировка объектов
 
Доброго времени суток.
Столкнулся с задачей сгруппировать объекты на сцене, чтобы их можно было вместе растягивать, крутить и перемещать.

И в принципе есть два решения :

1) Засовывать их в новый Sprite. Это облегчит существенно процесс вращения и растягивания, но для того чтобы добавить элемент в группу, нужно будет его "изъять" со сцены (заморочка с add(remove)Element / add(remove)Child во флексе) и добавить в мувик, при этом подгонять ему новые координаты чтобы визуально он остался на той же позиции. А в случае с вложенными группами это может превратиться в нехилый геморрой. Также что касается растягивания (поэкспериментировал со спрайтами) , то тоже всё автоматом будет сжиматься / растягиваться.

2) Объединять их в группы с помощью ассоциативных массивов. Т.е. каждому элементу задать свой groupID, и при клике на него, выделять всю группу (перетаскивать / вращать итд).
Существенно упрощает работу с координатами, в принципе я реализовал в этом случае всё кроме вращения.
Но при вращении придётся вращать каждый элемент вокруг своей оси и вокруг центра тяжести группы (который можно будет перетаскивать), что обещает доставить немало хлопот. При растягивании придётся учитывать смещение по x и y и изменение ширины/высоты. Кроме того, при операциях с целой группой придётся в цикле проматывать все элементы : скажем, при перетаскивании придётся обновлять координаты всех элементов группы, и элементов вложенных групп, итд.

У меня вопрос - какой из вариантов будет жрать меньше ресурсов? Конечно многое зависит от реализации, но всё же?
И может есть третий вариант, который намного проще и я попусту бьюсь головой об батарею ?
Заранее спасибо.

maxkar 16.11.2012 02:31

Цитата:

Сообщение от AlexLucas (Сообщение 1104539)
Но при вращении придётся вращать каждый элемент вокруг своей оси и вокруг центра тяжести группы (который можно будет перетаскивать), что обещает доставить немало хлопот.

Почему? Это банальное домножение матриц трансформации на одну и ту же матрицу. Если не ошибаюсь, домножать нужно будет слева.
Цитата:

У меня вопрос - какой из вариантов будет жрать меньше ресурсов? Конечно многое зависит от реализации, но всё же?
Сколько у вас будет элементов? Групп? Глубина вложенных групп? Количество перемещений? Количество вращений? У меня есть сильные подозрения, что основные проблемы доставит рендеринг вашего хозяйства на экран после перемещения, а не сам проход по элементам в группе (если там сильно не накосячить). А разницы между движением через спрайт и каждого отдельного спрайта особой не будет. Там в одном случае умножение на матрицу-трансформатор будет делать флеш-плеер, а во втором - то же самое вы вручную. В общем, на отдельных объектах будет на одно умножение меньше (что не принципиальнь, если только у вас нет вложенности в несколько тысяч групп, на дне которой всего один элемент). Ну и техники вроде cacheAsBitmap вы для группы использовать не сможете на отдельных спрайтах.
В вашем случае правильное решение не заботится пока о быстродействии отрисовки, но принять меры для возможности замены способа отображения (спрайт или отедльные спрайты на экране) без изменения остальной логики. Простыми словами, отделить Model+Controller от View. Model от изменения способа отображения у вас измениться не должен. А потом уже по месту решать, что делать со view.
Цитата:

И может есть третий вариант, который намного проще и я попусту бьюсь головой об батарею?
Ну так матрицы же. Ключевые слова: линейная алгебра, аналитическая геометрия, линейное пространство, операторы над линейными пространствами. Первый курс (технические вузы). ЛинАл и АнГем в нужном объеме идут обычно в одном учебнике. Какие-то вещи можно пропустить (не нужны определители, метрические пространства и все, что с ними связано, кривые второго порядка).
Все ваши действия делаются элементарным домножением слева на матрицу трансформации. Т.е. была у объекта матрица Mo, стала Mt*Mo, где Mt - матрица преобразования. Для поворотов/сдвигов строится легко. Для перекоса (skew) повернутой группы (в координатах группы) чуть-чуть сложнее (добавится обратная матрица текущего преобразования группы). Соответственно, если у вас объекты собраны в одну группу, умножается только матрица группы. Если разобрана - матрицы отдельных элементов группы. Mt в этом случае - одна для всех таких элементов вне зависимости от вложенности!
Ну и на всякий случай - никакой магии там нет. Эффективная матрица для объектов в группе строится путем умножения на внешние матрицы групп :). Т.е. в одном случае у вас было Mg1*Mg2*Mob=Mobj1 (g1, g2 - группы, Mob- матрица трансформации объекта в группе g2, Mg2 - трансформация группы g2 относительно g1, Mg1 - трансформация g1 относительно сцены, Mobj1 - трансформация объекта относительно сцены). Очевидно, что из этого следует, что (Mt*Mg1)*(Mg2*Mob)=Mt*(Mg1*Mg2*Mob)=Mt*Mobj1, так что с точки зрения чистой математики без разницы, кого на что домножать.
С точки зрения реализации я бы хранил отдельные матрицы трансформации для групп и объектов внутри группы. Для визуализации - как угодно. Можно складывать в спрайты (может быть, ставить им cacheAsBitmap). Можно раскладывать индивидуальные листья, вычисляя эффективную матрицу. Для трансформаций есть небольшое отличие, связанное с точностью вычислений. При использовании индивидуальных матриц из-за потери точности объекты внутри группы могут начать "разъезжаться" относительно друг друга. Т.е. после какого-то количества поворотов, например, квадрат перекосится. Причем вернуть объекты "в исходное состояние" уже не получится. А в группе (с отдельной матрицей) можно будет сбросить трансформацию группы и объекты станут квадратными. Хотя вы артефакты из-за точности вряд ли заметите, чтобы что-то накопилось, нужно быть или очень везучим (чтобы сразу создать матрицу трансформации, которая даст артефакт), или очень долго и нудно крутить объект (миллионы и миллиарды раз).

Всякие rotation/scaleX/scaleY/x/y у визуального объекта вам не нужны. Совсем. Вам нужны матрицы. При желании преводить координаты из одних систем в другие (ну мало ли где нужно, для вывода на экран, например) используются те же матрицы преобразования объектов. В матрицах все прекрасно пишется и работает. Прием все операции (повотот, сдвиг, масштабирование, перекос (skew)) - все это домножения на матрицы, только матрицы разные. Соответственно, выбор и формирование матрицы делается при выборе операции, а затем на модель просто применяется операция (applyTransform(Matrix), например).

AlexLucas 16.11.2012 18:57

Ну архитектура моего приложения скорее MVP чем MVC.
А что касается матриц, ведь всё кроме skew и shear можно осуществить элементарным rotation / x / y / scale.

Вы видимо объяснили мне как растягивать пропорционально целую группу элементов, но я так и не понял :
К примеру растягиваем группу с width 200 и height 300 так что в итоге её width изменяется на 10, height на 20.
Какую матрицу применить ко всем элементам этой группы чтобы они также пропорционально растянулись ?

Сделал но при scaleX и Y текстовых полей текст искажается ( в растре) / меняет размер шрифта (в векторе)

maxkar 17.11.2012 16:06

Конкретная архитектура не слишком принципиальна. Главное, чтобы вид был отделен от модели и его было просто поменять. Матрицами проще работать, чем scale/x/y/rotation. Через них все преобразования делаются единообразно и комбинации преобразований тоже легко выражаются. Через x/y/scale/rotation повотор вокруг произвольной точки, например, не так просто делается (для уже повернутого объекта).

Со скейлом все просто. Пусть мы скейлим относительно точки x, y. Тогда матрица будет
Код:

|1 0 x|  |sx 0  0|  |1 0 -x|
|0 1 y| * |0  sy 0| * |0 1 -y| = Ms
|0 0 1|  |0  0  1|  |0 0  1|
sx = 210 / 200, sy = 320 / 300

Соответственно, там все нужно умножить. X и Y при этом параллельны X и Y соответствующей области. Если мы скейлим повернутую группу, там все похоже. Если группа имеет трансформацию относительно сцены Mgt, то указанный скейл в координатах группы (визуально повернутый прямоугольник растягивается) будет Mgt*Ms*(Mgt^-1). Т.е на эту матрицу тоже можно умножать все объекты из группы и они попадут в правильную позицию (но тогда на матрицу группы мы отдельные элементы для получения эффективной матрицы не умножаем, естественно).

С текстом не совсем понятно, что именно вы хотите. Я бы как раз ожидал, что после скейла текст пропорционально уменьшится вместе со всеми остальными объектами группы. А иначе я нарисую кнопку, поскейлю, и она разъедется. Хотя вообще это тоже не большая проблема. Тоже решается матрицами :). Пусть Mf - эффективная матрица текстового поля (либо просто матрица, либо произведение всег групп на собственную матрицу, если работать с раздельными матрицами). Тогда вычисляем "систему координат" текстового поля в экранных координатах.
Код:

          |1|        |0|            |0|        |0|      |x' 0  0|
xs = Mf * |0| - Mf * |0|, ys = Mf * |1| - Mf * |0|, Mt = |0  y' 0|
          |1|        |1|            |1|        |1|      |0  0  1|
x' = 1/sqrt(xs*xs), y' = 1/sqrt(ys*ys)

xs, ys - единичные вектора текстового поля в экранной системе координат. x', y' - нормирующие коэффициенты (вы же хотите, чтобы длины единичных отрезков сохранялись, поэтому они так и выбраны). Поэтому нужно еще домножить матрицу трансформации справа (именно справа!) на Mt. А еще умножить "исходную" ширину текстового поля на x' и высоту на y' (потому что относительно текста они изменились). Итоговая матрица для вывода текста будет (Mf * Mt). Все преобразования меняют только Mf! Mt (а также x' и y') вычисляются только в момент вывода текста на экран (при рендеринге) и пересчитывается при изменении Mf. Очевидно, что текст "относительно группы" при таких требованиях может выглядеть совершенно не так, как относительно экрана.


Часовой пояс GMT +4, время: 08:41.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.