jobr97
jobr97

Reputation: 179

Box2d coordinate system

In the game I'm trying to code I got to have two bodies. One StaticBody and one DynamicBody. I want to have the DynamicBody on top of the StaticBody. Somehow all I get is this:

Bug

Is it possible that the viewports lower, left corner isn't at 0,0? And why can't the DynamicBody get on top of the StaticBody?

Gamescreen.java

package com.joelbrun.jetskirider.screens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.utils.Scaling;
import com.badlogic.gdx.utils.viewport.ScalingViewport;
import com.badlogic.gdx.utils.viewport.Viewport;


public class Gamescreen implements Screen {

    private static final float TIMESTEP = 1 / 60;
    private static final int VELOCITY_ITERATIONS = 8;
    private static final int POSITION_ITERATIONS = 3;
    public static final int GAMESCREEN_WIDTH = 1920;
    public static final int GAMESCREEN_HEIGHT = 720;
    public static final int OBSTACLE_TYPES = 5;
    private static final int WATER_HEIGHT = 200;
    private static final float JETSKI_BOX_X = 200;
    private static final float JETSKI_BOX_Y = 100;
    private World world;
    private Box2DDebugRenderer debugRenderer;
    public Texture jetski, wave;
    public Sprite background;
    public SpriteBatch batch;
    public OrthographicCamera camera;
    public Label score;
    Viewport viewport;

    @Override
    public void show() {
        world = new World(new Vector2(0, -9.81f), true);
        debugRenderer = new Box2DDebugRenderer();
        Texture[] texture = new Texture[OBSTACLE_TYPES];

        //Textures
        for (int i=0; i<OBSTACLE_TYPES; i++){
            texture[i] = new Texture(Gdx.files.internal("game/obstacles/obstacle" + Integer.toString(i+1)+".png"));
        }
        background = new Sprite(new Texture("game/background.png"));
        jetski = new Texture("game/jetski.png");
        wave = new Texture("game/water1.png");
        batch = new SpriteBatch();

        //Camera & Viewport
        camera = new OrthographicCamera();

        viewport = new ScalingViewport(Scaling.fillY, GAMESCREEN_WIDTH, GAMESCREEN_HEIGHT, camera);
        viewport.apply();
        camera.position.set(GAMESCREEN_WIDTH / 2, GAMESCREEN_HEIGHT / 2, 0);


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


        //shape
        PolygonShape box = new PolygonShape();
        box.setAsBox(2560, WATER_HEIGHT);

        //fixture definition
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = box;
        fixtureDef.density = 1000;
        fixtureDef.friction = .25f;
        fixtureDef.restitution = .1f;

        Fixture fixture = body.createFixture(fixtureDef);

        box.dispose();

        //Jetski
        bodyDef.type = BodyDef.BodyType.DynamicBody;
        bodyDef.position.set(1280,WATER_HEIGHT + 100);

        Body jetskiObject = world.createBody(bodyDef);

        PolygonShape jetskiBox = new PolygonShape();
        jetskiBox.setAsBox(JETSKI_BOX_X, JETSKI_BOX_Y);

        fixtureDef.shape = jetskiBox;
        fixtureDef.density = 100;
        fixtureDef.friction = 0;

        Fixture jetskiFixture = body.createFixture(fixtureDef);

        jetskiBox.dispose();
    }

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

        debugRenderer.render(world, camera.combined);

        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        batch.end();
        camera.update();

        world.step(TIMESTEP, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
    }

    @Override
    public void resize(int width, int height) {
        int SCREEN_WIDTH = width;
        int SCREEN_HEIGHT = height;

        viewport.setWorldSize(GAMESCREEN_WIDTH, GAMESCREEN_HEIGHT);
        viewport.update(SCREEN_WIDTH, SCREEN_HEIGHT,true);
        camera.update();
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {
        dispose();
    }

    @Override
    public void dispose() {
        batch.dispose();
        background.getTexture().dispose();
        jetski.dispose();
        wave.dispose();
        world.dispose();
        debugRenderer.dispose();
    }


}

Upvotes: 1

Views: 1733

Answers (3)

Leonardo
Leonardo

Reputation: 54

You should try to use a chainshape instead of a polygonshape for the staticbody. So that the dynamic body will remain in it instead of "teleporting" out. The dynamic body mustn't intersect the staticbody when it is created. Hope it will work!

Upvotes: 0

Alex S. Diaz
Alex S. Diaz

Reputation: 2667

You are using Box2D wrong. You should scale down Box2D to a small world because, without doing this, physics interaction will be 1px = 1m and an 1920 x 720 is too big (this will be reflected as your bodies moving too slow, because they are too big).

Check your code:

PolygonShape box = new PolygonShape();
box.setAsBox(2560, WATER_HEIGHT); // <- your water object dimensions

and

PolygonShape jetskiBox = new PolygonShape();dimensions
jetskiBox.setAsBox(JETSKI_BOX_X, JETSKI_BOX_Y);  // <- your jetsky object 

Then, check the setAsBox method:

public void setAsBox(float hx, float hy)

Parameters:

hx - the half-width.

hy - the half-height.

(Added emphasis)

So for your water, you are creating an static body of 5120 x 400 and for your jetski 400 x 200, this values are too high.

I sugest to try with the example that appear in the official wiki but then check sites like this and read the manual to understand how Box2D works. I could extract this:

In particular, Box2D has been tuned to work well with moving objects between 0.1 and 10 meters. So this means objects between soup cans and buses in size should work well. Static objects may be up to 50 meters big without too much trouble.

Being a 2D physics engine, it is tempting to use pixels as your units. Unfortunately this will lead to a poor simulation and possibly weird behavior. An object of length 200 pixels would be seen by Box2D as the size of a 45 story building.

Another thing, I don't know if this affect in someway, but I always do the world.step(...) first then the debugRenderer.render(...) at the end, in your code, you have this inverted (maybe this is why your jetski is not being moved).

Upvotes: 0

vdlmrc
vdlmrc

Reputation: 755

Yes with Box2D the origin is the bottom left corner of the viewport.

You can set the position of your bodies when you are setting up your BodyDef :

bodyDef.position.set(x, y);

And don't forget, in Box2D, the position of your body is the center of the Body. So when you set your PolygonShape as a box like this :

polygonShape.setAsBox(width, height);

Your actual box width will be width*2 and your actual box height will be height*2

Upvotes: 1

Related Questions