Как вы сортируете актеров на сцене 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() );