在libGDX中获取表格中演员的舞台坐标

15
我想创建一个浮动的帮助气泡来介绍我的游戏的基本功能。这个气泡应该漂浮在我想要解释的角色上方,就像下面的图片一样。
为了实现这一点,我需要获取角色(在这种情况下是左侧按钮)的坐标,然后我可以将气泡角色添加到舞台上覆盖其他所有内容。最后一部分很容易,但我正在努力检索按钮的实际坐标,因为它在一个表格中。
这两个按钮是以这种方式添加到表格中的:
t.add(btnLab).expandX().center();
t.add(btnSea).expandX().center();

我已经尝试了最明显的方法:

Vector2 loc = new Vector2(a.getX(), a.getY());
System.out.println("Loc: " + loc);
a.localToStageCoordinates(loc);
System.out.println("Loc: " + loc);

这是我通过sysouts得到的结果(按顺序):[0.0, 0.0]和[40.0, 130.0]。最后一个位置实际上是Table的位置,填充了屏幕上的蓝色区域。所以这个位置显然缺少Table用于放置Actor的东西,不能被使用(因为这只会得到Table的位置)。
(我也尝试过在这里使用t.localToStageCoordinates,其中t是Table。但结果相同。)
另一个我尝试过的解决方法是递归地搜索所有父级:
private static Vector2 getLoc(Actor a) {
    return getLoc(new Vector2(a.getX(), a.getY()), a.getParent());
}

private static Vector2 getLoc(Vector2 loc, Actor g) {
    System.out.println("Location: " + loc + ", Actor: " + g);
    loc.x += g.getX();
    loc.y += g.getY();
    if(g.getParent() == null) return loc;
    return getLoc(loc, g.getParent());
}

很遗憾,这给了我同样的结果。sysouts输出如下:

Location: [0.0:0.0], Actor: Table 40.0,130.0 944.0x508.0
Location: [40.0:130.0], Actor: Group 0.0,0.0 0.0x0.0
Location: [40.0:130.0], Actor: Group 0.0,0.0 0.0x0.0

我似乎无法获得表格中群组/演员的实际位置。

我应该如何做呢?


1
除了我的回答,我想知道你是否试图在演员首次渲染之前获取演员的位置?如果您尝试在框架有足够时间正确进行布局之前获取位置,则会得到错误的坐标。在我的示例中,我通过使用事件侦听器在执行布局后获取正确的位置来缓解这个问题。 - Jyro117
我在舞台(Stage)中有一个Table,它位于另一个Table中的VerticalGroup中。我按照下面的答案尝试了一下,但并没有成功。问题最终是由于在分配起始表位置之前未对元素进行布局。该答案中的任何舞台位置转换都不必要。一旦布局完成后,table.getX() 可以为我提供所需的舞台位置。 - bazola
@Jyro117 感谢你的提示。我也遇到了同样的问题。花了很长时间才意识到我可能过早地计算了演员的位置。 - Neerkoli
1个回答

29

我认为我知道你为什么感到困惑了。获取演员的舞台坐标实际上非常简单(假设演员是屏幕对齐、未旋转、未缩放的)。

你所需要做的就是这样:

public static Vector2 getStageLocation(Actor actor) {
    return actor.localToStageCoordinates(new Vector2(0, 0));
}
你做错了的事情是试图获取演员相对于桌子的位置(使用actor.getX()和actor.getY()),然后将该位置转换到舞台上。这样会导致你获取到的是桌子的位置,因为它会加上演员的位置。你真正想知道的是您演员内部的新Vector2(0,0)点的位置。这告诉您演员左下角的位置。如果您想要左上角,则可以使用new Vector2(0,actor.getHeight()),其他角落以类似的方式处理。
另外,如果您正在使用事件,并想知道事件的舞台位置,则只需执行以下操作:
@Override public void touchUp(final InputEvent event, final float x, final float y, final int pointer, final int button) {
    if (pointer == Buttons.LEFT) {
        Gdx.app.log("Event", "x: " + event.getStageX() + " y: " + event.getStageY());
    }
}

要查看更完整的示例,请参阅以下代码:

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;

public class ActorStage implements ApplicationListener {
    private Stage stage;
    private Skin skin;

    @Override public void create() {
        Gdx.app.log("CREATE", "App Opening");

        this.stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
        Gdx.input.setInputProcessor(this.stage);

        this.skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
        this.skin.hashCode();

        final Table table = new Table();
        table.setFillParent(true);

        final Button btnLab = new TextButton("Lab", skin);
        final Button btnSea = new TextButton("Sea", skin);


        setupButton(table, btnLab);
        setupButton(table, btnSea);

        this.stage.addActor(table);

        Gdx.gl20.glClearColor(0f, 0f, 0f, 1);
        Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    }

    private void setupButton(Table table, final Button button) {
        table.add(button).expandX().center();

        button.addListener(new ClickListener() {
            @Override public void clicked(InputEvent event, float x, float y) {
                Gdx.app.log("XY", "[" + x + ", " + y + "]");
                Gdx.app.log("Event", "[" + event.getStageX() + ", " + event.getStageY() + "]");
                Gdx.app.log("Actor", "[" + button.getX() + ", " + button.getY() + "]");

                Vector2 loc = new Vector2(button.getX(), button.getY());
                Vector2 stageLoc = button.localToStageCoordinates(loc);
                Gdx.app.log("ActorStage", "[" + stageLoc.x + ", " + stageLoc.y + "]");

                Vector2 zeroLoc = button.localToStageCoordinates(new Vector2());
                Gdx.app.log("ZeroStage", "[" + zeroLoc.x + ", " + zeroLoc.y + "]");
            }
        });
    }

    @Override public void render() {
        this.stage.act();

        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        Gdx.gl20.glEnable(GL20.GL_BLEND);

        this.stage.draw();
    }

    @Override public void dispose() {
        Gdx.app.log("DISPOSE", "App Closing");
    }

    @Override public void resize(final int width, final int height) {
        Gdx.app.log("RESIZE", width + "x" + height);
        Gdx.gl20.glViewport(0, 0, width, height);
        this.stage.setViewport(width, height, false);
    }

    @Override public void pause() {}

    @Override public void resume() {}
}

点击btnLab一次,点击btnSea一次,然后关闭窗口,输出:

CREATE: App Opening
RESIZE: 800x600
XY: [18.0, 13.0]
Event: [200.0, 296.0]
Actor: [182.0, 283.0]
ActorStage: [364.0, 566.0]
ZeroStage: [182.0, 283.0]
XY: [6.0, 23.0]
Event: [588.0, 306.0]
Actor: [582.0, 283.0]
ActorStage: [1164.0, 566.0]
ZeroStage: [582.0, 283.0]
DISPOSE: App Closing

正如您所看到的,您需要获取“ZeroStage”消息,因为它会提供演员在舞台上的位置。


这个问题表明 a.getX(), a.getY() 的输出是 0,0,那么这不意味着 OP 已经在做你建议的事情了吗? - DannyMo
我已经更新了我的答案,并提供了一个完整的示例,显示0,0确实会给出舞台坐标。原帖作者可能在做一些不同的事情,导致他的输出结果不同。 - Jyro117
哈哈,是的,零起了作用!那真是太傻了。感谢您的帮助和非常详细的回答。 - Erlend D.
没问题,我记得很久以前也曾经遇到过这个问题。 :) - Jyro117
4
对我来说不起作用。我有一个表格内部包含图像,表格再次被放置在舞台上。我在图像上使用localToStageCoordinates(new Vector2())方法,但它返回的坐标是错误的。我使用的是libgdx 1.1.0版本。 - Genry
2
这对我来说是有效的,但只有在表格和舞台绘制完成后才有效。如果我在初始设置期间请求位置,则返回异常坐标。 - Mofe Ejegi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接