SFML community forums

Help => Graphics => Topic started by: epilepticPi on July 13, 2016, 10:38:30 pm

Title: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 13, 2016, 10:38:30 pm
Dear reading forum user,
i used this script to check if a sprite was clicked:
bool isTileClicked(sf::Sprite sprite)
{
        if(sf::Mouse::getPosition().x > sprite.getPosition().x
                && sf::Mouse::getPosition().x < sprite.getPosition().x + (sprite.getScale().x * 275)
                && sf::Mouse::getPosition().y > sprite.getPosition().y
                && sf::Mouse::getPosition().y < sprite.getPosition().y + (sprite.getScale().y * 275)
                && sf::Mouse::isButtonPressed(sf::Mouse::Left)
                )
        {
                return true;
        }
        else
        {
                return false;
        }
}

In the loop/grid loop i wrote:
if(isTileClicked(unselectedGrid) == true)
                                {
                                        unselectedGrid.setTexture(selected);
                                }

But only the sprite 2 below and 1 to the right was highlighted.

How can i fix that?

Just ask if you need more snippets.

EDIT:
I used the relative mouse position and getglobalbounds to create a new function but now the tile below is highlighted
Title: Re: Clicking on a Sprite to highlight it
Post by: Mortal on July 14, 2016, 12:15:26 am
hard to tell what may cause the problem, but here few hints:

the sf::Mouse::getPosition() will gives the global position and i think you may need the position of mouse relative to window.
and for detecting whether or not the mouse position contains with sprite rectangle bounds is simple by call the sf::Sprite::getGlobalBounds() which will take care of sprite's transformation and returned a sf::Rect which has contain().

these will do exactly what you are trying to achieve.
Title: Re: Clicking on a Sprite to highlight it
Post by: TheGuerilla on July 14, 2016, 03:47:47 am
First off, I would make a function to check if a given coordinate is within a given bounding box; pointInRectangle is what I usually call it. That function would look like
inline int clamp(int val, int min, int max) {
    val = val < min ? min : val;
    val = val > max ? max : val;
    return val
}

inline bool pointInRectangle(int x, int y, int x1, int y1, int x2, int y2) {
    return (clamp(x, x1, x2) == x && clamp(y, y1, y2) == y);
(You need clamp to make pointInRectangle even easier to read)
With that function, you could just say
int x sf::Mouse::getPosition().x;
int y sf::Mouse::getPosition().y;
int x1 = sprite.getPosition().x;
int y1 = sprite.getPosition().y;
int x2 = sprite.getPosition().x + (sprite.getScale().x * 275);
int y2 = sprite.getPosition().y + (sprite.getScale().y * 275);
if (pointInRectangle(x, y, x1, y1, x2, y2) && sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
    // Do stuff...
}
Of course you could remove all the variables I set there, I just hate looking at that much within parameters.
Title: Re: Clicking on a Sprite to highlight it
Post by: Hapax on July 14, 2016, 03:17:23 pm
(click to show/hide)
A custom, manual solution is not really required for this since - as Mortal already mentioned - SFML has methods to do this checking already.
Therefore:
// window is the sf::RenderWindow that you are using and sprite is the sf::Sprite
const sf::Vector2f mousePosition = window.mapPixelToCoords(sf::Mouse::getPosition(window));
const bool isMouseInSprite = sprite.getGlobalBounds().contains(mousePosition);
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 14, 2016, 09:44:19 pm
Ive followed Hapax and Mortals tipps and reworked my code but now the tile below is highlighted
Title: Re: Clicking on a Sprite to highlight it
Post by: Mortal on July 14, 2016, 10:19:05 pm
if your project is fairly small post the code or write minimal example to demonstrate the issue. this will help us to fix the problem in your code.
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 14, 2016, 10:45:56 pm
#include "stdafx.h"
#include <SFML\Graphics.hpp>
#include <SFML\Window.hpp>
#include <iostream>
#include <string>

sf::RenderWindow window(sf::VideoMode(1600, 900), "Name");


int main()
{

        sf::Font font_freeSans;
        font_freeSans.loadFromFile("FreeSans.ttf");

        sf::Texture station_texture;
        station_texture.loadFromFile("station_cockpit_texture.png");

        sf::Texture selected;
        selected.loadFromFile("selected.png");

        sf::Texture unselected;
        unselected.loadFromFile("unselected.png");   //LOADING TEXTURES


        sf::Sprite unselectedGrid;
        unselectedGrid.setTexture(unselected);
        unselectedGrid.setScale(0.5, 0.5);

        while(window.isOpen())
        {
                sf::Vector2f mousePosition = window.mapPixelToCoords(sf::Mouse::getPosition(window));

                window.clear();

                sf::Event event;
                while(window.pollEvent(event))
                {
                        if(event.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                }
                for(int x = 0; x < 5; x++)
                {
                        for(int y = 0; y < 5; y++)
                        {
                                if (unselectedGrid.getGlobalBounds().contains(mousePosition))
                                {
                                        unselectedGrid.setTexture(selected);
                                }
                                if(x == 2 && y == 2)
                                {
                                        unselectedGrid.setTexture(station_texture);
                                }
                                unselectedGrid.setPosition(x * 137.5, y * 137.5);
                                window.draw(unselectedGrid);
                                std::cout << "Tile created (" << x << "," << y << ")" <<  std::endl;
                                unselectedGrid.setTexture(unselected);
                        }
                }

                window_spaceport.display();
        }

    return 0;
}
 
Title: Re: Clicking on a Sprite to highlight it
Post by: Hapax on July 14, 2016, 11:35:31 pm
You need to do the bounds checking when the sprite is in the place that you want to check it with. You are currently checking one position and then moving it before drawing it. Set the position first.
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 15, 2016, 12:26:59 am
Thanks! worked.
Title: Re: Clicking on a Sprite to highlight it
Post by: Hapax on July 15, 2016, 01:03:50 am
You're completely welcome! :)

It looks like you're attempting to draw a grid of tiles. Drawing a sf::Sprite multiple times (once for each tile) can be inefficient and you may want to consider having a look at sf::VertexArray (http://www.sfml-dev.org/tutorials/2.3/graphics-vertex-array.php). This way, you can draw all the tiles at once! There is a simple TileMap example (http://www.sfml-dev.org/tutorials/2.3/graphics-vertex-array.php#example-tile-map) on that tutorial page too.

However, you may want to consider something like Selba Ward's Tile Map (https://github.com/Hapaxia/SelbaWard/wiki/Tile-Map). Not only does it use a form of vertex array internally, it also allow movement around the 'level' (or 'map' - the definition of which tiles go where) and, maybe more importantly in your case, can return which tile is any particular point, even after transformations such as rotation.
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 15, 2016, 03:31:41 pm
Is it possible to make the tile stay selected? (general)
Title: Re: Clicking on a Sprite to highlight it
Post by: Hapax on July 17, 2016, 08:36:13 pm
Yes. Store which ones have been selected and which ones haven't (a collection of booleans - one for each tile), or just a list of the ones that have (a collection of tile IDs - IDs for each tile selected).
Then consult that store when drawing them.
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 19, 2016, 05:02:17 pm
I wrote this:
        int TileID[] = {0};
        sf::Texture zero;
        sf::Texture TileTexture[] = {zero};

if (unselectedGrid.getGlobalBounds().contains(mousePosition) && sf::Mouse::isButtonPressed(sf::Mouse::Left))
                                {
                                        unselectedGrid.setTexture(station);
                                        int id = (x+1) * (y+1);
                                        TileID[sizeof(TileID)] = id;
                                        TileTexture[sizeof(TileTexture)] = station;
                                       
                                }
for(int i = 0; i < sizeof(TileID); i++)
                                {
                                        if((x + 1) * (y + 1) == TileID[i])
                                        {
                                                unselectedGrid.setTexture(TileTexture[i]);
                                        }
                                }

 

But i get "Access violation at memory..."
But just once.
If i run it again its not complaining but its running like without that code
Title: Re: Clicking on a Sprite to highlight it
Post by: Laurent on July 19, 2016, 07:55:20 pm
You cannot guess C++, you must learn it ;) The way you're trying to use arrays is totally wrong.
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 19, 2016, 08:18:42 pm
Thanks for the help!
Title: Re: Clicking on a Sprite to highlight it
Post by: epilepticPi on July 19, 2016, 08:57:57 pm
Ive reworked my code and its working now. Thanks to everyone who helped me! Props to Laurent for the hint. ;)