LibGDX camera.project() 无法正常工作

问题描述 投票:0回答:1

我使用 Box2D 来管理我的游戏世界。我想在正文上方显示文本。我计划通过适当设置标签来做到这一点。问题在于,主体位于游戏世界中,而标签位于舞台 (UI) 中。所以我尝试使用 camera.project() 方法将世界坐标转换为屏幕坐标。不幸的是,由于某种原因我无法做到这一点 - 标签显示在与应有位置不同的位置 - 它相对于目标位置向下并向左移动。当调整窗口大小时,这个位置也会改变,但也是不正确的。 我要补充一点,否则我会以同样的方式使用 camera.unproject() 方法,这里没有问题 - 一切正常。我不知道为什么相反。

this.camera = new OrthographicCamera(ScreenManager.WIDTH * SCALE, ScreenManager.HEIGHT * SCALE);
this.viewport = new FitViewport(ScreenManager.WIDTH, ScreenManager.HEIGHT);
this.stage = new Stage(viewport, batch);
this.world = new World(Vector2.Zero, true);

// ...

Vector3 worldPosition = new Vector3(x, y, 0);
Vector3 screenPosition = camera.project(worldPosition,
    viewport.getScreenX(), viewport.getScreenY(),
    viewport.getScreenWidth(), viewport.getScreenHeight());

label.setPosition(screenPosition.x, screenPosition.y);

我的调整大小方法:

@Override
public void resize(int width, int height) {
    viewport.update(width, height, true);
}

当然我在render方法中为Stage调用act()draw()。我做错了什么?

java libgdx box2d
1个回答
0
投票

为了从

World
坐标转换为
Stage
坐标,您需要首先将
World
位置投影到 屏幕空间,然后将其取消投影回
Stage
-空间

Vector2 worldPosition = body.getPosition();
Vector3 screenPosition = worldCamera.project(new Vector3(worldPosition.x, worldPosition.y, 1.0f));
Vector3 stagePosition = stage.getCamera().unproject(screenPosition);

label.setPosition(stagePosition.x, stage.getHeight() - stagePosition.y)); // stage.getHeight() - because UP is flipped.

该过程将允许您跟踪 Box2D

Body
并设置
Label
的位置来匹配它:

上面示例的完整源代码包含在下面,它使用 libGDX 测试中的默认字体(字体字体图像)。

package com.bornander.sandbox;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.*;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class MyGdxSandbox extends ApplicationAdapter {
    World world;
    OrthographicCamera worldCamera;
    Box2DDebugRenderer box2DDebugRenderer;

    Body ballBody;
    Stage stage;
    Label label;
    
    @Override
    public void create () {
        world = new World(new Vector2(0.0f, -10.0f), false);
        float aspectRatio = (float)Gdx.graphics.getWidth() / Gdx.graphics.getHeight();
        float worldCameraViewportWidth = 100.0f;
        worldCamera = new OrthographicCamera(worldCameraViewportWidth, worldCameraViewportWidth / aspectRatio);
        worldCamera.position.set(worldCamera.viewportWidth / 2.0f, worldCamera.viewportHeight / 2.0f, 1.0f);
        box2DDebugRenderer = new Box2DDebugRenderer();

        CircleShape ballShape = new CircleShape();
        ballShape.setRadius(4.0f);

        FixtureDef ballFixtureDef = new FixtureDef();
        ballFixtureDef.shape = ballShape;
        ballFixtureDef.friction = 0.2f;
        ballFixtureDef.density = 1.0f;
        ballFixtureDef.restitution = 0.65f;

        BodyDef ballBodyDef = new BodyDef();
        ballBodyDef.type = BodyDef.BodyType.DynamicBody;

        ballBody = world.createBody(ballBodyDef);
        ballBody.createFixture(ballFixtureDef);
        ballBody.setTransform(25, 50, 0);
        ballBody.applyLinearImpulse(200, 0, ballBody.getPosition().x, ballBody.getPosition().y, true);

        PolygonShape groundShape = new PolygonShape();
        groundShape.setAsBox(25, 2);

        FixtureDef groundFixtureDef = new FixtureDef();
        groundFixtureDef.shape = groundShape;
        groundFixtureDef.friction = 0.2f;
        groundFixtureDef.density = 1.0f;
        groundFixtureDef.restitution = 0.2f;

        BodyDef groundBodyDef = new BodyDef();
        groundBodyDef.type = BodyDef.BodyType.StaticBody;

        Body ground = world.createBody(groundBodyDef);
        ground.createFixture(groundFixtureDef);
        ground.setTransform(50, 20, 0);


        stage = new Stage(new ScreenViewport());
        stage.setDebugAll(true);
        label = new Label("TEXT", new Label.LabelStyle(new BitmapFont(Gdx.files.internal("default.fnt")), Color.WHITE));
        label.setPosition(10, 10);
        stage.addActor(label);
    }

    @Override
    public void render () {
        ScreenUtils.clear(0, 0, 0, 1);
        float delta = Gdx.graphics.getDeltaTime();
        worldCamera.update();
        world.step(delta, 8, 8);
        Vector2 ballPositionWorld = ballBody.getPosition();
        Vector3 ballScreenPosition = worldCamera.project(new Vector3(ballPositionWorld.x, ballPositionWorld.y, 1.0f));
        Vector3 ballStagePosition = stage.getCamera().unproject(ballScreenPosition);
        label.setText(String.format("(%.3f, %.3f)", ballPositionWorld.x, ballPositionWorld.y));
        label.pack();
        label.setPosition(ballStagePosition.x, stage.getHeight() - ballStagePosition.y);
        box2DDebugRenderer.render(world, worldCamera.combined);
        stage.act();
        stage.draw();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.