Advertisement

Tiled SDL 2D Tilemap Glitch

Started by November 30, 2017 02:06 AM
7 comments, last by Grumn Gaming 7 years, 2 months ago

I have a simple openGL engine using SDL working. I'm not using any SDL_Image stuff, its all just openGL. I've made 2d tilemap levels with a .txt file before by reading in the characters and using a switch statement to assign them to various textures and using their position in the file to render them. This method works fine and produces no graphical glitches.

Then I made a .tmx map in Tiled and used TmxParser to read the file into my program, and I'm able to render the map properly to the screen, but when I move up and down these black lines start to appear between the tiles.

The map loads in fine at first, its only once I start moving the camera around that it happens, and its only when the camera moves up or down.

I made a video to show exactly what I'm seeing, I see a lot of these type of issues when searching google but nothing that matches whats happening to me.

" rel="external">

I'm not even sure if this is a problem with the code or what it could be so I don't know of any code to include.

This problem also happened to me when I was using Unity and importing a Tiled map with Tiled2Unity. In unity there were long horizontal line glitches on the tilemap, and now its happening to me again in c++, is this something to do with Tiled?

Has anyone encountered this before or know a solution?

Any help would be greatly appreciated, I feel stuck on this issue.

 

floating point precision.  please post the code with the snippet where you do the actual drawing.

Advertisement

  // Iterate through the tile layers.

    for (int i = 0; i < map->GetNumTileLayers(); ++i)
    {
        printf("                                    \n");
        printf("====================================\n");
        printf("Layer : %02d/%s \n", i, map->GetTileLayer(i)->GetName().c_str());
        printf("====================================\n");

 

        // Get a layer.
        const Tmx::TileLayer *tileLayer = map->GetTileLayer(i);

        for (int y = 0; y < tileLayer->GetHeight(); ++y)
        {
            for (int x = 0; x < tileLayer->GetWidth(); ++x)
            {
                //Flip y axis to convert from tiled format, tiled starts top left, we start bottom left
                glm::vec4 destRect(x * tileWidth, (tileLayer->GetHeight() * tileHeight) - (y * tileHeight)/* + (y * 1)*/, tileWidth, tileHeight);

                if (tileLayer->GetTileTilesetIndex(x, y) == -1)
                {
                    //printf("........    \n");
                }
                else
                {
                    // Get the tile's id and gid.
                    int tileId = tileLayer->GetTileId(x, y);
                    int tileGid = tileLayer->GetTileGid(x, y);
                    //printf("tileId:%d id:%03d gid:(%03d) firstGid:%03d", tileId, tileLayer->GetTileId(x, y), tileLayer->GetTileGid(x, y), map->FindTileset(tileGid)->GetFirstGid());
                    //int tileGid = tileLayer->GetTileGid(x, y);

                    // Find a tileset for that id.
                    const Tmx::Tileset *tileset = map->FindTileset(tileGid);

                    std::string imagePath = "x";

                    if (tileset->GetImage() != nullptr) {
                        imagePath = tileset->GetImage()->GetSource();
                    }
                    else {
                        SPH::fatalError("Could not find tileset source image.");
                    }

                    SPH::GLTexture texture = SPH::ResourceManager::getTexture(imagePath);

                    //printf("%s\n", tileset->GetImage()->GetSource().c_str());

                    SPH::TileSheet tileSheet;
                    tileSheet.init(texture, glm::ivec4(tileset->GetImage()->GetWidth() / tileWidth,
                        tileset->GetImage()->GetHeight() / tileHeight,
                        tileWidth, tileHeight));

                    m_spriteBatches[0].render(destRect, tileSheet.getUVs(tileId), texture.id, 1.0f, whiteColor);
 

Sprite.h

Sprite.cpp

Level.cpp

SpriteBatch.h

SpriteBatch.cpp

TileSheet.h

I think what you're saying is I'm using floating point numbers in my tileSheet.getUVs, is that correct? If I changed them to ints it would be fine? Or floating point numbers in my destRect?

Yep, that's exactly it. You should "floor" (i.e. round toward negative infinity; note that this is not quite the same as truncation) every position before drawing there. Otherwise some go to the right and some go to the left, and what you end up with is a mess.

Floor doesn't change anything.

 

glm::vec4 destRect(x * tileWidth, (tileLayer->GetHeight() * tileHeight) - (y * tileHeight), tileWidth, tileHeight);

printf("Dest Rect: x: %f, y: %f, width: %.5f, height: %.5f\n", destRect.x, destRect.y, destRect.z, destRect.w);

x and y are already ints, tileWidth and tileHeight are ints, and tileLayer->GetHeight() returns an int.

There are no floats anywhere in my destRect coords, I did a printf on the destRect to confirm nothing changed when I added floor.

The printf result looks like this:

Dest Rect: x: 736.000000, y: 32.000000, width: 32.000000, height: 32.000000

Where does floating point precision come in here?

that may be the case, however, you are using some kind of camera somewhere that has floating points as its position.  what framework are you using?  SDL?  SFML?

ultimately underneath that framework is OpenGL.  And you may be giving the tile positions in "ints" (although it is a float hence the xxx.00000), but the transform done by the camera the location on screen ends up being in floats with actual values past the decimal.

I used SFML before in my life.  Look into using a sf::VertexArray (or whatever it is called) to do a mass tilemap drawing.  It is more efficient and will clean up those problems.  If you are using SDL then someone else may be able to help you.

 

Advertisement

Yes I’m using sdl but not for the rendering code, that is all OpenGL, but this gives me a place to start messing around with it, thank you. Maybe I need to make the tranform that holds my camera position from a glm::vec4 to a glm::ivec4 Or floor() the x and y positions in the camera class

Thank you djsteffey and juliemaru! The problem was 100% floating point precision and it was fixed by adding floor to the camera update code!

 

glm::vec3 translate(std::floor(-_position.x + _screenWidth/2), std::floor(-_position.y + _screenHeight/2), 0.0f);
_cameraMatrix = glm::translate(_orthoMatrix, translate);

 

Works perfectly now, I can't believe it, thank you so much!

 

Here is the end result:

Ive never thought something so bad looked so good,

 

This topic is closed to new replies.

Advertisement