1
\$\begingroup\$

I have a collision problem in Box2D.

I am trying to do a simple platform game with Libgdx, Box2D and TiledMap.

I have a map made with TiledMap:

I load the map in my Android game. I read all the "objects" from the map and draw it on the screen with no problem:

But when I add a player made with Box2D , the player not collides with map objects. He simply passes through:

enter image description here

enter image description here

I have spent two days in this and I can't see my mistake.

Here is my level code:

package com.larralde.screens.gamescreens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.maps.Map;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.larralde.GeometryConflict;
import com.larralde.config.Constantes;
import com.larralde.entities.EntityFactory;
import com.larralde.entities.PlayerContactListener;
import com.larralde.entities.PlayerEntity;
import com.larralde.entities.WorldEntity;
import com.larralde.screens.BaseScreen;
import com.larralde.utils.TiledMapLoader;
import com.larralde.utils.TiledMapObject;

import java.util.ArrayList;


public class Level_01_01 extends BaseScreen {

    private float SCREEN_X, SCREEN_Y;
    private Stage stage;
    private Skin skin;
    private TiledMapRenderer tiledMapRenderer;
    private TiledMap tiledMap;
    private PlayerEntity jugador;
    private World world;
    private Vector3 position;
    ArrayList<TiledMapObject> tiledMapObjects;
    private ArrayList<WorldEntity> actores;

    public Level_01_01(GeometryConflict game, String skinFile){
        super(game);

        SCREEN_X = game.getAppConfig().getScreenX();
        SCREEN_Y = game.getAppConfig().getScreenY();

        stage = new Stage(new FitViewport(SCREEN_X, SCREEN_Y));
        stage.setDebugAll(true);
        position = new Vector3(stage.getCamera().position);
        skin = new Skin(Gdx.files.internal(skinFile));

        world = new World(new Vector2(0, -10), true);
        world.setContactListener(new PlayerContactListener());

        tiledMap = new TmxMapLoader().load("levels/ACTO_01_01.tmx");
        tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);

        tiledMapObjects = new ArrayList<TiledMapObject>();
        actores = new ArrayList<WorldEntity>();
    }

    @Override
    public void show() {
        EntityFactory factory = new EntityFactory(game.getManager());
        //Gdx.input.setInputProcessor(stage);
        jugador = factory.createPlayer(world, new Vector2(1f, 15f),game);
        stage.addActor(jugador);

        //Cargamos los objetos del mapa
        tiledMapObjects.clear();
        tiledMapObjects.addAll(TiledMapLoader.dameObjetos(tiledMap, 32f, world, "Objetos"));

        //Metemos los objetos en el mundo.
        actores.clear();
        for(TiledMapObject oAux : tiledMapObjects){
            actores.add(new WorldEntity(oAux,world));
        }

        for(WorldEntity aAux : actores){
            stage.addActor(aAux);
        }

        stage.getCamera().position.set(position);
        stage.getCamera().update();
    }

    @Override
    public void hide() {
        stage.clear();

        jugador.detach();

    }

    @Override
    public void dispose() {
        // Dispose assets.
        stage.dispose();
        skin.dispose();
    }

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

        /*if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
            //stage.getCamera().translate(-32,0,0);
            jugador.setPosition(jugador.getX() - 32, jugador.getY());
        }
        if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
            //stage.getCamera().translate(32, 0, 0);
            jugador.setPosition(jugador.getX() + 32, jugador.getY());
        }
        if(Gdx.input.isKeyPressed(Input.Keys.UP)){
            //stage.getCamera().translate(0, 32, 0);
            jugador.setPosition(jugador.getX(), jugador.getY() + 32);
        }
        if(Gdx.input.isKeyPressed(Input.Keys.DOWN)){
            //stage.getCamera().translate(0, -32, 0);
            jugador.setPosition(jugador.getX(), jugador.getY() - 32);

        }*/

        stage.act();
        world.step(delta, 6, 2);

        /*if (jugador.getX() > 150 && jugador.isAlive()) {
            float speed = Constantes.PLAYER_SPEED * delta * Constantes.PIXELS_IN_METER;
            stage.getCamera().translate(speed, 0, 0);
        }*/
        tiledMapRenderer.setView((OrthographicCamera) stage.getCamera());
        tiledMapRenderer.render();

        stage.draw();
    }

}

And the Class that load the objects from the Map:

 package com.larralde.utils;

import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.objects.CircleMapObject;
import com.badlogic.gdx.maps.objects.PolygonMapObject;
import com.badlogic.gdx.maps.objects.PolylineMapObject;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.objects.TextureMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Rectangle;
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.ChainShape;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Shape;
import com.badlogic.gdx.physics.box2d.World;
import com.larralde.config.Constantes;

import java.util.ArrayList;

public class TiledMapLoader {

    //El tamaño de los tiles. Ejemplo, si es 16x16 sera 16f. Siempre cuadrados¡¡
    private static float ppt = 0f;

    public static ArrayList<TiledMapObject> dameObjetos(TiledMap map, float pixels, World world, String layerName){
        ppt = pixels;

        MapObjects objects = map.getLayers().get(layerName).getObjects();


        ArrayList<TiledMapObject> tiledMapObjects =  new ArrayList<TiledMapObject>();

        for(MapObject object : objects) {

            if (object instanceof TextureMapObject) {
                continue;
            }

            //Creamos el objeto
            TiledMapObject tiledAux = new TiledMapObject();

            Shape shape;

            if (object instanceof RectangleMapObject) {
                shape = getRectangle((RectangleMapObject) object,tiledAux);
            }
            else if (object instanceof PolygonMapObject) {
                shape = getPolygon((PolygonMapObject)object,tiledAux);
            }
            else if (object instanceof PolylineMapObject) {
                shape = getPolyline((PolylineMapObject)object,tiledAux);
            }
            else if (object instanceof CircleMapObject) {
                shape = getCircle((CircleMapObject)object,tiledAux);
            }
            else {
                continue;
            }

            BodyDef bd = new BodyDef();
            bd.position.set(tiledAux.getX(),tiledAux.getY());
            bd.type = BodyDef.BodyType.StaticBody;
            Body body = world.createBody(bd);
            body.createFixture(shape, 1);

            tiledAux.setBody(body);
            tiledMapObjects.add(tiledAux);

            shape.dispose();
        }

        return tiledMapObjects;

    }

    private static PolygonShape getRectangle(RectangleMapObject rectangleObject,TiledMapObject tiledAux) {
        Rectangle rectangle = rectangleObject.getRectangle();
        PolygonShape polygon = new PolygonShape();
        Vector2 size = new Vector2((rectangle.x + rectangle.width * 0.5f) / ppt,(rectangle.y + rectangle.height * 0.5f ) / ppt);
        polygon.setAsBox(rectangle.width * 0.5f / ppt,rectangle.height * 0.5f / ppt,size,0.0f);

        //Obtenemos la posicion
        Vector2 posicion = new Vector2(0,0);
        rectangle.getPosition(posicion);
        tiledAux.setX(posicion.x);
        tiledAux.setY(posicion.y);
        tiledAux.setHeight(rectangle.getHeight());
        tiledAux.setWidth(rectangle.getWidth());
        tiledAux.setTipoFigura(Constantes.FIGURA_CUADRADO);
        return polygon;
    }

    private static CircleShape getCircle(CircleMapObject circleObject,TiledMapObject tiledAux) {
        Circle circle = circleObject.getCircle();
        CircleShape circleShape = new CircleShape();
        circleShape.setRadius(circle.radius / ppt);
        circleShape.setPosition(new Vector2(circle.x / ppt, circle.y / ppt));

        //Obtenemos la posicion
        Vector2 posicion = circleShape.getPosition();
        tiledAux.setX(posicion.x);
        tiledAux.setY(posicion.y);
        tiledAux.setHeight(circle.radius * 2f);
        tiledAux.setWidth(circle.radius * 2f);
        tiledAux.setTipoFigura(Constantes.FIGURA_CIRCULO);
        return circleShape;
    }

    private static PolygonShape getPolygon(PolygonMapObject polygonObject,TiledMapObject tiledAux) {
        PolygonShape polygon = new PolygonShape();
        float[] vertices = polygonObject.getPolygon().getTransformedVertices();

        float[] worldVertices = new float[vertices.length];

        for (int i = 0; i < vertices.length; ++i) {
            worldVertices[i] = vertices[i] / ppt;
        }
        tiledAux.setTipoFigura(Constantes.FIGURA_POLIGONO);
        polygon.set(worldVertices);
        return polygon;
    }

    private static ChainShape getPolyline(PolylineMapObject polylineObject,TiledMapObject tiledAux) {
        float[] vertices = polylineObject.getPolyline().getTransformedVertices();
        Vector2[] worldVertices = new Vector2[vertices.length / 2];

        for (int i = 0; i < vertices.length / 2; ++i) {
            worldVertices[i] = new Vector2();
            worldVertices[i].x = vertices[i * 2] / ppt;
            worldVertices[i].y = vertices[i * 2 + 1] / ppt;
        }

        ChainShape chain = new ChainShape();
        chain.createChain(worldVertices);

        tiledAux.setTipoFigura(Constantes.FIGURA_CADENA);

        return chain;
    }
}

I try to create other objects in Box2D instead of using the TiledMap but not collide.

\$\endgroup\$
1
  • \$\begingroup\$ Is very strange. If I put a new Player, the physics work between the two players, but not in the floor. prntscr.com/al9rlc \$\endgroup\$
    – Ildelian
    Mar 28 '16 at 20:40
0
\$\begingroup\$

You are setting your Bodies to be Static, and this indicates that they are 0 mass, and do not move.

Try setting the body type of your character to Dynamic instead.

https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/physics/box2d/BodyDef.BodyType.html

\$\endgroup\$
8
  • \$\begingroup\$ And not is the problem, I have two characters, one Static and one Dinamic. The Dynamic character can collide with the static character, but no with the floor. \$\endgroup\$
    – Ildelian
    Mar 30 '16 at 9:53
  • \$\begingroup\$ @Ildelian That is strange. Some other things you can try, is making the floor hitbox larger. Sometimes a small hitbox will cause instability with box2d. Another thing, make sure that your floor and your character on not on the same collision layer. \$\endgroup\$
    – jgallant
    Mar 30 '16 at 10:38
  • \$\begingroup\$ Yes, is very Strange. I have done this tests: \$\endgroup\$
    – Ildelian
    Mar 30 '16 at 14:15
  • \$\begingroup\$ 1 -> Load all the "RectangleMapObject" from the map and draw all with the same position and size, result: prntscr.com/am0k9d -> All the objects is in the same position and Physics works. \$\endgroup\$
    – Ildelian
    Mar 30 '16 at 14:15
  • \$\begingroup\$ 2 -> Load all the "RectangleMapObject" from the map and draw all with distinct position (Setting Manually) and same size, result: prntscr.com/am0myc -> All the objects is in different position and Physics works. \$\endgroup\$
    – Ildelian
    Mar 30 '16 at 14:15
0
\$\begingroup\$

I have found the problem.

TiledMAp is in Pixels. Box2D works in Meters. Scene2D works in Piexles

I need to convert the Units between meters and Pixels.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.