as3 - Как сортировать объекты отображения, которые постоянно меняют глубину?

У меня есть 2.5D-игра (2D-игра, которая действует как 3D-игра), в которой вы постоянно переключаете глубину, где игрок отображается поверх объекта, когда он идет перед ним, а когда он идет позади него, объект отображается сверху игрока. Например, когда у игрока меньше, чем у объекта, игрок будет идти за объектом и наоборот.

Я пытался использовать такой код:

if (player.y < block.y)
{
    setChildIndex(block, numChildren - 5);
}
else if (player.y > block.y)
{
    setChildIndex(block, numChildren - 10);
}

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


person Crook    schedule 30.12.2015    source источник
comment
используйте сортировку стека по z-индексу, то же самое, что используется для создания эффекта трехмерной глубины с использованием только двухмерных методов, другими словами, назначьте каждому объекту zIndex и через равные промежутки времени запустите процедуру z-sorter, которая сортирует отображаемые объекты на основе их значения z-индекса   -  person Nikos M.    schedule 30.12.2015


Ответы (1)


Используйте сортировку стека z-index (также называемую z-buffer в литературе по 3D-графике) то же используется для создания эффекта трехмерной глубины с использованием только двухмерных методов.

Другими словами, назначьте каждому объекту zIndex и через равные промежутки времени (например, событие onEnterFrame) запустите подпрограмму zsort, которая сортирует (порядок) отображаемых объектов на основе их значения zIndex. Или, в качестве альтернативы, вы можете запускать подпрограмму zsort вручную каждый раз, когда происходит изменение zIndex на объектах.

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

Хитрость здесь заключается в том, чтобы иметь соответствующие промежутки (т. е. не обязательно следующие zIndex+1) в значениях zIndex, присвоенных объектам, чтобы объекты можно было размещать между этими промежутками, чтобы имитировать прохождение впереди или позади других объектов, без > каждый раз приходится корректировать более одного значения zIndex, т.е. вы корректируете только одно значение zIndex объекта, проходящего впереди или позади другого объекта, а не zIndex этого другого объекта.

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

вот очень простая процедура zsorter, которая периодически запускает событие onEnterFrame и выполняет для вас необходимую сортировку по глубине (из ссылки 1. ниже)

package {

 import flash.display.*;
 import flash.events.*;

 public class DepthSortSpace extends MovieClip {

  public function DepthSortSpace() {
   super();
   this.addEventListener( Event.ADDED_TO_STAGE, this.addedToStage, false, 0, true );
  }

  private function addedToStage( e:Event ) {
   this.stage.addEventListener( Event.ENTER_FRAME, this.enterFrame, false, 0, true );
  }

  private function sortDisplayList():void {
   var len:uint = numChildren;
   var i,j;
   for( i=0; i < len-1; i++ )
    for (j=i+1; j < len; j++)
     if ( getChildAt(i).y > getChildAt(j).y ) this.swapChildrenAt( i, j );
  }

  private function enterFrame(e:Event) {
   this.sortDisplayList();
  }

 }
}

Вышеприведенный zsorter на самом деле является movieClip, который действует как контейнер scene, поскольку вы добавляете свои объекты отображения в zsorter movieClip, и это заботится о их соответствующей сортировке, но можно просто взять процедуру zsort и применить ее к любому DisplayObjectContainer или Scene экземпляр объекта.

Примечание. zsorter выше использует алгоритм сортировки bubbleSort, который имеет O(n^2) сложности, но можно использовать и другой алгоритм сортировки (например, mergeSort со сложностью O(n lgn))

примеры и ссылки

  1. http://nephilim.blogspot.gr/2010/06/easy-depth-sorting-in-actionscript-3.html
  2. http://www.actionscript.org/forums/actionscript-3-0-a/169035-sorting-technique.html
  3. http://www.simppa.fi/blog/the-fastest-way-to-z-sort-and-handle-objects-in-as3/
person Nikos M.    schedule 30.12.2015
comment
Это на самом деле очень круто! Не могли бы вы объяснить, что такое super(); предполагается делать? Спасибо. - person Crook; 31.12.2015
comment
super() вызывает конструктор родительского класса мувиклипа, поскольку zsorter расширяет класс мувиклипа, он гарантирует, что конструктор мувиклипа также вызывается (через вызов метода super) - person Nikos M.; 31.12.2015