SFML community forums

Help => General => Topic started by: metulburr on November 27, 2013, 02:15:18 pm

Title: different results on several compiles with same code
Post by: metulburr on November 27, 2013, 02:15:18 pm
My obvious goal is to get a button class in which changes color on mouse hovering over the button. I have 2 problems. 1) if i recompile time after time again, sometimes it prints correctly when the mouse is inside the rectangel, sometimes it prints when the mouse is bleow the rectangle. It is different each time compiling. 2) At the time it does display correctly when the mouse is inside the rectangle, i expected it to change color bassed on is_hovering bool value. However the color never changes, yet the display messages do?

I tried minimizing it, but i am not sure how to minimize it more without losing a working example.

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>


class Button{
    public:
        sf::Vector2f position;
        sf::RectangleShape rect;
        bool is_hovering;
        int width, height;
       
        Button(){
            rect.setFillColor(sf::Color(200,200,200));
        }
           
        void create(float w, float h, float x, float y){
            width = w;
            height = h;
            position = {x,y};
            rect.setSize(sf::Vector2f(w,h));
            rect.setPosition(position);
        }
       

       
        void update(sf::Vector2i mouse){
            if (mouse.x > position.x &&
            mouse.x < (position.x + width) &&
            mouse.y > position.y &&
            mouse.y < position.y + height){
                std::cout << "inside rect" << std::endl;
                is_hovering = true;
            }
            else
                std::cout << std::endl;
                is_hovering = false;
           
            if (is_hovering)
                rect.setFillColor(sf::Color(50,50,50));
            else
                rect.setFillColor(sf::Color(200,200,200));
        }
};

class Control{
    public:
        sf::RenderWindow window;
        sf::Clock clock;
        sf::Time frame_time = sf::seconds(1.f/60.f);
        sf::Time time = sf::Time::Zero, update_time = sf::Time::Zero;
        sf::Vector2i mouse;
        Button button;
       
        Control(){
            window.create(sf::VideoMode(600,400), "Title");
            button.create(100,20, 100,100);
            //window.setKeyRepeatEnabled(false);
        }
       
        void update(){
            mouse = sf::Mouse::getPosition(window);
           
            time = clock.restart();
            update_time += time;

            while(update_time > frame_time){
                update_time -= frame_time;
                button.update(mouse);
            }
            render();
        }
       
        void render(){
            window.clear(sf::Color::Black);
            window.draw(button.rect);
            window.display();
        }
       
        void event_handler(sf::Event event){
            while(window.pollEvent(event)){
                if (event.type == sf::Event::Closed)
                    window.close();
            }
        }
       
        void run(){
            while (window.isOpen()){
                sf::Event event;
                event_handler(event);
                update();
            }
        }
};

int main(){
    Control app;
    app.run();
}
 
Title: Re: different results on several compiles
Post by: FRex on November 27, 2013, 02:33:32 pm
Quote
1) if i recompile time after time again, sometimes it prints correctly when the mouse is inside the rectangel, sometimes it prints when the mouse is bleow the rectangle. It is different each time compiling.
Can't reproduce.

Quote
2) At the time it does display correctly when the mouse is inside the rectangle, i expected it to change color bassed on is_hovering bool value. However the color never changes, yet the display messages do?
Without // !! lines you always set is_hovering to false and use the non hover color all the time:
if (mouse.x > position.x &&
mouse.x < (position.x + width) &&
mouse.y > position.y &&
mouse.y < position.y + height){
    std::cout << "inside rect" << std::endl;
    is_hovering = true;
}
else
{// !!
    std::cout << std::endl;
    is_hovering = false;
}// !!
 
Title: Re: different results on several compiles
Post by: wintertime on November 27, 2013, 02:56:51 pm
I suspect its because you sometimes maximize the window before testing. You have to either catch the resize event and adapt the window accordingly or you need to always use mapPixelToCoords on the coordinates you got for the mouse.
I would also think it is better you only update the coordinates when you get a mouse event from the included data and not always read mouse status.
Title: Re: different results on several compiles
Post by: metulburr on November 27, 2013, 03:07:19 pm
Quote
Can't reproduce.
I posted this to represent my problem.
Note i did this before i read your second part regarding the missing brackets
http://www.youtube.com/watch?v=Yy1fRtQCXlo&feature=youtu.be
Also the execute button is not just re-running, but also recompiling via:
g++ -std=c++11 -Wall -o "%e" "%f" -lsfml-audio -lsfml-graphics -lsfml-window -lsfml-system &&"./%e"


and 2), ah thanks, I guess i should just always put the brackets when i put one line of code being the fact that i add a line and forget to add the brackets. thanks.

EDIT:
deleted original youtube video and thus replaced previous link with latest link
Title: Re: different results on several compiles
Post by: metulburr on November 27, 2013, 03:24:02 pm
Quote
I suspect its because you sometimes maximize the window before testing. You have to either catch the resize event and adapt the window accordingly or you need to always use mapPixelToCoords on the coordinates you got for the mouse.
I do not change the window size at all. Is this still accurate if i do not?

Quote
I would also think it is better you only update the coordinates when you get a mouse event from the included data and not always read mouse status.
To be 100% honest, i am not exactly sure what you mean by this?
Title: Re: different results on several compiles
Post by: wintertime on November 27, 2013, 03:39:49 pm
As long as there is a resize button on the window you want to be compatible to it. Some people click it even without thinking about it.

You call pollEvent, but you throw away all the information you get instead of using it. You should read the tutorial about all event types. Then you dont need to call Mouse::getPosition anymore. Thats because the mouse does not always move on every frame.
Even worse you have a useless busy loop that calls Button::update a million times with the same data that prevents your program from getting fresh events.
Title: Re: different results on several compiles with same code
Post by: metulburr on November 27, 2013, 03:51:42 pm
Quote
As long as there is a resize button on the window you want to be compatible to it. Some people click it even without thinking about it.
I tried it without touching the window at all to ensure not touching the window resize. However, it still has the same results. I also added sf::Style::Titlebar | sf::Style::Close to window.create() to disable winodw resizing, however i still get the same results.

Quote
You call pollEvent, but you throw away all the information you get instead of using it. You should read the tutorial about all event types. Then you dont need to call Mouse::getPosition anymore. Thats because the mouse does not always move on every frame.
I have read the tutorials. I actually have spent the past few days re-reading and re-reading the tutorials. I have at least read events tutorial page 4 times yesterday. If you are referring to specific method, i would advise you to note that method. No where in this quote do you suggest what specifc event you are referring to. If you are referring to sf::Event::MouseMoved, however i dont know, because you do not say... why use that over this method? Plus i do not see where that would cause such strange behavior with the button class?

Quote
Even worse you have a useless busy loop that calls Button::update a million times with the same data that prevents your program from getting fresh events.
ah ok. Thanks. That makes sense. I had that there after reading the SMFL book. Although now i am not sure why the SFML book states to even have that loop in the first place.
        void update(){
            mouse = sf::Mouse::getPosition(window);
            button.update(mouse);
           
            time = clock.restart();
            update_time += time;

            while(update_time > frame_time){
                update_time -= frame_time;

            }
            render();
        }
Title: Re: different results on several compiles with same code
Post by: wintertime on November 27, 2013, 04:16:57 pm
I was speaking of this tutorial: http://sfml-dev.org/tutorials/2.1/window-events.php
There is some updated code:
        void update() {
        }

        void event_handler() {
            sf::Event event;
            while(window.pollEvent(event)) {
                if (event.type == sf::Event::Closed)
                    window.close();
                else if(event.type == sf::Event::MouseMoved)
                    button.update(window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x,event.mouseMove.y)));
            }
        }
     
        void run(){
            while (window.isOpen()){
                event_handler();
                update();
                render();
            }
        }

 
Title: Re: different results on several compiles with same code
Post by: metulburr on November 27, 2013, 04:33:21 pm
Here is the entire code with that implemented. Your method looks a lot more complex for something i do not understand the benfits of, as it does the same thing as sf::Mouse::getPosition(window) and sending it to Button::update.
Regardless...(if this code is correct in what you meant) the original problem of the OP #1 still exists in the matter of the button gets hovered color sometimes when the mouse is off below the button and somtimes compiled when the mouse is on hte button. identical to the video clip.

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>


class Button{
    public:
        sf::Vector2f position;
        sf::RectangleShape rect;
        bool is_hovering;
        int width, height;
       
        Button(){
            rect.setFillColor(sf::Color(200,200,200));
        }
           
        void create(float w, float h, float x, float y){
            width = w;
            height = h;
            position = {x,y};
            rect.setSize(sf::Vector2f(w,h));
            rect.setPosition(position);
        }
       

       
        void update(sf::Vector2f mouse){
            if (mouse.x > position.x &&
            mouse.x < (position.x + width) &&
            mouse.y > position.y &&
            mouse.y < position.y + height){
                is_hovering = true;
            }
            else{
                is_hovering = false;
            }
           
            if (is_hovering)
                rect.setFillColor(sf::Color(50,50,50));
            else
                rect.setFillColor(sf::Color(200,200,200));
        }
};

class Control{
    public:
        sf::RenderWindow window;
        sf::Clock clock;
        sf::Time frame_time = sf::seconds(1.f/60.f);
        sf::Time time = sf::Time::Zero, update_time = sf::Time::Zero;
        sf::Vector2i mouse;
        Button button;
       
        Control(){
            window.create(sf::VideoMode(600,400), "Title", sf::Style::Titlebar | sf::Style::Close);
            button.create(100,20, 100,100);
            //window.setKeyRepeatEnabled(false);
        }
       
        void time_update(){
            time = clock.restart();
            update_time += time;

            while(update_time > frame_time){
                update_time -= frame_time;

            }
        }
       
        void update(){
            time_update();
            mouse = sf::Mouse::getPosition(window);
            //button.update(mouse);
           

            render();
        }
       
        void render(){
            window.clear(sf::Color::Black);
            window.draw(button.rect);
            window.display();
        }
       
        void event_handler(){
            sf::Event event;
            while(window.pollEvent(event)){
                if (event.type == sf::Event::Closed)
                    window.close();
                else if(event.type == sf::Event::MouseMoved)
                    button.update(window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x,event.mouseMove.y)));
            }
        }
       
        void run(){
            while (window.isOpen()){
                event_handler();
                update();
            }
        }
};

int main(){
    Control app;
    app.run();
}
 
Title: Re: different results on several compiles with same code
Post by: metulburr on November 27, 2013, 04:56:13 pm
well this is quite interesting...
If i compile the previous post's code in Ubuntu 12.04.3, i do not have any problems that i can see. The button always gets highlighted. I tried it about 20 times. Same thing every time. However in Arch Linux, with the same code compiled, most of the time the button gets highlighted, but roughly 1/4 the time i get the problem of the mouse having to be below the button for it to get highlighted. I tried this about 20 times with having this problem about 4 of those times. Such like: http://www.youtube.com/watch?v=Yy1fRtQCXlo&feature=youtu.be
Note the last 2 compiling/runs.

Now my question is what is different about arch and ubuntu. Both of my distros have the required libs for SFML, obviously otherwise they would not compile at all. I normally blame my code first, but i think this time the only thing i can think of is a bug in SFML. Can another Arch Linux user compile this code and have it work 100% of the time?

Both my Arch and Ubuntu are using SFML 2.1 64 bit
Title: Re: different results on several compiles with same code
Post by: Laurent on November 27, 2013, 11:11:03 pm
Could you please make this example more minimal (and thus more readable)? There are a lot of unused stuff (update_time, mouse, ...) and it's hard to follow the logic with everything split up in small parts. A single main() with everything directly written would be great, instead of those useless levels of abstraction.
Title: Re: different results on several compiles with same code
Post by: metulburr on November 27, 2013, 11:43:18 pm
Quote
Could you please make this example more minimal

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>





int main(){
    sf::RenderWindow window(sf::VideoMode(600,400), "Title", sf::Style::Titlebar | sf::Style::Close);
   
    sf::Vector2f position;
    sf::RectangleShape rect;
    int width, height;
   
    rect.setFillColor(sf::Color(200,200,200));
    width = 100;
    height = 20;
    position = {100,100};
    rect.setSize(sf::Vector2f(width, height));
    rect.setPosition(position);
   
    sf::Vector2i mouse;

    while (window.isOpen()){
        mouse = sf::Mouse::getPosition(window);
        sf::Event event;
        while(window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
            else if(event.type == sf::Event::MouseMoved){
                if (mouse.x > position.x &&
                mouse.x < (position.x + width) &&
                mouse.y > position.y &&
                mouse.y < position.y + height){
                    rect.setFillColor(sf::Color(50,50,50));
                }
                else{
                    rect.setFillColor(sf::Color(200,200,200));
                }
            }
        }
        window.clear(sf::Color::Black);
        window.draw(rect);
        window.display();
    }
}
I tried this is Ubuntu 12.04.3 and Windows 8 and they both seem to work 100% of the time. It appears to only happen in Arch.
Title: Re: different results on several compiles with same code
Post by: binary1248 on November 28, 2013, 02:18:39 am
I don't know if anyone else noticed, but the problem doesn't lie in the mouse collision detection or event handling at all. If you look very carefully at the video(s), you will notice the position of the sf::RectangleShape changes between executions. Maybe this is a sign that I've been working on GUIs for too long 8).

You can throw out the collision detection code and all the event handling, and it might probably still occur that the sf::RectangleShape doesn't stay in the same position although the hardcoded position doesn't change, and that is the real problem, not the fact that the collision is not properly detected. The collision detection uses data that is saved in the user code, not the data representation inside SFML. If you were to query the sf::RectangleShape for its position in one of those broken executions, it would probably return some bogus values.

The only critical places I would look at are:
sf::Vector2f position;
...
position = {100,100};
...
rect.setPosition(position);
When initially constructing the sf::Vector2f, its constructor sets both x and y values to 0, regardless of data type, no narrowing conversion should ever be required.
The second one is a bit trickier. Normally you would be able to initialize data structures using aggregate initialization with the { 1, 2, 3 }; syntax, but only if the object doesn't have any user defined constructors, which sf::Vector<T> has. So in C++03 that syntax would be illegal. It only works because -std=c++11 is used. In C++11 it isn't about aggregate initialization any more. That expression evaluates to a construction of a new sf::Vector2f to assign to position due to uniform initialization. In this case as well, a non-narrowing conversion has to be performed.
The last spot is when the position is finally passed on to SFML. Since SFML takes the parameter by reference, I don't see much opportunity for anything to go wrong there.

Obviously, something is going wrong somewhere. The executable produced by the compiler/linker should stay the same unless your disk was dying in the process of your testing. The only spot I could think of where something might go wrong is during the conversion from int to float. Normally it should not be a problem since it is not a narrowing conversion, but considering something has to be a problem, that would be the most likely candidate, short of random memory corruption due to broken RAM, a broken disk, a broken processor, or (since it only happens on Arch) a broken runtime environment and/or kernel.

I would try to minimize the opportunities for the culprit to mess with your data and try to avoid unnecessary conversions, as is the case in all your code examples. Also, try to print out the data before it gets passed over to SFML, even though it should be what you would expect, better safe than sorry. Over time developers learn to trust their compiler and runtime environments, but a little scepticism can go a long way sometimes, especially when something has to obviously be broken.
Title: Re: different results on several compiles with same code
Post by: metulburr on November 30, 2013, 03:29:10 pm
it took me awhile to test it to ensure it was still happening as i did get a kernel update and had to re-compile it. Although it still happens with the newer kernel.

All in all, now it happens 1/20 of the time in arch for some reason, regardless of being float or int. Which makes it worse. As it is even harder to test.

Quote
The only spot I could think of where something might go wrong is during the conversion from int to float. Normally it should not be a problem since it is not a narrowing conversion, but considering something has to be a problem, that would be the most likely candidate,
changing everything to float to ensure there is no conversion, i also still get the same problem.



It is driving me nuts as i am not sure i can safely move around in distros and expect the same results with SFML.

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>

int main(){
    sf::RenderWindow window(sf::VideoMode(600,400), "Title", sf::Style::Titlebar | sf::Style::Close);
   
    sf::Vector2f position;
    sf::RectangleShape rect;
    float width, height;
   
    rect.setFillColor(sf::Color(200,200,200));
    width = 100.0;
    height = 20.0;
    position = {100.0,100.0};
    rect.setSize(sf::Vector2f(width, height));
    rect.setPosition(position);
   
    sf::Vector2i mouse;

    while (window.isOpen()){
        mouse = sf::Mouse::getPosition(window);
        sf::Event event;
        while(window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
            else if(event.type == sf::Event::MouseMoved){
                if (mouse.x > position.x &&
                mouse.x < (position.x + width) &&
                mouse.y > position.y &&
                mouse.y < position.y + height){
                    rect.setFillColor(sf::Color(50,50,50));
                }
                else{
                    rect.setFillColor(sf::Color(200,200,200));
                }
            }
        }
        window.clear(sf::Color::Black);
        window.draw(rect);
        window.display();
    }
}
Title: Re: different results on several compiles with same code
Post by: binary1248 on November 30, 2013, 04:31:48 pm
Did you already try using a debugger and watching the values as they get passed around?
Title: Re: different results on several compiles with same code
Post by: wintertime on November 30, 2013, 10:03:59 pm
You still dont use the mouse position from the event. The stale, old position data from the superfluous getPosition call outside the event loop is wrong. If on arch linux the frequency of mouse events is lower or the OS settings allow moving the mouse pointer faster, you will get a higher error from this.

Btw., I would still suggest using mapPixelToCoords.
Title: Re: different results on several compiles with same code
Post by: metulburr on December 01, 2013, 01:20:21 pm
@binary1248
In the past 3 years of programming , i have never used a debugger.  I have always used print statements to determine a value. I attempted to figure out how to use the debugger in Geany IDE, but i couldnt figure the process out.

@windertime
are you referring to:
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>

int main(){
    sf::RenderWindow window(sf::VideoMode(600,400), "Title", sf::Style::Titlebar | sf::Style::Close);
   
    sf::Vector2f position;
    sf::RectangleShape rect;
    float width, height;
   
    rect.setFillColor(sf::Color(200,200,200));
    width = 100.0;
    height = 20.0;
    position = {100.0,100.0};
    rect.setSize(sf::Vector2f(width, height));
    rect.setPosition(position);
   
    sf::Vector2i mouse;

    while (window.isOpen()){
        sf::Event event;
        while(window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
            else if(event.type == sf::Event::MouseMoved){
                int mousex = event.mouseMove.x;
                int mousey = event.mouseMove.y;
               
                if (mousex > position.x &&
                mousex < (position.x + width) &&
                mousey > position.y &&
                mousey < position.y + height){
                    rect.setFillColor(sf::Color(50,50,50));
                }
                else{
                    rect.setFillColor(sf::Color(200,200,200));
                }
            }
        }
        window.clear(sf::Color::Black);
        window.draw(rect);
        window.display();
    }
}
because i still get the same problem.

And regarding mapPixelToCoors. What does this even do? Yes i read the docs. but "Convert a point from target coordinates to world coordinates. " doesn't make sense to me. Trying to read the SFML documentation in the eyes of a newbie is like trying to learn Greek. 

Quote
This function finds the pixel of the render-target that matches the given 2D point. In other words, it goes through the same process as the graphics card, to compute the final position of a rendered point.

Initially, both coordinate systems (world units and target pixels) match perfectly. But if you define a custom view or resize your render-target, this assertion is not true anymore, ie. a point located at (150, 75) in your 2D world may map to the pixel (10, 50) of your render-target – if the view is translated by (140, 25).

This version uses a custom view for calculations, see the other overload of the function if you want to use the current view of the render-target.
I dont know if this is just me or not, but i read this over like 10 times and still i am like WTF?

EDIT:
ok i think you mean this?
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>

int main(){
    sf::RenderWindow window(sf::VideoMode(600,400), "Title", sf::Style::Titlebar | sf::Style::Close);
   
    sf::Vector2f mouse;
    sf::Vector2f position;
    sf::RectangleShape rect;
    float width, height;
   
    rect.setFillColor(sf::Color(200,200,200));
    width = 100.0;
    height = 20.0;
    position = {100.0,100.0};
    rect.setSize(sf::Vector2f(width, height));
    rect.setPosition(position);
   

    while (window.isOpen()){
        sf::Event event;
        while(window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
            else if(event.type == sf::Event::MouseMoved){
                mouse = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x,event.mouseMove.y));
            }
               
            if (mouse.x > position.x &&
            mouse.x < (position.x + width) &&
            mouse.y > position.y &&
            mouse.y < position.y + height){
                rect.setFillColor(sf::Color(50,50,50));
            }
            else{
                rect.setFillColor(sf::Color(200,200,200));
            }
           
        }
        window.clear(sf::Color::Black);
        window.draw(rect);
        window.display();
    }
}
if so even after using mappixeltocoords, i stll have the same problem.
Title: Re: different results on several compiles with same code
Post by: binary1248 on December 01, 2013, 03:31:10 pm
@binary1248
In the past 3 years of programming , i have never used a debugger.  I have always used print statements to determine a value. I attempted to figure out how to use the debugger in Geany IDE, but i couldnt figure the process out.
Well then... it's about time you started to use one ;). These things can be solved so easily if you use one. Never used Geany's debugger, but Code::Blocks has nice gdb integration, so you can try that if Geany doesn't work for you.