Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags
(2 edits)

Box2D (1/2)

OK, we now have a level created ! Now it's time to read this map, and create the bodies !

First, we'll create a GameConstants class, that will contain a lot of constants that we need to have access during the game. That we'll make things easier to handle.

Here is the GameConstants.java :

public class GameConstants {
    //World constants
    public static float MPP = 0.05f;            //Meter/Pixel
    public static float PPM = 1/MPP;            //Pixel/Meter
    public static float BOX_STEP = 1/60f; 
    public static int BOX_VELOCITY_ITERATIONS = 6;
    public static int BOX_POSITION_ITERATIONS = 2;
    public static float GRAVITY = 0;
    public static float DENSITY = 1.0f;
    
    //Tiled Map constants
    public static int PPT = 32;                    //Pixel/Tile
    
    //Screen constants
    public static int NB_HORIZONTAL_TILE = 50;
    public static float SCREEN_WIDTH = MPP * NB_HORIZONTAL_TILE * PPT;
    public static float SCREEN_RATIO = (float)Gdx.graphics.getHeight()/(float)Gdx.graphics.getWidth();
    public static float SCREEN_HEIGHT = SCREEN_WIDTH * SCREEN_RATIO;
    
    //Hero constants
    public static float HERO_HEIGHT = 1.5f * PPT * MPP / 2;
    public static float HERO_WIDTH = HERO_HEIGHT / 2;
    public static float JETPACK_IMPULSE = 100;
    public static float TOM_ROTATION = 5;
}
  • There are World constants that are relative to Box2D. MPP and PPM are very important : By default in Box2D, 1 pixel = 1 m. Thus, the object you create by default are HUGE. And the Box2D simulation doesn't work for huge sizes and huge mass. Therefore the MPP and PPM factor conversions will be used to scale down the world and to sprites. For now I chose a conversion of 20 pixels for 1 meter.
  • There is also the Tiled Map Constant that is simply the size of one tile, 32 pixels in my case. That will be important to set up the camera.
  • The screen constants, that are actually camera constants, are there simply to chose the size of the viewport. For example, I chose I wanted my camera to display 50 tiles on the width. The number of tiles that will be displayed on the height will depend on the screen ratio.
  • An then I created the hero constants : His size, the power of his jetpack and the rotation speed.

All these are only starting values. As the development goes by, I will certainly modify these values according to the gameplay I want.

Now that we have these constants, we need a TiledMapReader to read the map we created and created bodies :

Here is the TiledMapReader.java :

public class TiledMapReader {

    private OrthographicCamera camera;
    private World world;
    private MapObjects objects;
    public Array<Obstacle> obstacles;
    public Hero hero;
    
    public TiledMapReader(final MyGdxGame game, TiledMap tiledMap, World world, OrthographicCamera camera){
        this.camera = camera;
        this.world = world;
        
        hero = new Hero(world, camera, tiledMap);
        
        objects = tiledMap.getLayers().get("Objects").getObjects();

        obstacles = new Array<Obstacle>();    
        
        for (RectangleMapObject rectangleObject : objects.getByType(RectangleMapObject.class)) {
            Obstacle obstacle = new Obstacle(world, camera, rectangleObject);
            obstacles.add(obstacle);
        }
    }
}

You can see, this calsse reads reads the tiledMap and create the hero and the objects. The TiledMapReader class read the layer, and find the layer called "Objects" in which I created the walls, and returns the object found in this layer. Then, for each object in this layer, if the object is a rectangle, we create an Obstacle and we put it in an Obstacle Array.

Here is the class Hero.java :

public class Hero {

    public Body heroBody;
    private BodyDef bodyDef;
    private FixtureDef fixtureDef;
    private PolygonShape heroShape;
    private float width, height, posXInit, posYInit;
    private Vector2 direction;
    
    public Hero(World world, Camera camera, TiledMap tiledMap){

        MapObjects personnages = (MapObjects)tiledMap.getLayers().get("Spawn").getObjects();

        width = GameConstants.HERO_WIDTH;
        height = GameConstants.HERO_HEIGHT;
        posXInit = (personnages.get("Tom").getProperties().get("x", float.class) + personnages.get("Tom").getProperties().get("width", float.class)/2) * GameConstants.MPP;
        posYInit = (personnages.get("Tom").getProperties().get("y", float.class) + personnages.get("Tom").getProperties().get("height", float.class)/2) * GameConstants.MPP;
        direction = new Vector2();
        
        heroShape = new PolygonShape();
        heroShape.setAsBox(width, height);
        
        bodyDef = new BodyDef();
        bodyDef.position.set(posXInit, posYInit);
        bodyDef.type = BodyType.DynamicBody; 
        
        heroBody = world.createBody(bodyDef);
        heroBody.setFixedRotation(false);
            
        fixtureDef = new FixtureDef();  
        fixtureDef.shape = heroShape; 
        fixtureDef.density = (float)(GameConstants.DENSITY/(width * height));
        fixtureDef.friction = 0.01f;  
        fixtureDef.restitution = 0.1f;  
        heroBody.createFixture(fixtureDef).setUserData("Tom"); 
        heroBody.setUserData("Tom");
        
        heroShape.dispose();
    }
    
    public void displacement(){    
        if(Gdx.input.isKeyPressed(Keys.W)){
            heroBody.applyForceToCenter(new Vector2(0, GameConstants.JETPACK_IMPULSE).rotate(heroBody.getAngle() * MathUtils.radiansToDegrees), true);
        }
        
        if(Gdx.input.isKeyPressed(Keys.A))
            heroBody.setAngularVelocity(GameConstants.TOM_ROTATION);
        else if(Gdx.input.isKeyPressed(Keys.D))
            heroBody.setAngularVelocity(- GameConstants.TOM_ROTATION);
        else
            heroBody.setAngularVelocity(0);
    }
    
    public float getX(){
        return heroBody.getPosition().x;
    }
    
    public float getY(){
        return heroBody.getPosition().y;
    }
    
    public Vector2 getOrigine(){
        return new Vector2(posXInit, posYInit);
    }
}

The Hero class reads the tiledMap, find the layer called "Spawn" and look for an object called "Tom". Then it get the coordinate of Tom and creates a body at this coordinates. This class contains a displacement() method to control the hero with WAD keys. There are also few others method that could be useful during the development.