简体   繁体   中英

How to prevent texture bleeding in a tilemap in LibGDX

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 (eg 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:

瓦片集配置

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.

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.)

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM