1
\$\begingroup\$

I want to get the tile that my cursor is over in my game.

I did some googling though most of the examples we're in other languages/libraries and if they weren't, they didn't work for me because I use a sf::view.


So, what I currently have is a tile generator which works like this :

GameScreen.h :

std::vector<sf::Sprite*> tiles;
std::map<std::string, sf::Texture*> textures;

GameScreen.cpp :

void GameScreen::Init()
{
    std::cout << "Loading map" << std::endl;
    textures.insert(std::make_pair("Grass", new sf::Texture()));
    if (!textures["Grass"]->loadFromFile("Res/Textures/Grass.png"))
        std::cout << "Could not load texture : Grass.png" << std::endl;

    for (int y = 0; y < MapSize; y++)
    {
        for (int x = 0; x < MapSize; x++)
        {
            sf::Sprite* tile = new sf::Sprite();
            tile->setTexture(*textures["Grass"]);
            tile->setPosition(x * 32, y * 32);
            tiles.push_back(tile);
            std::cout << "Loading : " << tiles.size() << " / " << MapSize * MapSize << std::endl;
        }
    }

    std::cout << "Map loaded!" << std::endl;

    initialized = true;
}

How would I get the tile my cursor is currently over, even if my sf::view is moving?


This is how the newest code is looking :

Calling the get tiles function :

gameScreen.GetSpriteByPosition(window.mapPixelToCoords(sf::Mouse::getPosition(window), view));

Inside the get tile function :

sf::Sprite* GameScreen::GetSpriteByPosition(sf::Vector2f mousePos)
{
    sf::FloatRect mouseBound(mousePos, sf::Vector2f(1, 1));

    for (int i = 0; i < tiles.size(); i++)
    {
        if (tiles[i]->getGlobalBounds().intersects(mouseBound))
        {
            std::cout << "Found tile, index : " << i << std::endl;
            return tiles[i];
        }
        std::cout << "not found" << std::endl;
    }

    return nullptr;
}
\$\endgroup\$

3 Answers 3

1
\$\begingroup\$

SFML has a few good functions that allows you to do what you want a bit simpler

window.mapPixelToCoords(sf::Mouse::getPosition(window), viewRect);

That line of code will convert the mouse position relative to the window (sf::Vector2i), to a world coordinate (sf::Vector2f). I have the window as an argument there, or else it will get the mousePos relative the the monitor

Luckily, SFML has it's own built in collision checking function in sf::FloatRect, so you don't need to write out the checking for if a x is less than another x and that

sf::Sprite getTile(sf::Vector2f mousePos)
{
    sf::FloatRect mouseBound(mousePos, sf::Vector2f(1, 1)); // create a floatRect with the mouse position for collision checking
    for (int i = 0; i < allTiles.size(); i++)
    {
        if (allTiles[i].getGlobalBounds().intersects(mouseBound))
            {
                std::cout << "Found tile at " << i << std::endl;
                return allTiles[i];
            }
    }

    return nullptr;
}

Combine the mousePos check above, and the code here below, and it should work out fine. If you have any questions about the stuff I used, make sure to ask.

Your edited code at time of the comment didn't work, because of that else statement. You check if the mouse hits the VERY FIRST tile, and if it doesn't return null

Documentation:

sf::Mouse::getPosition

sf::RenderTarget::mapPixelToCoords

\$\endgroup\$
3
  • \$\begingroup\$ Tried this but it does not work. Updated the post again with my new code. :3 \$\endgroup\$
    – BiiX
    Commented Jan 24, 2016 at 13:10
  • 1
    \$\begingroup\$ It's because you are returning nullptr on the FIRST LOOP. Remove that "return nullptr" in the for loop, and your golden \$\endgroup\$
    – TCVM
    Commented Jan 24, 2016 at 20:01
  • \$\begingroup\$ Of course, didn't notice that! Works perfectly now! Thank you! :) \$\endgroup\$
    – BiiX
    Commented Jan 24, 2016 at 20:06
2
\$\begingroup\$

Figure out your mouse position in world space and divide by the tile size.

Basically keep track of where your upper left corner is in world space, add the mouse position to that (with appropriate scaling etc.) and then divide it by your tilesize.

\$\endgroup\$
2
\$\begingroup\$

First off, you should really store the tiles in a 2d array. As far as I can tell from documentation, sf::View has a getViewport() method. This method gives the coordinates of the top-left point of your view. Next you will need the coordinate of the mouse, in relation to the top-left of your window. Finally, you add the two coordinates together, and you'll have the world-space coordinates of the mouse. From here, it's a matter of basic integer divisions to get the tile you are currently hovering.

const int TILE_WIDTH = 32;
const int TILE_HEIGHT = 32;

Sprite tiles[][] = { ... }

sf::View* view = { ... }
sf::Rect viewRect = view->getViewport();
int mouseX = { ... }
int mouseY = { ... }
int worldX = viewRect.x + mouseX;
int worldY = viewRect.y + mouseY;

int tileX = worldX / TILE_WIDTH;
int tileY = worldY / TILE_HEIGHT;

Sprite tile = tiles[tileX][tileY];

This is just off the top of my head, it may contain errors.

\$\endgroup\$
6
  • \$\begingroup\$ After doing this how would I get the actual object of the sprite or it's position in the 2d array? \$\endgroup\$
    – BiiX
    Commented Jan 23, 2016 at 13:04
  • 1
    \$\begingroup\$ tileX and tileY holds the position of the tile, in "tile-space". So if you have a 2d array, you would simply do as shown on the last line. \$\endgroup\$
    – William
    Commented Jan 23, 2016 at 13:14
  • \$\begingroup\$ Ah, I see. Do you know how to do it if I have to use a vector? \$\endgroup\$
    – BiiX
    Commented Jan 23, 2016 at 13:32
  • \$\begingroup\$ Maybe I could somehow use getGlobalBounds to do this? Comparing mouse position to the sprites globalBounds? \$\endgroup\$
    – BiiX
    Commented Jan 23, 2016 at 13:45
  • 1
    \$\begingroup\$ If you want to rely on checking each tiles bound, you would simply use the worldX and worldY to check if that point is inside the sprites bounds. This isn't very efficient though as the complexity goes from O(1)(constant) to O(n)(linear), meaning the more tiles, the slower your program is. \$\endgroup\$
    – William
    Commented Jan 23, 2016 at 14:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .