3

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();
}
}
Balkanko
  • 31
  • 2
  • First thing, you should call `camera.update()` after setting the new position. Next, try to use a constant delta instead of the delta provided by libgdx which is dependent of your computer power. – Alexandre GUIDET Aug 16 '17 at 04:21

2 Answers2

0

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.

Alexandre GUIDET
  • 852
  • 9
  • 27
0

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.
ccw
  • 1