libgdx world to screen pos and factors

2019-06-09 10:51发布

问题:

I want to draw a texture on a body, which is a box. How do I convert the coordinates of the body to screen coordinates? I know that the other way around is with camera.unproject(pos), is it similar to this?

I see a lot of people using constants such as WORLD_TO_SCREEN = 32, but I currently don't have that in my game. Is that a problem, and how can I implement it now? Because it seems like people that are using these factors can convert world to screen positions easily. I currently have a camera and an ExtendViewport

camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
viewport = new ExtendViewport(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, camera);
camera.position.set(VIEWPORT_WIDTH/2, VIEWPORT_HEIGHT/2, 0f);

Viewport width and height are set to this

public static final int VIEWPORT_WIDTH = 20;
public static final int VIEWPORT_HEIGHT = 22;

I don't really know what I'm doing, I read documentation and read some tutorials, but if someone could give some explanation about these variables and the world_to_screen factor that would really help me out.

I also set APP_WIDTH=1280, APP_HEIGHT = 720 Do viewport width and height mean that for box2d my screen is 20 meters wide and 22 meters high? (asking it again because I added a lot the question and I would really like to know these things)

[EDIT]

So I'm trying to draw a ground picture on the ground body

float x = stage.getGround().getX();
float y = stage.getGround().getY();
float w = stage.getGround().getWidth();
float h = stage.getGround().getHeight();

stage.act(delta);
stage.draw();
stage.updateCamera();

Texture texture = new Texture(Gdx.files.internal("ground.png"));
Sprite sprite = new Sprite(texture);
sprite.setSize(w, h);
sprite.setPosition(x-sprite.getWidth()/2, y-sprite.getHeight()/2);

But I don't see it anywhere

[EDIT 2] Stage Class

public class Mission1Stage extends Stage{
    public static final int VIEWPORT_WIDTH = 20;
    public static final int VIEWPORT_HEIGHT = 22;

    private World world;
    private Ground ground;
    private LeftWall leftWall;
    private Rocket rocket;

    private static final float TIME_STEP = 1 / 300f;
    private float accumulator = 0f;

    private OrthographicCamera camera;
    private Box2DDebugRenderer renderer;
    private Viewport viewport;

    private SpriteBatch spriteBatch = new SpriteBatch();

    private Vector3 touchPoint;
    private ShapeRenderer shapeRenderer;

    private Button boostButton;
    private Skin boostSkin;

    private Button boostLeftButton;
    private Skin boostLeftSkin;

    private Button boostRightButton;
    private Skin boostRightSkin;

    private Button resetButton;
    private Skin resetSkin;

    private Game game;

    private boolean isTouched = false;

    public Mission1Stage(Game game) {
        setUpWorld();
        renderer = new Box2DDebugRenderer();
        shapeRenderer = new ShapeRenderer();
        setupCamera();
        setUpButtons();
        addActor(new Background(ground));
    }

    private void setUpWorld() {
        world = WorldUtils.createWorld();
        setUpGround();
        setUpRocket();
    }

    private void setUpGround() {
        ground = new Ground(WorldUtils.createGround(world));
        addActor(ground);
    }

    private void setUpLeftWall() {
        leftWall = new LeftWall(WorldUtils.createLeftWall(world));
    }

    private void setUpRocket() {
        rocket = new Rocket(WorldUtils.createRocket(world));
        addActor(rocket);
    }

    private void setupCamera() {
        camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
        viewport = new ExtendViewport(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, camera);
        camera.position.set(VIEWPORT_WIDTH/2, VIEWPORT_HEIGHT/2, 0f);
        camera.update();
    }

    private void setUpButtons() {
        boostSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
        boostButton = new Button(boostSkin);
        boostButton.setSize(80,80);
        boostButton.setPosition(Gdx.graphics.getWidth()-boostButton.getWidth()*2,0);
        boostButton.setTransform(true);
        boostButton.scaleBy(0.5f);
        Gdx.input.setInputProcessor(this);
        addActor(boostButton);

        boostLeftSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
        boostLeftButton = new Button(boostLeftSkin);
        boostLeftButton.setSize(100, 100);
        boostLeftButton.setPosition(0, 0);
        addActor(boostLeftButton);

        boostRightSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
        boostRightButton = new Button(boostRightSkin);
        boostRightButton.setSize(100, 100);
        boostRightButton.setPosition(boostLeftButton.getWidth(), 0);
        addActor(boostRightButton);

        resetSkin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
        resetButton = new Button(resetSkin);
        resetButton.setSize(100, 100);
        resetButton.setPosition(Gdx.graphics.getWidth()-100, Gdx.graphics.getHeight()-100);
        addActor(resetButton);
    }

    @Override
    public void act(float delta) {
        super.act(delta);
        handleInput();

        accumulator += delta;

        while(accumulator >= delta) {
            world.step(TIME_STEP, 6, 2);
            accumulator -= TIME_STEP;
        }
    }

    @Override
    public void draw() {
        super.draw();
        renderer.render(world, camera.combined);

        float x = getGround().getBody().getPosition().x;
        float y = getGround().getBody().getPosition().y;
        float w = getGround().getWidth() * 2;
        float h = getGround().getHeight() * 2;

        spriteBatch.setProjectionMatrix(getCamera().combined);

        Texture texture = new Texture(Gdx.files.internal("ground.png"));
        Sprite sprite = new Sprite(texture);
        sprite.setSize(w, h);
        sprite.setPosition(x-sprite.getWidth()/2, y-sprite.getHeight()/2);


        spriteBatch.begin();
        sprite.draw(spriteBatch);
        spriteBatch.end();
    }

    public void handleInput() {
        if(boostButton.isPressed()) {
            rocket.boost();
        }
        if(boostLeftButton.isPressed()) {
            rocket.turnLeft();
        }
        if(boostRightButton.isPressed()) {
            rocket.turnRight();
        }
        if(resetButton.isPressed()) {

        }
    }

    public boolean resetScreen() {
        if(resetButton.isPressed()) return true;
        return false;
    }

    public void updateCamera() {

    }

    public Ground getGround() {
        return ground;
    }

    public void resize(int width, int height) {
        viewport.update(width, height);
        camera.position.x = VIEWPORT_WIDTH / 2;
        camera.position.y = VIEWPORT_HEIGHT /2;
    }


    private void translateScreenToWorldCoordinates(int x, int y) {
        getCamera().unproject(touchPoint.set(x, y, 0));getCamera();
    }
}

Screen class

public class Mission1Screen implements Screen{
    private Game game;
    private Mission1Stage stage;
    private SpriteBatch spriteBatch = new SpriteBatch();

    private Skin boostSkin;
    private Button boostButton;

    public Mission1Screen(Game game) {
        this.game = game;
        stage = new Mission1Stage(game);
    }

    @Override
    public void show() {

    }

    @Override
    public void render(float delta) {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        if(stage.resetScreen()) {
            game.setScreen(new Mission1Screen(game));
        }

        stage.act(delta);
        stage.draw();
        stage.updateCamera();
    }

    @Override
    public void resize(int width, int height) {
        stage.resize(width, height);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {

    }
}

[EDIT 3]

public class Main extends Game {

    @Override
    public void create () {
        this.setScreen(new Mission1Screen(this));
    }

    @Override
    public void render () {
        super.render();
    }

    @Override
    public void dispose () {

    }
}

回答1:

We mostly use Pixel to meter conversion because box2d best works in meters (0-10) but you can avoid this conversion by using small worldwidth and height of your viewport. I mostly prefer 48 and 80 as viewport width and height.

You can use unproject(vector3) method of camera that translate a point given in screen coordinates to world space. I am using this method in touchdown because I get screen coordinate as parameter then I need to convert it into camera world space so that I can generate object at a particular position in world.

public class MyGdxTest extends Game implements InputProcessor {

    private SpriteBatch batch;
    private ExtendViewport extendViewport;
    private OrthographicCamera cam;

    private float w=20;
    private float h=22;

    private World world;
    private Box2DDebugRenderer debugRenderer;

    private Array<Body> array;
    private Vector3 vector3;

    @Override
    public void create() {

        cam=new OrthographicCamera();
        extendViewport=new ExtendViewport(w,h,cam);

        batch =new SpriteBatch();
        Gdx.input.setInputProcessor(this);

        world=new World(new Vector2(0,-9.8f),true);
        array=new Array<Body>();
        debugRenderer=new Box2DDebugRenderer();
        vector3=new Vector3();

        BodyDef bodyDef=new BodyDef();
        bodyDef.type= BodyDef.BodyType.StaticBody;
        bodyDef.position.set(0,0);
        Body body=world.createBody(bodyDef);

        ChainShape chainShape=new ChainShape();
        chainShape.createChain(new float[]{1,1,55,1});

        FixtureDef fixtureDef=new FixtureDef();
        fixtureDef.shape=chainShape;
        fixtureDef.restitution=.5f;
        body.createFixture(fixtureDef);
        chainShape.dispose();
    }

    @Override
    public void render() {
        super.render();

        Gdx.gl.glClearColor(0,1,1,1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        world.step(1/60f,6,2);
        batch.setProjectionMatrix(cam.combined);
        batch.begin();

        world.getBodies(array);
        for (Body body:array){
            if(body.getUserData()!=null) {
                Sprite sprite = (Sprite) body.getUserData();
                sprite.setPosition(body.getPosition().x-sprite.getWidth()/2, body.getPosition().y-sprite.getHeight()/2);
                sprite.setRotation(body.getAngle()*MathUtils.radDeg);
                sprite.draw(batch);
            }
        }
        batch.end();
        debugRenderer.render(world,cam.combined);
    }

    @Override
    public void resize(int width, int height) {
        super.resize(width,height);
        extendViewport.update(width,height);
        cam.position.x = w /2;
        cam.position.y = h/2;
        cam.update();
    }

    private void createPhysicsObject(float x,float y){

        float sizeX=2,sizeY=2;
        BodyDef bodyDef=new BodyDef();
        bodyDef.position.set(x,y);
        bodyDef.type= BodyDef.BodyType.DynamicBody;

        Body body=world.createBody(bodyDef);

        PolygonShape polygonShape=new PolygonShape();
        polygonShape.setAsBox(sizeX,sizeY);
        FixtureDef fixtureDef=new FixtureDef();
        fixtureDef.shape=polygonShape;
        fixtureDef.restitution=.2f;
        fixtureDef.density=2;

        body.createFixture(fixtureDef);
        body.setFixedRotation(false);
        polygonShape.dispose();


        Sprite sprite=new Sprite(new Texture("badlogic.jpg"));
        sprite.setSize(2*sizeX,2*sizeY);
        sprite.setPosition(x-sprite.getWidth()/2,y-sprite.getHeight()/2);
        sprite.setOrigin(sizeX,sizeY);

        body.setUserData(sprite);
    }

    @Override
    public void dispose() {
        batch.dispose();
        debugRenderer.dispose();
        world.dispose();
    }

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {

        vector3.set(screenX,screenY,0);
        Vector3 position=cam.unproject(vector3);
        createPhysicsObject(vector3.x,vector3.y);

        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}