1

I know there are quite some questions (and answers) on this topic, but they all have different solutions, and none of them seems to be working in my case.

I'm developing a small test project with libGDX, in which I tried to add a simple tilemap. I created the tilemap using Tiled, which seems to be working quite good, except for the texture bleeding, that causes black lines (the background color) to appear between the tiles sometimes.


What I've tried so far:

I read several SO-questions, tutorials and forum posts, and tried almost all of the solutions, but I just don't seem to get this working. Most of the answers said that I would need a padding between the tiles, but this doesn't seem to fix it. I also tried loading the tilemap with different parameters (e.g. to use the Nearest filter when loading them) or rounding the camera's position to prevent rounding problems, but this did even make it worse.


My current setup:

You can find the whole project on GitHub. The branch is called 'tile_map_scaling'

At the moment I'm using a tileset that is made of this tile-picture: tile_map_texture

It has two pixels of space between every tile, to use as padding and margin.

My Tiled tileset settings look like this:

tileset_config

I use two pixels of margin and spacing, to (try to) prevent the bleeding here.

Most of the time it is rendered just fine, but still sometimes there are these lines between the tiles like in this picture (sometimes they seem to appear only on a part of the map):

texture_bleeding_example

I'm currently loading the tile map into the asset manager without any parameters:

public void load() {
    AssetManager manager = new AssetManager();
    manager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
    manager.setErrorListener(this);
    manager.load("map/map.tmx", TiledMap.class, new AssetLoaderParameters());
}

... and use it like this:

public class GameScreen {

    public static final float WORLD_TO_SCREEN = 4.0f;
    public static final float SCENE_WIDTH = 1280f;
    public static final float SCENE_HEIGHT = 720f;

    //...

    private Viewport viewport;
    private OrthographicCamera camera;
    
    private TiledMap map;
    private OrthogonalTiledMapRenderer renderer;
    
    public GameScreen() {
        camera = new OrthographicCamera();
        viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);

        map = assetManager.get("map/map.tmx");
        renderer = new OrthogonalTiledMapRenderer(map);
    }

    @Override
    public void render(float delta) {
        //clear the screen (with a black screen)
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
        moveCamera(delta);
        renderer.setView(camera);
        renderer.render();
        //... draw the player, some debug graphics, a hud, ...
        moveCameraToPlayer();
    }

    private void moveCamera(float delta) {
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            camera.position.x -= CAMERA_SPEED * delta;
        }
        else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            camera.position.x += CAMERA_SPEED * delta;
        }
        
        // ...

        //update the camera to re-calculate the matrices
        camera.update();
    }


    private void moveCameraToPlayer() {
        Vector2 dwarfPosition = dwarf.getPosition();
        
        //movement in positive X and Y direction
        float deltaX = camera.position.x - dwarfPosition.x;
        float deltaY = camera.position.y - dwarfPosition.y;
        float movementXPos = deltaX - MOVEMENT_RANGE_X;
        float movementYPos = deltaY - MOVEMENT_RANGE_Y;
        
        //movement in negative X and Y direction
        deltaX = dwarfPosition.x - camera.position.x;
        deltaY = dwarfPosition.y - camera.position.y;
        float movementXNeg = deltaX - MOVEMENT_RANGE_X;
        float movementYNeg = deltaY - MOVEMENT_RANGE_Y;
            
        camera.position.x -= Math.max(movementXPos, 0);
        camera.position.y -= Math.max(movementYPos, 0);
        
        camera.position.x += Math.max(movementXNeg, 0);
        camera.position.y += Math.max(movementYNeg, 0);
        
        camera.update();
    }
    
    // ... some other methods ...
}

The question:

I am using padding on the tilemap and also tried different loading parameters and rounding the camera position, but still I have this texture bleeding problem in my tilemap.
What am I missing? Or what am I doing wrong?

Any help on this would be great.

Tobias
  • 2,547
  • 3
  • 14
  • 29
  • How do you create your texture atlas of tiles? You don't want to have gaps between them, but rather bleed copies of their border pixels out from them. The LibGDX TexturePacker has a setting for this. But it also looks like your game uses pixel art, so you should probably be using Nearest filtering, which isn't susceptible to the edge bleeding issue in the first place. – Tenfour04 Aug 08 '20 at 13:45
  • I didn't create any atlas, but just tried to use a texture, that I found on itch.io. I think I now understand what the problem is. Thank you very much. – Tobias Aug 08 '20 at 14:23

3 Answers3

1

You need to pad the edges of your tiles in you tilesheet. It looks like you've tried to do this but the padding is transparent, it needs to be of the color of the pixel it is padding.

So if you have an image like this (where each letter is a pixel and the tile size is one):

AB
CB

then padding it should look something like this

 A  B 
AAABBB
 A  B
 C  C
CCCCCC
 C  C

The pixel being padded must be padded with a pixel of the same color.

(I'll try try create a pull request with a fix for your git-repo as well.)

bornander
  • 751
  • 8
  • 20
  • 1
    I think now I understand :) I tried to just use a tileset, that I found on itch.io without creating a texture atlas or something similar, so the margin is transparent instead of the edge colors (which doesn't realy make any sense now as I understand what they are used for). Could you point out any tutorials on how to create the correct graphics from the ones I am using? Already thank you very much. This helps me a lot :) – Tobias Aug 08 '20 at 14:21
  • 1
    I created a pull request for your tileset, it should fix the issue. As for a tool to do this, libGDX has a one called runnable-texturepacker.jar, it works on separate tile images and combines them into a sprite sheet. so I just split yours into multiple 128x128 images and then ran runnable-texturepacker.jar with a pack.json file configured for tile padding. – bornander Aug 08 '20 at 14:47
  • I just merged your pull request and it seems to be perfectly working now. Thank you very much! :) – Tobias Aug 08 '20 at 14:55
0

As a little addition to bornander's answer, I created some python scripts, that do all the work to generate a tileset texture, that has the correct edge padding (that bornander explained in his answer) from a texture, that has no padding yet.

Just in case anyone can make use of it, it can be found on GitHub: https://github.com/tfassbender/libGdxImageTools

Tobias
  • 2,547
  • 3
  • 14
  • 29
0

There is also a npm package that can extrude the tiles. It was built for the Phaser JS game library, but you could still use it. https://github.com/sporadic-labs/tile-extruder