Search code examples
javalibgdx

LibGDX float with camera position causing black lines with Tiled map


I am creating a top-down shooter game, and whenever I move the camera, or zoom, black likes appear like a grid image

I am using Tiled to create the map, and I have the camera following my centered box2d body. I have found that making the camera position equal the position of the box2d body with an int cast results in the black lines disappearing like this: image

The problem though, is that because I have the game scaled down, the player will move for a second or two and then when the player reaches the next whole number on either axis, the camera snaps to the player, which is not what I want for the game as it's jarring. The player's movement is granular, but, while rounded, the camera's is not. I do not know if this is a problem with my tile sheet or if it's something I can fix by altering some code. I have tried all different kinds of combinations of padding, and values of spacing and margins. So ultimately, how can I have the camera match the player's position smoothly and not cause the black lines? I'd greatly appreciate any help or recommendations. Thank you in advance!

Where I am type casting the player's float position to an int in game class:

    public void cameraUpdate(float delta) {

    //timeStep = 60 times a second, velocity iterations = 6, position iterations = 2
    world.step(1/60f, 6, 2); //tells game how many times per second for Box2d to make its calculations
    cam.position.x = (int)playerOne.b2body.getPosition().x;
    cam.position.y = (int)playerOne.b2body.getPosition().y;

    cam.update();
}

Majority of player class:

public class PlayerOne extends Sprite implements Disposable{
public World world; // world player will live in
public Body b2body; //creates body for player
private BodyDef bdef = new BodyDef();
private float speed = 1f;
private boolean running;
TextureAtlas textureAtlas;
Sprite sprite;
TextureRegion textureRegion;
private Sound runningSound;



public PlayerOne(World world) {
    this.world = world;
    definePlayer();
    textureAtlas = new TextureAtlas(Gdx.files.internal("sprites/TDPlayer.atlas"));
    textureRegion = textureAtlas.findRegion("TDPlayer");
    sprite =new Sprite(new Texture("sprites/TDPlayer.png"));
    sprite.setOrigin((sprite.getWidth() / 2) / DunGun.PPM, (float) ((sprite.getHeight() / 2) / DunGun.PPM - .08));
    runningSound = Gdx.audio.newSound(Gdx.files.internal("sound effects/running.mp3"));

}


public void definePlayer() {
    //define player body
    bdef.position.set(750 / DunGun.PPM, 400 / DunGun.PPM);

    bdef.type = BodyDef.BodyType.DynamicBody;
    //create body in the world
    b2body = world.createBody(bdef);

    FixtureDef fdef = new FixtureDef();
    CircleShape shape = new CircleShape();
    shape.setRadius(12 / DunGun.PPM);

    fdef.shape = shape;
    b2body.createFixture(fdef);
}

public void renderSprite(SpriteBatch batch) {
    float posX = b2body.getPosition().x;
    float posY = b2body.getPosition().y;
    float posX2 = (float) (posX - .14);
    float posY2 = (float) (posY - .1);
    sprite.setSize(32 / DunGun.PPM, 32 / DunGun.PPM);
    sprite.setPosition(posX2, posY2);
    float mouseX = Level1.mouse_position.x; //grabs cam.unproject x vector value
    float mouseY = Level1.mouse_position.y; //grabs cam.unproject y vector value

    float angle = MathUtils.atan2(mouseY - getY(), mouseX - getX()) * MathUtils.radDeg; //find the distance between mouse and player

    angle = angle - 90; //makes it a full 360 degrees
    if (angle < 0) {
        angle += 360 ;
    }
    float angle2 = MathUtils.atan2(mouseY - getY(), mouseX - getX()); //get distance between mouse and player in radians
    b2body.setTransform(b2body.getPosition().x, b2body.getPosition().y, angle2); //sets the position of the body to the position of the body and implements rotation
    sprite.setRotation(angle); //rotates sprite
    sprite.draw(batch); //draws sprite
    }

public void handleInput(float delta) {
    setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2 + (5 / DunGun.PPM));

    this.b2body.setLinearVelocity(0, 0);

    if(Gdx.input.isKeyPressed(Input.Keys.W)){
        this.b2body.setLinearVelocity(0f, speed);
    }if(Gdx.input.isKeyPressed(Input.Keys.S)){
        this.b2body.setLinearVelocity(0f, -speed);
    }if(Gdx.input.isKeyPressed(Input.Keys.A)){
        this.b2body.setLinearVelocity(-speed, 0f);

    }if(Gdx.input.isKeyPressed(Input.Keys.D)){
        this.b2body.setLinearVelocity(speed, 0f);

    }if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.A)){
        this.b2body.setLinearVelocity(-speed, speed);

    }if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.D)){
        this.b2body.setLinearVelocity(speed, speed);
    }
    if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.A)){
        this.b2body.setLinearVelocity(-speed, -speed );

    }if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.D)){
        this.b2body.setLinearVelocity(speed, -speed);
    } 

Where I declare the pixels per meter scale:

public class DunGun extends Game{
public SpriteBatch batch;
//Virtual Screen size and Box2D Scale(Pixels Per Meter)
public static final int V_WIDTH = 1500;
public static final int V_HEIGHT = 800;
public static final float PPM = 100; //Pixels Per Meter

Game render and resize methods:

    @Override
public void render(float delta) {
    cameraUpdate(delta);
    playerOne.handleInput(delta);
    //clears screen
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
        cam.zoom -= .01;

    }
    if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
        cam.zoom += .01;

    }


    mapRenderer.render();
    b2dr.render(world, cam.combined); //renders the Box2d world

    mapRenderer.setView(cam);
    //render our game map
    //mapRenderer.render(); // renders map
    //mapRenderer.render(layerBackround); //renders layer in Tiled that p1 covers
    game.batch.setProjectionMatrix(cam.combined); //keeps player sprite from doing weird out of sync movement

    mouse_position.set(Gdx.input.getX(), Gdx.input.getY(), 0);
    cam.unproject(mouse_position); //gets mouse coordinates within viewport
    game.batch.begin(); //starts sprite spriteBatch

    playerOne.renderSprite(game.batch);

    game.batch.end(); //starts sprite spriteBatch
    //mapRenderer.render(layerAfterBackground); //renders layer of Tiled that hides p1
}


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

Solution

  • I solved it by fiddling around with the padding of the tilesets in GDX Texture Packer. I added 5 pixels of padding around the 32x32 tiles. I set the margins to 2, and spacing to 4 in Tiled. I had tried a lot of different combinations of padding/spacing/margins that didn't work which made me think it was a coding problem, but those settings worked, and I didn't have to round the floats.