在 LibGDX 的 `scene2d` API 中是否可以在多个阶段拥有相同的 Actor 实例?

Is it possible in LibGDX's `scene2d` API to have the same Actor instance in multiple Stages?

我正在使用令人惊叹的 libGDX+scene2d API 制作一个程序,我将其结构化如下:

(在所有情况下,删除“My”将为您提供它扩展的相应库 class 的名称)

这个模型运行良好,直到我在使用 Action 系统在屏幕之间执行操作时遇到一些问题。那时我决定拥有一个属于 MyGameOmnipresentActor 是个好主意,顾名思义,它出现在每个场景中。所以我修改了 MyStage 看起来或多或少像这样:

public class MyStage extends Stage {
public MyStage(MyGame g) {
    super(new FitViewport(MyGame.WIDTH, MyGame.HEIGHT), g.batch);
    addActor(game.omnipresentInvisibleActor);
}

@Override
public void clear() {
    unfocusAll();
    getRoot().clearActions();
    getRoot().clearListeners();
    removeActorsButNotListenersNorActions();
}

public void removeActorsButNotListenersNorActions() {
    for (Actor a : getActors()) if (a.getClass()!= OmnipresentInvisibleActor.class) a.remove();
}

它经历了一个痛苦的调试阶段,直到我发现以下内容:

public PresentationScreen(MyGame g) {
    // super() call and other irrelevant/already debugged code
    System.out.println("PRINT_BEFORE: "+ stage.getActors().toString()); // OmnipresentActor is there
    mainMenuScreen = new MainMenuScreen(game);
    System.out.println("PRINT_AFTER: "+ stage.getActors().toString()); // OmnipresentActor is not there anymore, but was added to the mainMenuScreen

"PRINT_BEFORE" 语句显示 stage 持有 omnipresentActor。在 "PRINT_AFTER" 中它不再存在,而 mainMenuScreen 确实持有它。所以我的问题,现在更精确了:

scene2d 是否阻止了这种情况的发生,还是我做错了什么?

回答非常感谢!干杯

一个演员只能是一个舞台的成员:感谢@Tenfour04 确认。经过一些研究后,解释很清楚:

Stage.addActor() 看起来像这样:

(这里是Stage.java的github代码)

/** Adds an actor to the root of the stage.
     * @see Group#addActor(Actor) */
    public void addActor (Actor actor) {
        root.addActor(actor);
}

而 root 在 Stage 构造函数中被简单地初始化为一个组:root = new Group();.

Group.addActor() 看起来像这样:

(这里是Group.java的github代码)

/** Adds an actor as a child of this group. The actor is first removed from its parent group, if any. */
public void addActor (Actor actor) {
    if (actor.parent != null) actor.parent.removeActor(actor, false);
    children.add(actor);
    actor.setParent(this);
    actor.setStage(getStage());
    childrenChanged();

}

所以在树的第一行是答案:在创建新阶段时,如果要添加的 actor 已经有父级,则将其从当前父级中删除。因此,我提出的问题有两种可能的解决方案:

解决方案 1:覆盖 addActor 删除 if 语句,或库的任何其他更改,我不确定它是否有效。我宁愿认为这可能是非常有问题的,例如它可能会阻止阶段正确处理

解决方案 2:更改设计,这样您就不需要无所不在的演员,也不需要 changing/reimplementing 库。 目前这就是我所做的基于 的回答,它不是很干净,但目前可以使用:

1) 在MyScreen class 中添加了以下字段:

private boolean watchingTemp;
private Actor watchActorTemp;
private Action actionTemp;

2) 然后添加这个方法:

public void addActionOnStageAfterActorEndsHisActions(Actor actor, Action action) {
    watchActorTemp = actor;
    actionTemp = action;
    watchingTemp = true;
}

3) 然后在 render 方法中,我添加了以下内容:

if (watchingTemp && !watchActorTemp.hasActions()) {
        watchingTemp = false;
        stage.addAction(actionTemp);
    }

4) 最后,当希望在屏幕转换时执行一个动作(并最终处理第一个),你可以这样做:我在点击屏幕之间的门时使用类似的东西

public void movePlayerTHENgotoNewScreen(float xPos, float yPos, whatever else...) {
    game.player.walkToAnyPoint(xPos, yPos);
    yourFavoriteScreen.addActionOnStageAfterActorEndsHisActions(game.player, gotoNewScreen(wathever else...));
}

希望对您有所帮助!