9

我在对 LibGdx Stage 对象中的 Actor 进行排序时遇到问题。当舞台被渲染时,图像会按照它们添加的顺序被渲染。Stage 使用一个数组来保存 Actor。我已经尝试设置每个 Actor 的 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());

它给了我以下错误并且不会编译:

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

我不知道我做错了什么。谁可以给我解释一下这个?

4

8 回答 8

19

而不是接受的答案,我更喜欢准备几个“层”组,然后以我喜欢的任何顺序添加到这些组中。

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, ...) 并将它们按顺序添加到阶段。然后派生类可以在不考虑顺序的情况下向这些层添加内容。

于 2013-07-09T21:07:47.210 回答
12

看起来您的代码Stage.getActors()返回一个ArrayofActors而不是一个List. Collections.sort()方法只接受列表。尝试:

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

来自@James Holloway 的排序更新(通过问题中的 z-index): z-index 被舞台覆盖,无论数组的内部顺序是什么。因此,设置 Z-Index 没有任何效果,除非您将其设置为高于列表的长度,然后它只是将图像放在列表的顶部(内部 Stage 会这样做)。这可以通过按名称或 ID 排序来解决。

于 2013-04-21T09:57:31.567 回答
2

我让所有演员扩展了一个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() );

于 2017-05-02T20:00:53.067 回答
0

可能不适合所有情况,但我使用 LibGdx Actor.userObject 来存储我的 z-index,然后根据它进行自动排序。在您的 Screen 或 Game 类中:

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 方法(不是 stage.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);

这也将避免在每次渲染调用时对数组进行排序。希望能帮助到你!

于 2015-04-11T07:22:14.203 回答
0

我的解决方案在快速测试中适用于我,但可能仍然存在一些缺陷。如果人们发现任何东西,请大声喊叫,但这对我来说效果很好,而且很轻。

我只在我的卡片上运行它(我正在写一个纸牌游戏)所以它只调整舞台上的卡片类,它们可能总是高于其他东西,比如表格/标签等。

我在int zIndex我的类中添加了一个本地,它在 Comparator 中使用,并在 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;
    }
}
于 2016-01-03T14:34:31.757 回答
0

不确定这是否是最近添加的,但对我有用的只是调用sort演员数组:

gameStage.getActors().sort(new ActorRenderComparator());

然后ActorRenderComparator可能看起来像这样:

public class ActorRenderComparator implements Comparator<Actor> {
    @Override
    public int compare(Actor a, Actor b) {
        if (a.getY() == b.getY()) {
            return 0;
        }

        if (a.getY() > b.getY()) {
            return -1;
        }

        return 1;
    }
}
于 2020-08-14T15:08:51.047 回答
0

最简单的解决方案!我很惭愧,我花了这么长时间才想出这个……

创建一个扩展 Stage 的“ZStage”类。覆盖 getActors 方法。根据演员的 Y 指数对演员进行冒泡排序,以获得他们的渲染顺序。

公共类 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;
}

}

于 2017-04-15T19:22:56.867 回答
0

我使用了一些浮点值来对我的玩家进行排序。数值越大,玩家的指数越高。这是我的片段:-

    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--;
    }
于 2015-12-31T06:45:13.040 回答