Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Оптимизация сортировки объектов в изометрии (http://www.flasher.ru/forum/showthread.php?t=153851)

Jewelz 09.04.2011 14:33

Оптимизация сортировки объектов в изометрии
 
Вложений: 1
перелопатил много существующих изо движков, но нашел пока только один самый стабильно работающих способ сортировки (к сожалению довольно медленный: 350 элементов ~80мс)

требуется помощь в оптимизации или в подборе другого алгоритма

исходные данные:
- 2d объекты с известными координатами в изометрическом мире (x,y) и габаритами (width, height), а также уровнем высоты, для упрощения сортировки "слоев"
- для нахождения крайних точек объектов используется класс Bounds со св-ми left=x, right=x+width, back=y, front=y+height

условия:
- сортировка должна происходить по изометрическим законам

и текущий алгоритм:
http://www.flasher.ru/forum/attachme...1&d=1302341473
Код AS3:

protected function sort(itemsToRender:Array):Array
{               
        //создаем копию исходного массива
        var list:Array = itemsToRender.slice(0);
 
        itemsToRender = [];
 
        var i:int;
        var j:int;
        var listLength:int = list.length;
 
        for (i = 0; i < listLength; i++)
        {
                //неотсортированный элемент
                var notSortedObj:IIsoItem = list[i] as IIsoItem;
                var notSortedObjBounds:Bounds = notSortedObj.bounds;
 
                var added:Boolean = false;
                var moLength:int = itemsToRender.length;
                for (j = 0; j < moLength; j++)
                {
                        var sortedObj:IIsoItem = itemsToRender[j] as IIsoItem;
                        var sortedObjBounds:Bounds = sortedObj.bounds;
 
                        //если хоть одна точка notSortedObj попадает в правый верхний квадрант sortedObj, то notSortedObj лежит ниже
                        if (notSortedObj.level == sortedObj.level && notSortedObjBounds.right > sortedObjBounds.left && notSortedObjBounds.back < sortedObjBounds.front)
                        {
                                itemsToRender.splice(j, 0, notSortedObj);
                                added = true;
                                break;
                        }else if (notSortedObj.level < sortedObj.level) {
                                itemsToRender.splice(j, 0, notSortedObj);
                                added = true;
                                break;
                        }
                }
 
                //если ни одно из условий не выполнилось, то объект лежит выше всех
                if (!added) itemsToRender.push(notSortedObj);
        }
 
        list = null;
 
        //возвращает отсортированные элементы
        return itemsToRender;
}


BlooDHounD 09.04.2011 18:05

проще поворачивать в другую сторону. тогда и координаты и рейтинг сортировки высчитывается проще.
расчёт рейтинга становится элементарным: x + y. у кого это число больше - тот ближе к экрану. принцип оптимизации сортировки тоже очень прост: составляешь массив, в котором у тебя лежат объекты с их рейтингами. индекс элемента в массиве должен соответствовать его в глубине на сцене. в этом случаи алгоритм в общем виде будет выглядеть так:
Код AS3:

/**
 * @private
 * контейнер, в котором отображается всё наше барахло
 */

private var _content:DisplayObjectContainer;
 
/**
 * хэш, где хранятся соответствия модели их вьюхам
 * model -> view
 */

private const _elements:Dictionary = new Dictionary();
 
/**
 * @private
 * храним рейтинги сортировки
 */

private const _sortings:Vector.<uint> = new Vector.<uint>();
 
/**
 * @private
 * принудительно обновляет позицию вьюхи относительно модели
 */

private function updatePosition(data:MapElement):void {
 
        // получаем ссылку на вьюшку
        var view:DisplayObject = this._elements[ data ];
 
        var x:Number = data.x;
        var y:Number = data.y;
 
        // изменяем координаты вьюшки
        view.x = ( x - y ) * COOEF_X;
        view.y = ( x + y ) * COOEF_Y;
 
        // получаем текущий индекс
        var lastIndex:uint = this._content.getChildIndex( view );
        var lastRating:uint = this._sortings[ lastIndex ];
        // новый рейтинг
        var newRating:uint = Math.round( x + y ) + COOEF_SORT; // считаем новый рейтинг сортировки
        // если рейтинг не изменился, то ничего не делаем
        if ( lastRating != newRating ) {
                // удаляем себя из списка
                this._sortings.splice( lastIndex, 1 );
                // найдём куда ставить и поставим
                var newIndex:uint = this._sortings.length;
                while ( --newIndex ) {
                        if ( this._sortings[ newIndex ] <= newRating ) break;
                }
                // вставляем новый индекс
                this._sortings.splice( i, 0, newRating );
                this._content.setChildIndex( view, newIndex );
        }
 
}

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

Jewelz 09.04.2011 18:24

Вложений: 1
>>x + y. у кого это число больше - тот ближе у экрану
если верно понял про поворот, то при следующей ситуации возникнет ошибка - объект с индексом 2 окажется ниже объекта с индексом 3

за наводку спасибо, думал про сортировку рейтингов, попробую

BlooDHounD 09.04.2011 19:55

эта ошибка возникнет независимо от поворота. это свойство объекта данной формы.
я привёл пример z-сортировки. она работает только для точек. объёмные объекты сложной формы невозможно отсортировать корректно во всех случаях. они должны соответствовать условиям:
1. они должны быть выпуклые
2. его формы должны приближаться к кругу.

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

p.s.: не пытайтесь сортировать объекты. сортируйте точки.

Добавлено через 39 секунд
ну либо пишите эвристические алгоритмы определения форм =)

Добавлено через 3 минуты
и да. на картинке перепутаны x и y =)

Котяра 09.04.2011 21:17

Разбивайте объект 2 на части согласно тайлам. Общую z считайте по максимальной из z частей.
UPD. хотя если использовать формулу x+y, то и 2 и 3 имеют рейтинг 8.
Надо подумать..

BlooDHounD 09.04.2011 21:32

Котяра, как ты высчитал их рейтинг не зная где находятся их центры?

Котяра 09.04.2011 21:52

Я же говорю, если по максимальным считать. Максимальный - это нижний угол (если принять бесконечно малый размер тайла)

expl 09.04.2011 21:57

Вложений: 1
Цитата:

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

Пути решения:
- внедрить топологический алгоритм (не лажает, вообще, даже если некоторые объекты пересекаются - остальные сортируются правильно, если впринципе можно отсортировать - сортурует) - максимум что удалось выжать - 200мс для 1000 и 1 мс для 100 объектов (сложность построения графа квадратная)
- не парится и использовать бинарную вставку - лажает не намного больше, зато бдет сортировать 1000 объектов за 1-5 мс.
- отказаться от прямоугольных объектов, возможно использование "почти прямоугольных":
Вложение 26418
- ухищрения с разрезаниями в стиле OpenSpace

P.S. Для сортировки изометрии на плоскости классической ситуации с невозможностью сортировки возникнуть не может (по-крайней мере я такую придумать не смог), даже если некоторые объекты пересекаются - остальные можно отсортировать.

Цитата:

p.s.: не пытайтесь сортировать объекты. сортируйте точки.
Эх, если бы это прокатывало для прямоугольников, а тем более для параллелепипедов.

BlooDHounD 09.04.2011 23:03

Цитата:

Эх, если бы это прокатывало для прямоугольников, а тем более для параллелепипедов.
см. ограничения.

Котяра 09.04.2011 23:17

линк на тему:
http://code.google.com/p/as3isolib/s...outRenderer.as
но выполнить правильную сортировку как в примере(good)
всё равно не получится
http://members.gamedev.net/osan/images/boxes.gif

mikhailk 09.04.2011 23:19

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

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

Это я к тому, что мы иногда решаем задачи более сложные, нежели требуется на самом деле.

BlooDHounD 09.04.2011 23:45

mikhailk, собственно я об этом с самого начала и говорил.

expl 09.04.2011 23:45

Цитата:

Сообщение от Котяра (Сообщение 988100)
линк на тему:
http://code.google.com/p/as3isolib/s...outRenderer.as
но выполнить правильную сортировку как в примере(good)
всё равно не получится
http://members.gamedev.net/osan/images/boxes.gif

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

Цитата:

Цитата:
Эх, если бы это прокатывало для прямоугольников, а тем более для параллелепипедов.
см. ограничения.
Ну да, ну да.
В альтернативном варианте можно заменить поиск ближайшего индекса на бинарный поиск, не всегда надо, но все-таки:
плюсы: гарантированное время n*log n при загрузке карты
минусы: Если перемещающихся больше чем стоящих на месте - log(n) это больше чем найти ближайший индекс за 1-2 шага (они ж не далеко за шаг уходят)
Зато, если бинарную вставку не использовать подморозим флешку алгоритмом со сложностью n * n при загрузке карты.

BlooDHounD 10.04.2011 00:39

Цитата:

- на плоскости такого не бывает.
расскажите это дереву и стене.

Добавлено через 1 минуту
и заодно расскажите чем мы подморозим флэшку моим алгоритмом?

expl 10.04.2011 01:07

Цитата:

Сообщение от BlooDHounD (Сообщение 988123)
расскажите это дереву и стене.

Более формально:
"Для любого количества объектов в виде прямогольных параллелепипедов любых размеров, если
1. они не пересекаются физически
2. нижней частью лежат на одной плоскости
всегда можно найти такой порядок отображения, при котором они будут правильно выглядеть в изометрической проекции"
(здесь речь не о конкретном алгоритме, а о принципиальной возможности)
Уверен на 95%

Цитата:

Сообщение от BlooDHounD (Сообщение 988123)
Добавлено через 1 минуту
и заодно расскажите чем мы подморозим флэшку моим алгоритмом?

допустим загружаем 1000 объектов
ложим 1-й - ищем ему место среди 0 объектов,
ложим 2-й - ищем ему место среди 1 объекта,
...
ложим n-1 -й - ищем ему место среди n-2 объектов
ложим n-й - ищем ему место среди n-1 объектов
Т.к. объекты добавляются в неотсортированном порядке - то поиск ближайшего объекта будет пропорционален n уже существущих
Т.е. общаяя сложность пропорциональна n*n. Что-то типа сортировки пузырьком получается.

А когда объекты уже отсортированы и на каждом шаге их относительное положение меняется несильно - новый индекс находится быстро. Просто на старте пик будет.

Нет, не совсем так, у Вас поиск идет, насколько понял, не от текущего индекса элемента, а от начала. Т.е. в любом случае сложность квадратная. Экономия достигается только за счет НЕсортировки неподвижных объектов.

BlooDHounD 10.04.2011 13:45

вы скажите сколько объектов должно быть, что на старте из-за моего алгоритма всё залипло. я могу гарантировать, что на 1К объектов всё залипнет не из-за сортировки, а из-за добавления на сцену большого количество графики.

я алгоритм писал прямо тут. вы ж понимаете, что вставить один иф, для ограниченного поиска при перемещении - дело 1 минуты?
и да скорость достигается за счёт того, что статика не изменяет своих рейтингов.

Добавлено через 9 минут
Цитата:

"Для любого количества объектов в виде прямогольных параллелепипедов любых размеров, если
1. они не пересекаются физически
2. нижней частью лежат на одной плоскости
другой алгоритм с другими ограничениями. просто 99% случаев не нужны эти самые ограничения. чаще нужно нарисовать дерево и стену. уверен на 100%.

expl 10.04.2011 14:07

Цитата:

вы скажите сколько объектов должно быть, что на старте из-за моего алгоритма всё залипло. я могу гарантировать, что на 1К объектов всё залипнет не из-за сортировки, а из-за добавления на сцену большого количество графики.

я алгоритм писал прямо тут. вы ж понимаете, что вставить один иф, для ограниченного поиска при перемещении - дело 1 минуты?
и да скорость достигается за счёт того, что статика не изменяет своих рейтингов.
Да, если вставить этот иф он может и уделать в нормальном режиме бинарный поиск.
А я и не говорю что Ваш алгоритм нежизнеспособен - я подобный много где видел и он отлично справлялся. Просто есть альтернативное решение - бинарный поиск (которому вообще плевать на состояние на карте - он всегда выдает стабильное время), только и всего.

Цитата:

другой алгоритм с другими ограничениями. просто 99% случаев не нужны эти самые ограничения. чаще нужно нарисовать дерево и стену. уверен на 100%.
Не совсем фразу понял.
Всмысле зашить порядок стены и дерева в локацию? Ну не знаю.
Если игра типа "город" - там пользователь сам распологает изометрические объекты и ему поставить их "неудобно для примитивной сортировки" не запретишь.

BlooDHounD 10.04.2011 14:43

Цитата:

Сообщение от expl
Да, если вставить этот иф он может и уделать в нормальном режиме бинарный поиск.

бинарный поиск - это очень абстрактное понятие. вы имеете ввиду оставить мою систему с рейтингами и изменить алгоритм поиска в массиве? просто если так, то бинарный поиск будет периодически спотыкаться на элементах с одинаковым рейтингом. и будем наблюдать моргающие объекты. да и с двигающемся персонажем, где индекс меняется +/-5 на 1К элементов, это совершенно излишне.
Цитата:

Сообщение от expl
Всмысле зашить порядок стены и дерева в локацию?

в смысле: "все объекты не пересекающиеся прямоугольники" - это сильное ограничение, это значит, что в рядом с размашистом деревом нельзя ставить куст.

expl 10.04.2011 20:00

Цитата:

Сообщение от BlooDHounD (Сообщение 988218)
бинарный поиск - это очень абстрактное понятие. вы имеете ввиду оставить мою систему с рейтингами и изменить алгоритм поиска в массиве? просто если так, то бинарный поиск будет периодически спотыкаться на элементах с одинаковым рейтингом. и будем наблюдать моргающие объекты. да и с двигающемся персонажем, где индекс меняется +/-5 на 1К элементов, это совершенно излишне.

Именно поиск в массиве и имею ввиду. Проблема когда перс стоит на кусте и мигает действиельно существует - решается дополнительными приоритетами сортировки, кроме координаты.
Короче, +1 в пользу простого поиска.
Цитата:

Сообщение от BlooDHounD (Сообщение 988218)
в смысле: "все объекты не пересекающиеся прямоугольники" - это сильное ограничение, это значит, что в рядом с размашистом деревом нельзя ставить куст.

А если пареллелепипеды пересекающиеся - то впринципе не врезав их один в другой нормально отобразить в _общем_ случае не получиться.

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

Еще эта честная сортировка с такой производительностью практически не применима (100-200 сортируемых объектов - это мало даже для социалок)
Похоже все, кому нужны прямоугольные объекты, юзают какие-то хаки, потому что не смог найти ни одного НЕлажащего алгоритма, даже сортировка из книги ActionScript for Multiplayer Games and Virtual Worlds ошибается на достаточно простых ситуациях.

mikhailk 10.04.2011 22:55

Я так понимаю, надо все-таки определиться, какая задача решается. Задача сортировки объектов для социалки типа "город", на мой взгляд, элементарная, поскольку объекты-здания стационарные, а движущиеся объекты типа людей-машинок - мелкие и не отягощенные анимацией. Такую задачу вполне можно решить в общем виде.

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

TERRORist 10.04.2011 23:42

Чем проще, тем лучше)
[IMG]http://img25.**************/img25/9601/depth.png[/IMG]

dimarik 10.04.2011 23:46

это вроде и есть x + y

TERRORist 10.04.2011 23:50

ну да, тольно это maxX*y + x. Просто (x + y) ничего не даст.

Сортирует только точки, не прямоугольники.

Я тред не читал, как то лень, сортировки какие то...

Принцип KISS такой есть - keep it stupidly simple.

setChildIndex (mc, maxX*mc.y + mc.x); // - и все)

mikhailk 10.04.2011 23:54

Цитата:

Чем проще, тем лучше)
исходя из этого рисунка достаточно сортировать по y :)

а, нет, понял
да, в этом случае y*maxX+x

но это не изометрия

TERRORist 10.04.2011 23:58

почему не изометрия?
Я ж рисовал изометрические кубики, старался...

BlooDHounD 11.04.2011 00:03

в изометрии не работают с прямыми координатами.

TERRORist 11.04.2011 00:05

ну, их можно перевести в координаты экрана и обратно, если оч хочется.Только что это поменяет?

dimarik 11.04.2011 00:14

Изометрия — это лишь способ представления трехмерного пространства. Решаемый, например, матричными преобразованиями.

mikhailk 11.04.2011 00:41

Цитата:

Я ж рисовал изометрические кубики, старался...
Ромбики. :)
Там рулят ромбики.

http://img-fotki.yandex.ru/get/5701/...91d_da5c377f_L

Это я как раз решал аналогичную проблему :)

TERRORist 11.04.2011 01:00

а чтоб решить проблему, описанную на первой странице (картинка котяры Bad и Good), нужно оперировать отдельными гранями, а не фигурами в целом.

BlooDHounD 11.04.2011 02:52

ваще фигурами. твоя "изометрия" заставляет делать кучу преобразований, а всеобщая - нет.

TERRORist 11.04.2011 12:55

в каком смысле кучу преобразований? Спрайты в конечном счете имеют экранные координаты

объясните мне плиз, как отсортировать три фигуры на картинке Good, не разбивая их на грани. я не понимаю.

BlooDHounD 11.04.2011 13:05

TERRORist, никак. собственно об этом весь трэд.

kutuzov 17.05.2011 19:40

тоже столкнулся с проблемой производительности
в as3isolib есть дефолтный лэйаут рендерер, который сортирует чайлды
я оставил логику, но переписал с поддержкой apparat
увеличилась производительность в среднем в 3-4 раза
на 400 объектах со 120мс до 35-40мс

mikhailk 18.05.2011 00:14

На какой технике?
Если социалку пишете - тестируйте на нетбуках.

kutuzov 18.05.2011 00:28

нетбуков не имею, у меня коре два дуо 2.53, 4гб
рендерю не каждый кадр, а когда персы встают ровно в клетку сетки, этого достаточно, ну и цель была избавиться от залипаний в момент сортировки, аппарат помог

mikhailk 18.05.2011 00:48

Тут как бы есть объективная реальность
Связка нетбук+WinXP+1Гб памяти дает ужасающую производительность
Все будет шевелиться в два-три раза медленнее, чем наблюдаете на своем "коре два дуо 2.53, 4гб"

Но это так, не для дискуссии
Просто увидел "35-40мс"


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

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