15

I want to create a floating help bubble to introduce the basic functioning of my game. This bubble should float above the Actor I want it to explain, like shown in the picture below.

Floating instruction bubble.

To accomplish this, I want the coordinates of the Actor, in this case the left button, and then I can add the bubble Actor to the Stage in front of everything else. The last part is easy enough, but I'm struggling with retrieving the actual coordinates of the button, as it is in a table.

The two buttons are added to a Table like this:

t.add(btnLab).expandX().center();
t.add(btnSea).expandX().center();

I've tried the most obvious approach:

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

This gives me (in the order of the sysouts): [0.0, 0.0] and [40.0, 130.0]. The last position is actually the position of the Table, which fills the blue area of the screen. So this location obviously misses something the Table does to place the Actor, and cannot be used (as I only end up with the location of the Table).

(I've also tried using t.localToStageCoordinates here, t being the Table. Same results.)

Another solution I tried was to recursively search through all Parents:

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

Unfortunately, this gives me the same. The sysouts gives the following:

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

So I can't seem to get the actual positions of the Groups/Actors within the Table.

How am I supposed to do this?

4

1 回答 1

28

我想我明白你在哪里感到困惑。获取演员的舞台坐标实际上非常简单(假设屏幕对齐、未旋转、未缩放演员)。

您需要做的就是:

public static Vector2 getStageLocation(Actor actor) {
    return actor.localToStageCoordinates(new Vector2(0, 0));
}

你做错的是试图获取演员相对于桌子的位置(通过使用actor.getX()和actor.getY()),然后将该位置转换为舞台。这最终会为您提供桌子的位置,因为它将添加演员的位置。你真正要知道你的演员内部的新向量2(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”消息,因为它可以为您提供演员在舞台上的位置。

于 2013-08-08T19:56:00.360 回答