简体   繁体   English

你如何在 libgdx Stage 中对 Actor 进行排序?

[英]How do you sort Actors in a libgdx Stage?

I'm having trouble sorting Actors in a LibGdx Stage object.我在 LibGdx Stage 对象中对 Actor 进行排序时遇到问题。 When the Stage gets rendered the images are rendered in the order they are added.当舞台被渲染时,图像会按照它们添加的顺序进行渲染。 Stage uses an Array to hold the Actors. Stage 使用一个 Array 来保存 Actors。 I've tried setting the ZIndex of each Actor, but it still didn't sort.我已经尝试设置每个 Actor 的 ZIndex,但它仍然没有排序。 Then I tried creating a comparator object like this:然后我尝试创建一个像这样的比较器对象:

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;
        }
    }
}

and then when I want to do the actual comparison I did:然后当我想做实际比较时,我做了:

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

It gives me the following error and won't compile:它给了我以下错误并且无法编译:

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

I have no clue what I'm doing wrong.我不知道我做错了什么。 Can someone explain this to me?谁可以给我解释一下这个?

Rather than the accepted answer, I like it better to prepare several "layer" groups, then adding to those group in whatever order it pleases me.与接受的答案相比,我更喜欢准备几个“层”组,然后按照我喜欢的任何顺序添加到这些组中。

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);

(Of course the addActor() order still matters among elements of bg , and among elements of fg , but not between an element of fg and an element of bg .) (当然所述addActor()顺序仍的元素之中事项bg ,和的元素之中fg ,但不是的元件之间fg和的元素bg )。

This workflow works well in an inheritance scenario, where the base class owns protected Group layers ( this.bg , this.fg , ...) and adds them in order to the stage.此工作流在继承场景中运行良好,其中基类拥有受保护的 Group 层( this.bgthis.fg 、...)并将它们按顺序添加到舞台中。 Then the derived class can add things to those layers without taking care of the order.然后派生类可以在不考虑顺序的情况下向这些层添加内容。

Looks like your code Stage.getActors() returns an Array of Actors instead of a List .看起来您的代码Stage.getActors()返回了一个Actors Array而不是一个List Collections.sort() method accepts only Lists. Collections.sort()方法只接受列表。 Try:尝试:

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

Update on sorting (by z-index in the question) from @James Holloway: z-index is overridden by the stage to be whatever the internal order of the Array is.来自@James Holloway 的排序更新(按问题中的 z-index): z-index 被舞台覆盖,无论数组的内部顺序是什么。 So setting the Z-Index has no effect, except in the case that you set it as higher than the length of the list and then it just puts the image on top of the list (internal Stage does this).因此,设置 Z-Index 没有任何影响,除非您将其设置为高于列表的长度,然后它只是将图像放在列表的顶部(内部 Stage 会这样做)。 This is solved by sorting by name or ID.这是通过按名称或 ID 排序来解决的。

I have all my actors extend a DepthActor class that contains a depth value and implements Comparable<DepthActor> :我让所有演员都扩展了一个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);
  }
}

Then sorting in place is trivial:然后就地排序是微不足道的:

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

Probably not suitable for all cases, but I'm using LibGdx Actor.userObject for storing my z-index, and then auto sorting based on that.可能并不适合所有情况,但我使用 LibGdx Actor.userObject 来存储我的 z-index,然后基于它进行自动排序。 In your Screen or Game class:在你的 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;
    }
}

and then you add actors using the new addActor method (not stage.addActor):然后使用新的 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);

This will also avoid sorting the array on each render call.这也将避免在每次渲染调用时对数组进行排序。 Hope it helps!希望能帮助到你!

I have used some float value to sort the my players.我使用了一些浮点值来对我的球员进行排序。 Larger the value higher the index of the player.值越大,玩家的指数越高。 Here is my snippet:-这是我的片段:-

    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--;
    }

My solution works for me in quick tests but there may still be some flaws.我的解决方案在快速测试中对我有用,但可能仍然存在一些缺陷。 If people spot anything then please shout, but this works well for me and is fairly light.如果人们发现任何东西,请大喊大叫,但这对我来说效果很好,而且相当轻。

I'm only running it on my cards (I'm writing a card game) so it only adjusts Card classes that are on the stage, and they will potentially be always above other things like Tables/Labels etc.我只在我的卡片上运行它(我正在写一个纸牌游戏)所以它只调整舞台上的卡片类,它们可能总是高于其他东西,如表格/标签等。

I've added a local int zIndex to my class which is what is used in the Comparator and is set at the beginning of the setZIndex method.我在我的类中添加了一个本地int zIndex ,它是在 Comparator 中使用的,并设置在 setZIndex 方法的开头。

The beginning part of the method is lifted from the original in the Actor class.该方法的开头部分是从 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;
    }
}

EASIEST SOLUTION!!最简单的解决方案!! I am ashamed it took me as long as it did to come up with this...我很惭愧我花了这么长时间才想出这个......

Make a "ZStage" class that extends Stage.制作一个扩展舞台的“ZStage”类。 Override the getActors method.覆盖 getActors 方法。 Bubble-sort the actors based on their Y index to get their rendering order.根据他们的 Y 索引对演员进行冒泡排序以获得他们的渲染顺序。

public class ZStage extends Stage {公共类 ZStage 扩展了 Stage {

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;
}

} }

Not sure if this was recently added but what worked for me is simply calling sort on the Array of actors:不确定这是否是最近添加的,但对我有用的只是在演员数组上调用sort

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

Then the ActorRenderComparator may look something like this:那么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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM