LibGDX Tiled: Moving camera causes tiles to stutter/blur/wave

Viewed 978

I've tried searching all over for the solution to this problem and have had no luck; although I have tried various suggestions which I will detail below along with the issue.

I've created a very small and simple sample project to test rendering a Tiled map and setting up a camera with a viewport and some simple input handling so I can "pan" around the map with WASD. The problem is that when I try to pan around the map, I get weird effects with the map. These include:

  • Tiles "waving." By this I mean when I scroll up/down or across the screen will appear "wavy"
  • Glitchy / Stuttering screen. Camera will not appear smooth at times.
  • Tiles changing,(for example, the black bars on the yellow tiles will have one pixel of a different color yellow on the side or top when moving the camera. What side these "extra" pixels are on depends on which way the camera moves). I Think this is called texture bleeding but I am not sure.

The things I have tried:

  • Pad all tiles with the same color pixel on all sides (This gets rid of black horizontal lines on map)
  • Set filter to linear / nearest (Tried all combinations)
  • Play around with viewport
  • change speed of camera

Does any one have any ideas of what could be going wrong? I just wan't to make sure I understand how to render the map and move the camera properly without any issues before continuing.

Exact Code:

public class GameScreen implements Screen {
final Alpha game;

private OrthographicCamera camera;
private FitViewport viewport;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private Rectangle player;

public GameScreen(final Alpha game) {
    this.game = game;

    camera = new OrthographicCamera();
    viewport = new FitViewport(800, 480, camera);

    TmxMapLoader.Parameters params = new TmxMapLoader.Parameters();
    params.textureMinFilter = Texture.TextureFilter.Nearest;
    params.textureMagFilter = Texture.TextureFilter.Linear;
    map = new TmxMapLoader().load("simple_padded_same_color.tmx");
    renderer = new OrthogonalTiledMapRenderer(map);

    player = new Rectangle(32,32,32,32);
}

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

    // handle input
    if (Gdx.input.isKeyPressed(Input.Keys.A)) {
        player.setX(player.getX() - 200 * delta);
    }
    if (Gdx.input.isKeyPressed(Input.Keys.D)) {
        player.setX(player.getX() + 200 * delta);
    }
    if (Gdx.input.isKeyPressed(Input.Keys.W)) {
        player.setY(player.getY() + 200 * delta);
    }
    if (Gdx.input.isKeyPressed(Input.Keys.S)) {
        player.setY(player.getY() - 200 * delta);
    }

    camera.position.set(player.getX(), player.getY(), 0);

    renderer.setView(camera);
    renderer.render();
}

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

@Override
public void show() {
}

@Override
public void hide() {
}

@Override
public void pause() {
}

@Override
public void resume() {
}

@Override
public void dispose() {
    map.dispose();
    renderer.dispose();
}
}
2 Answers

For anybody stumbling upon this question, I've been googling and trying stuff for about a week. I've finally fixed it so I'll share what I did.

  1. Add padding to your tile-set and maybe character. I also used duplicate padding.
  2. Check your interpolation functions and make sure they aren't the issue (in one case one of the interpolation methods I was using was making the effect worse).
  3. Change your ortho camera initialization. Originally I had my camera set to draw 25x19 tiles. Changing this number would sometimes fix the issue but then the map would be distorted. Here is what I used:
camera.setToOrtho(false, Gdx.graphics.getWidth() / TILE_SIZE / 2f, Gdx.graphics.getHeight() / TILE_SIZE / 2f);

TILE_SIZE is your tile (PPU?). My tiles are 16x16 so the value is 16. My map renderer was initialized with a value of 1 / 16.0f

If you are using a viewport you can also apply this in the resize method.

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height, false);
        camera.setToOrtho(false, width / 16f / 2f, height / 16f / 2f);
    }

Stuff I did to debug the issue:

  1. Profiling, which didn't really show anything.
  2. Making sure I wasn't creating any objects in render/update loop.
  3. Change my time step various times.
  4. Strip down the code to barebones level.
Related