Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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();
}
}
like image 893
Balkanko Avatar asked Nov 19 '25 00:11

Balkanko


1 Answers

Here is what your render function should look like

@Override
public void render(float delta) {

    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    // force a constant delta
    float gameDelta = 0.1f;

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

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

    // then set the view
    renderer.setView(camera);
    // last render
    renderer.render();
}

First, you will need to update your camera after setting the new position. Then, try to use a constant delta instead of the actual one which will lead to weird camera movement as the libgdx delta represents the amount of time between two frames and is not constant. This should remove the wavy effect you have in your game.

To understand your delta issue, I recommend reading this article http://gameprogrammingpatterns.com/game-loop.html

Ideally you would use an Entity System framework and a specific PhysicSystem and a MotionSystem to compute your player movement and decouple the player position computation from the rendering loop.

Libgdx comes with Ashley, you can also have a look at Artemis-odb which is a also great project and more complete than Ashley in my opinion.

like image 99
Alexandre GUIDET Avatar answered Nov 21 '25 18:11

Alexandre GUIDET



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!