SFML community forums

Help => Graphics => Topic started by: Boute on April 14, 2017, 12:26:35 pm

Title: [SOLVED] How to change pixels on a big map
Post by: Boute on April 14, 2017, 12:26:35 pm
Hi,

I’m working on a game project. The game is a Quizz where a name of a country appear on the screen and you have to click on the right country on a map.

I’m having trouble with a module of my game : I want that when your mouse is passing over a country, it changes its color, and when the country is found, its color is green etc.
Here is a pic to demonstrate what i’ve achieved (the mouse is over the France) :

(http://www.pictures-cloud.fr/uploads/477515e6fd7c8ae78d8dc91e4cbc42c5/thumb-geoquizz_forum.-3e12b88aa61e66ab904f3c991ea02e57.jpg) (http://www.pictures-cloud.fr/large-477515e6fd7c8ae78d8dc91e4cbc42c5/geoquizz_forum.-3e12b88aa61e66ab904f3c991ea02e57.jpg.html)

Here is how my program works :
•   Each country has a pixel array in the Country class :
std::vector<sf::Vector2u> PixelsArray
It is charged at the start of the game using a Boundary-Fill-like algorithm.
The pixel array countains the position of each pixel of the country.

•   When the mouse is over a country, a fonction in the Map class is called.
Here is how it works :
void Map::fill(std::vector <sf::Vector2u>& pixelsArray, sf::Color newColor)
{
        //Exit the function if we fill with the color of the boundaries
        if (newColor == borderColor)
                return;

        for (int i = 0; i < pixelsArray.size(); i++)
                imageMap.setPixel(pixelsArray[i].x, pixelsArray[i].y, newColor);

        texture.loadFromImage(imageMap);
        map.setTexture(texture);
}
I use an image of the map to transform the pixels and then i am updating the texture of map’s sprite with this image.


The problem is that my map is 3958 * 2596 and it takes about a second to update the texture. So each time i move my mouse over a country, when it wants to update the color to the selected color, my game freeze for one second. I noticed that it doesn’t come from the pixel Array loop but more from the part :
texture.loadFromImage(imageMap);
map.setTexture(texture);

I've tried to reduce the Map's texture to what the player is able to see (the view) so it is by exemple 1700*1050 when the player is on the Europe continent, but it's too slow too.

I've thinked about update texture with :
void sf::Texture::update        (       const Uint8 *   pixels,
unsigned int    width,
unsigned int    height,
unsigned int    x,
unsigned int    y
)      

but it would be very difficult to set an IntRect for each country etc.

Actually what could be perfect, is to use something like
void sf::Texture::update        (       const Uint8 *   pixels  )
with the position of each pixels (wich I already have). In other words, updating the texture with only the pixels of a country (with my country's sf::Vector2u pixel array)

Thank you for your attention, I hope you will understand : P
Title: Re: How to change pixels on a big map
Post by: UroboroStudio on April 14, 2017, 02:36:35 pm
You might consider getting rid of that big texture (map) and use sf::Sprite for each country.

It will be more fast, and much more less expensive for your computer.

The idea is to create one texture for each country, load them at the start in a std::vector<sf::Sprite> and asign each sprite his position on the "map". Use window.clear(dark blue) for the background, and Sprite.setColor(light blue) for the country.

sf::Sprite country;
country.setColor(sf::Color::Blue);
country.SetPosition(pos);
vCountry.pushback(country);

Now, you need a method to know when the mouse is over any country. You can use Sprite.getGlobalBounds().contains(Mouse Position) to check it. But it's not a precise method because the FloatRect of a Sprite is a square shape and can overlay with any other country nearby.

So I will say to check if the mouse position is inside the bounds of a contry Sprite and IF so, then perform a pixel perfect check to be sure the mouse IS inside the country.

for (int i = 0; i < vCountry.size(); ++i)
{
    if (vCountry[i].getGlobalBounds().contains(mouse) && pixel_perfect(vCountry[i], mouse)
    {
        vCountry[i].setColor(Grey);
    }
}

For drawing, you only have to iterate through the vector of sprites and draw them.

window.clear(Dark Blue);

for (int i = 0; i < vCountry.size(); ++i) window.draw(vCountry[i])

window.display()
Title: Re: How to change pixels on a big map
Post by: Boute on April 14, 2017, 03:58:23 pm
Thank you Uroboro for your answer.

I already thought to do this way at the begining of my project. It is really easier in the use. But i gave up for some reason :

However, after a reflexion, I think I'll go this way. I will get the texture of each country with the Photoshop's magical wand tool and it will be much easier to use it in the code than what I started to do (I started to do a vertex-array (triangle strip) for each country to do an approximate shape and then detect if the mouse is over this shape by detecting if the mouse is over one of the triangles of the triangle strip ...) It'll be faster to take the texture with the Wand than writing the coordinates of each vertex of the country's shape. So thank you for your help ! =)

I still hope someone can find an other solution using the map texture, it could save me a lot of time.
Title: Re: How to change pixels on a big map
Post by: Arcade on April 14, 2017, 06:00:47 pm
If time is an issue you could continue using your large texture as the background, but instead of modifying the texture to apply a color, you could overlay a colored sprite of the country at that position. You can then just skip creating the sprites for the countries you don't want to implement.
Title: Re: How to change pixels on a big map
Post by: Boute on April 14, 2017, 06:33:59 pm
Yes you're right but if I overlay with a sprite of country, it won't take so many extra time to assign a texture to a country with this sprite. It's almost what I am doing : I am making a texture for many countries and then I'll put them over the big map so I'll keep the little countries I've not made. Actually I just started and doing a texture for each country is not so long and it will probably simplify my code.

Anyway thank you for your answer ; )
Title: Re: How to change pixels on a big map
Post by: Mortal on April 14, 2017, 06:36:58 pm
first think comes to my mind is using polygon shape for each country. did you consider it?
Title: Re: How to change pixels on a big map
Post by: Boute on April 14, 2017, 06:47:15 pm
I think it looks too complicated to construct a polygon shape for each country wich fits exactly like the country's shape on the map. I started to do an approximative polygon of vertex array for mouse-detection for few countries and it took a lot of time to put each vertex at the correct position. So i don't imagine with an almost perfect polygon to draw a country.