Advertisement

How Could i Update a Vertex Array Tile Map?

Started by January 11, 2024 03:49 AM
2 comments, last by yusuf0 11 months ago

HI. I m trying to learn creating tilemap with vertex array. I found a code from a tutorial but i didnt understand completely this code:

class TileMap : public sf::Drawable, public sf::Transformable
{
public:

    bool load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height)
    {
        // load the tileset texture
        if (!m_tileset.loadFromFile(tileset))
            return false;

        // resize the vertex array to fit the level size
        m_vertices.setPrimitiveType(sf::Quads);
        m_vertices.resize(width * height * 4);

        // populate the vertex array, with one quad per tile
        for (unsigned int i = 0; i < width; ++i)
            for (unsigned int j = 0; j < height; ++j)
            {
                // get the current tile number
                int tileNumber = tiles[i + j * width];
                // find its position in the tileset texture
                int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
                // get a pointer to the current tile's quad
                sf::Vertex* quad = &m_vertices[(i + j * width) * 4];

                // define its 4 corners
                quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y);
                quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y);
                quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y);

                // define its 4 texture coordinates
                quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);

                quad[0].color = sf::Color(shadow, shadow, shadow, 255);
                quad[1].color = sf::Color(shadow, shadow, shadow, 255);
                quad[2].color = sf::Color(shadow, shadow, shadow, 255);
                quad[3].color = sf::Color(shadow, shadow, shadow, 255);
            }
        return true;
    }

private:
    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // apply the transform
        states.transform *= getTransform();
        // apply the tileset texture
        states.texture = &m_tileset;
        // draw the vertex array
        target.draw(m_vertices, states);        
    }
    sf::VertexArray m_vertices;
    sf::Texture m_tileset;
};

int main()
{

    // create the tilemap from the level definition
    TileMap tilemap;
    if (!tilemap.load("tilemap.png", sf::Vector2u(100, 100), level, 100, 100))
        return -1;

    //drawing tilemap
    window.draw(tilemap);


}

My question is how could i update only 1 tile or all tiles? For exaple i will detect collision between tiles and player characters. Or i would like to change tile colors etc.

If you can explain with minimal example code then i will appreciate for that. Thanks for all answers.

yusuf0 said:
HI. I m trying to learn creating tilemap with vertex array. I found a code from a tutorial but i didnt understand completely this code:

What do you not understand about it? And why do you want to do your own tile maps, although SFML already has that implemented? (I assume you use SFML, because the code seemingly does.)

yusuf0 said:
My question is how could i update only 1 tile or all tiles? For exaple i will detect collision between tiles and player characters. Or i would like to change tile colors etc.

There are many options.
The easiest is to regenerate the vertices on CPU and uploading them to GPU each frame.
Basically you would need to call above code each frame, but replacing load from disk with a copy from memory where you currently store your dynamic map.

The problem is probably the upload to GPU which takes most time.
So you could instead just upload the map (likely just one byte per tile), and use a compute shader to generate the vertex data on GPU. (Geometry shader might be a alternative, generating one quad per tile on the fly.)
If the map is too big, you could only upload a range of it, e.g. the rectangle representing the current screen.
The compute shader would then only update what's in the rectangle.

But if you don't need the whole map on GPU, you could instead just upload what's currently on screen anyway, probably eliminating all performance worries. Then you can do anything on CPU, and uploading the small vertex buffer should be no problem at all. Basically you only need to add frustum culling to the code.

Advertisement

This topic is closed to new replies.

Advertisement