Как вы сортируете актеров на сцене libgdx?

у меня возникли проблемы с сортировкой актеров в объекте сцены LibGdx. Когда этап получает визуализацию, изображения отображаются в порядке их добавления. Сцена использует массив для удержания актеров. Я пробовал установить ZIndex каждого актера, но он все еще не сортировался. Затем я попытался создать объект-компаратор следующим образом:

public class ActorComparator implements Comparator < Actor > {
    @Override
    public int compare(Actor arg0, Actor arg1) {
        if (arg0.getZIndex() < arg1.getZIndex()) {
            return -1;
        } else if (arg0.getZIndex() == arg1.getZIndex()) {
            return 0;
        } else {
            return 1;
        }
    }
}

а затем, когда я хочу сделать фактическое сравнение, я сделал:

Collections.sort(Stage.getActors(), new ActorComparator());

Это дает мне следующую ошибку и не compile:

The method sort(List<T>, Comparator<? super T>) in the type Collections 
is not applicable for the arguments (Array<Actor>, ActorComparator)

Я понятия не имею, что я делаю неправильно. Кто-нибудь может мне это объяснить?

7 ответов


похоже на ваш код Stage.getActors() возвращает Array of Actors вместо List. Collections.sort() метод принимает только списки. Попробуйте:

Collections.sort(Arrays.asList(Stage.getActors().toArray()), new ActorComparator());

обновление по сортировке (по Z-индексу в вопросе) от @James Holloway: Z-индекс переопределяется этапом, чтобы быть любым внутренним порядком массива. Таким образом, установка Z-индекса не имеет никакого эффекта, за исключением случая, когда вы устанавливаете его выше длины списка, а затем просто помещаете изображение поверх списка (внутренняя стадия делает это). Это решается сортировкой по имени или ID.


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

Group bg = new Group();
Group fg = new Group();
// the order is important in the following two lines
stage.addActor(bg); 
stage.addActor(fg); 

bg.addActor(whatever);
fg.addActor(whatever);
bg.addActor(whatever);
fg.addActor(whatever);

(конечно addActor() заказ все вопросы между элементами bg, и между элементами fg, но не между элементом fg и элемент bg.)

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


вероятно, не подходит для всех случаев, но я использую libGDX Actor.userObject для хранения моего z-индекса, а затем автоматической сортировки на основе этого. В вашем экране или классе игры:

class ActorZOrderComparator implements Comparator<Actor> {
    @Override
    public int compare(Actor o1, Actor o2) {
        if (o1 != null && o1.getUserObject() != null && o1.getUserObject() instanceof Integer
                && o2 != null && o2.getUserObject() != null && o2.getUserObject() instanceof Integer) {
            int z1 = (Integer) o1.getUserObject();
            int z2 = (Integer) o2.getUserObject();
            return z1 - z2;
        } else if (o1 != null && o2 != null) {
            return o1.getZIndex() - o2.getZIndex();
        } else if (o1 != null) {
            return -1;
        } else if (o2 != null) {
            return 1;
        } else {
            return 0;
        }
    }
}

protected ActorZOrderComparator zOrderComparator = new ActorZOrderComparator();
private boolean invalidZOrder;

protected void addActor(Actor actor) {
    stage.addActor(actor);
    if (actor.getUserObject() instanceof Integer) {
        invalidZOrder = true;
    }
}

@Override
public void render(float delta) {
    if (invalidZOrder) {
        Arrays.sort(stage.getRoot().getChildren().begin(), zOrderComparator);
        stage.getRoot().getChildren().end();
        invalidZOrder = false;
    }
}

а затем вы добавляете актеров, используя новый метод addActor (не этап.addActor):

Image leftBar = new Image(skin, "leftBar");
    leftBar.setPosition(0, GameSettings.VIEWPORT_HEIGHT * 0.5f, Align.left);
    leftBar.setUserObject(1); // <-- this is the z-index, set it before calling addActor(..)
    addActor(leftBar);

Это также позволит избежать сортировки массива при каждом вызове рендеринга. Надеюсь, это поможет!


я использовал некоторое значение float для сортировки моих игроков. Чем больше значение, тем выше индекс игрока. Вот мой фрагмент:-

    Map<Actor, Float> map = new HashMap<Actor, Float>();
    map.put(playerActor, playerArea);
    for (int i = 0; i < totalEnemies; i++) {
        if (i != playerImageNo) {
            map.put(enemyActor[i], enemyArea[i]);
        }
    }
    int noOfPlayers = map.size();

    // Sort Map based on values(size)
    Set<Entry<Actor, Float>> set = map.entrySet();
    List<Entry<Actor, Float>> list = new ArrayList<Entry<Actor, Float>>(set);
    Collections.sort(list, new Comparator<Map.Entry<Actor, Float>>() {
        @Override
        public int compare(Map.Entry<Actor, Float> o1,
                Map.Entry<Actor, Float> o2) {
            return (o2.getValue()).compareTo(o1.getValue());
        }
    });

    for (Map.Entry<Actor, Float> entry : list) {
        entry.getKey().setZIndex(noOfPlayers);          
        System.out.println("Player: " + entry.getKey() + ", index: " + noOfPlayers);
        noOfPlayers--;
    }

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

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

я добавил местный int zIndex моему классу, который используется в компараторе и установлен на начало метода setZIndex.

начальная часть метода извлекается из оригинала в классе Actor.

@Override
public void setZIndex(int index) {
    this.zIndex = index;
    if (index < 0) throw new IllegalArgumentException("ZIndex cannot be < 0.");
    Group parent = this.getParent();
    if (parent == null) return;
    Array<Actor> children = parent.getChildren();
    if (children.size == 1) return;
    ArrayList<Card> allCards = new ArrayList<Card>();
    for(Actor child : children) {
        if(child instanceof Card) {
            allCards.add((Card)child);
        }
    }
    Collections.sort(allCards, new ZIndexComparator());
    for (Card card : allCards) {
        children.removeValue(card, false);
        children.add(card);
    }
}

class ZIndexComparator implements Comparator<Card> {
    public int compare(Card card1, Card card2) {
        return card1.zIndex - card2.zIndex;
    }
}

САМОЕ ПРОСТОЕ РЕШЕНИЕ!! Мне стыдно, что мне потребовалось столько времени, чтобы придумать это...

создайте класс "ZStage", который расширяет Stage. Переопределите метод getActors. Bubble-сортировка актеров на основе их индекса Y, чтобы получить их порядок рендеринга.

public class ZStage расширяет этап {

public ZStage(Viewport vp){
    super(vp);
}

@Override
/** Returns the root's child actors.
 * @see Group#getChildren() */
public Array<Actor> getActors () {
    SnapshotArray<Actor> children = getRoot().getChildren();

    boolean sorting = true;
    while(sorting){
        sorting=false;
        for(int x=0; x< children.size-1; x++){
            if(children.get(x).getY() < children.get(x+1).getY()){
                children.swap(x,x+1);
                sorting=true;
            }
        }
    }

    return children;
}

}


у меня все мои актеры расширить DepthActor класс, содержащий значение глубины и реализующий Comparable<DepthActor>:

import com.badlogic.gdx.scenes.scene2d.Actor;

import java.util.Comparator;

/**
 * @author snd
 * @since May 02, 2017
 */
public class DepthActor extends Actor implements Comparable<DepthActor>
{
  public int depth;

  @Override
  public int compareTo(DepthActor o)
  {
    return depth < o.depth ? -1 : (depth > o.depth ? 1 : 0);
  }
}

тогда сортировка на месте тривиальна:

com.badlogic.gdx.utils.Sort.instance().sort( stage.getActors() );