Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Dot going out of the canvas.  (Read 3325 times)

0 Members and 1 Guest are viewing this topic.

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Dot going out of the canvas.
« on: June 02, 2018, 10:31:41 pm »
I am making a little drawing program, which for now can only place dots. My problem is when i click on the edge of the canvas it draws it outside of it. Also the when i resize the window everything goes out of proportion.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

using namespace std;

sf::CircleShape drawDot(sf::Vector2f position, unsigned int dotSize, unsigned int r, unsigned int g, unsigned int b)
{
    sf::CircleShape dot;

    dot.setRadius(dotSize);
    dot.setFillColor(sf::Color(r, g, b));
    dot.setPosition(position);

    return dot;
}

int main()
{
    sf::VideoMode screenSize = sf::VideoMode::getDesktopMode();
    sf::RenderWindow window(screenSize, "Little Painter");

    window.setFramerateLimit(60);

    sf::Event event;
    sf::Vector2f dotPosition;
    sf::Mouse mouse;
    sf::RectangleShape menuGUI(sf::Vector2f(200, 30)), canvas(sf::Vector2f(1020, 800));
    sf::Text guiText;
    sf::Font font;

    font.loadFromFile("expressway rg.ttf");

    guiText.setString("Dot Color");
    guiText.setCharacterSize(24);
    guiText.setFillColor(sf::Color::White);
    guiText.setFont(font);
    guiText.setPosition(44, 1.1f);



    canvas.setPosition(120 ,112);

    vector<sf::CircleShape> circles;

    int defaultSize = 15, r = 0, g = 100, b = 0;;

    while(window.isOpen() == true)
    {

        while(window.pollEvent(event))
        {

            menuGUI.setFillColor(sf::Color(33, 33, 33));

            sf::Vector2i mousePos = sf::Mouse::getPosition(window);
            sf::Vector2f mouseInBox = window.mapPixelToCoords(mousePos);

            sf::FloatRect menuGUIBounds = menuGUI.getGlobalBounds();
            sf::FloatRect canvasBounds = canvas.getGlobalBounds();

            if(event.type == sf::Event::Closed)
            {
                window.close();
            }

            if(event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Right)
            {
                if(canvasBounds.contains(mouseInBox))
                {
                    dotPosition = static_cast<sf::Vector2f>(mouse.getPosition(window));

                    circles.push_back(drawDot(dotPosition, defaultSize, r, g, b));
                }

            }

            if(menuGUIBounds.contains(mouseInBox))
            {
                menuGUI.setFillColor(sf::Color::Blue);

                if(event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Left)
                {
                    r = rand() % 255;
                    g = rand() % 255;
                    b = rand() % 255;
                }
            }


            if(event.type == sf::Event::MouseWheelMoved)
            {
                defaultSize += event.mouseWheel.delta;
                cout<<event.mouseWheel.delta<<endl;
            }

            window.clear(sf::Color(61,61,61));

            window.draw(menuGUI);
            window.draw(guiText);
            window.draw(canvas);
            for(vector<sf::CircleShape>::iterator it = circles.begin(); it != circles.end(); ++it)
            {
                window.draw(*it);
            }
 
            window.display();
        }

    }
}
 
« Last Edit: June 02, 2018, 10:56:35 pm by Xrey274 »

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Dot going out of the canvas.
« Reply #1 on: June 03, 2018, 04:27:03 am »
There are several mistakes and oversights in your code like using input polling, doing everything in the pollEvent loop, accessing wrong field of Event union in some checks, using static_cast instead of constructor to turn Vector2i into Vector2f.

It's also bad style to use 'using namespace std;' or compare a bool to true and you don't need to include Window.hpp and System.hpp because Graphics.hpp includes them both. You also probably use a C++11 and over capable compiler so you should use ranged fors (look it up) instead of using iterators directly, or at least use the auto keyword.

You need to change view when window resizes (Resized event) to avoid stretching.

As for the edge problem, I'm not sure what you'd expect to happen, your code is very straightforward to me and produces the expected result. What else do you think should happen?
Back to C++ gamedev with SFML in May 2023

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dot going out of the canvas.
« Reply #2 on: June 03, 2018, 01:41:18 pm »
Whats wrong with input pulling? What wrong Field am I  calling? What constructor? A constructor from one of my non existant classes or one from sfml?

I know that using namespace std; is a bad practice, but for the time being it's not interfiering with anything so it's fine. Also I know about ranged loops just totaly forgot about them.

About the edging I know that it's doing what it's supposed to do, but I am asking how can I change that.

Also one last question is it possible to give a CircleShape pointer to the draw function in RenderWindow?

This code gives me an error: No matching function for call to "sf::RenderWindow::draw(sf::CircleShape*&)
vector<sf::CircleShape*> circles;

for(vector<sf::CircleShape*>::iterator it = circles.begin(); it != circles.end(); ++it)
            {
                window.draw(*it);
            }
 


Chet

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Dot going out of the canvas.
« Reply #3 on: June 03, 2018, 05:00:27 pm »
This is because your bounds checking is incomplete. You are checking if the mouse coordinates are within the bounds of the canvas then drawing them - that's good. The bad part is that when you draw the do you do so from the upper left hand corner of the circle. When you do this on the right or bottom edge the dot will be drawn over the edge.

To fix this just take into account the size of the dot when you determine if the it can be placed on the canvas. If your dot is 10 pixels you shouldn't place the dot unless it's within getGlobalBounds() - dotSize.

Now as to your other problems...

What wrong Field am I  calling?

In the following code the event is a mouse button press but you are also checking they key code from a keypress event. Since sf::Event is a union accessing anything other than the last member set (written to) results in undefined behavior.
           if(event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Right)

You need to handle the key press event separately and maintain a flag that tracks if a certain key is pressed or not pressed so you can check it during other events.

You should actually be checking the event.mouseButton.button member instead of event.key.code. (read the documentation).

I know that using namespace std; is a bad practice, but for the time being it's not interfiering with anything so it's fine.

If you know that it's wrong why do you do it? I'l never understand why people take this poor approach to software development.

Also one last question is it possible to give a CircleShape pointer to the draw function in RenderWindow?

The draw function takes a reference not a pointer. Call it like so
                window.draw(**it);

« Last Edit: June 03, 2018, 05:04:06 pm by Chet »

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dot going out of the canvas.
« Reply #4 on: June 03, 2018, 05:43:00 pm »
So inside the if(event.type == sf::MouseButtonPressed) i need a second if that checks if its a left or right click?

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dot going out of the canvas.
« Reply #5 on: June 03, 2018, 05:58:07 pm »
Also btw turning the vector of circleShapes into a vector of circleShape pointers causes the program to crash when using the push_back method.

Chet

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Dot going out of the canvas.
« Reply #6 on: June 03, 2018, 06:10:55 pm »
So inside the if(event.type == sf::MouseButtonPressed) i need a second if that checks if its a left or right click?

This code...
if(event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Right)

should be...

if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Right)

Chet

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Dot going out of the canvas.
« Reply #7 on: June 03, 2018, 06:13:22 pm »
Also btw turning the vector of circleShapes into a vector of circleShape pointers causes the program to crash when using the push_back method.

Sounds like more undefined behavior. Chances are the original vector is being destroyed causing the CircleShape objects to be destroyed which invalidates the pointers in your new vector.


I suggest you learn how to properly use a debugger to help identify the source of these problems.
« Last Edit: June 03, 2018, 06:19:31 pm by Chet »

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dot going out of the canvas.
« Reply #8 on: June 03, 2018, 09:49:28 pm »
Any idea how to fix the problem?

Chet

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Dot going out of the canvas.
« Reply #9 on: June 03, 2018, 10:41:26 pm »
Any idea how to fix the problem?

Yes. Use a debugger.

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dot going out of the canvas.
« Reply #10 on: June 04, 2018, 06:40:55 pm »
Any good sources to learn debugging with Code::Blocks

Chet

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Dot going out of the canvas.
« Reply #11 on: June 04, 2018, 08:59:25 pm »
Any good sources to learn debugging with Code::Blocks

Seems Google is broken for just you so here's some debugging links to help you until Google starts working again.

http://wiki.codeblocks.org/index.php/Debugging_with_Code::Blocks


https://rubberduckdebugging.com/
https://ericlippert.com/2014/03/05/how-to-debug-small-programs/

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Dot going out of the canvas.
« Reply #12 on: June 04, 2018, 09:19:52 pm »
Just a quick question: Am I doing the sf::View thing wrong or is there something wrong with getMousePosition, because when I down size the window dots are being place very far away from the mouse cursor?

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

sf::CircleShape* drawDot(sf::Vector2f position, unsigned int dotSize, unsigned int r, unsigned int g, unsigned int b)
{
    sf::CircleShape* dot;
    dot = new sf::CircleShape;

    dot->setRadius(dotSize);
    dot->setFillColor(sf::Color(r, g, b));
    dot->setPosition(position);

    return dot;
}

int main()
{
    sf::VideoMode screenSize = sf::VideoMode::getDesktopMode();
    sf::RenderWindow window(sf::VideoMode(screenSize.width / 2, screenSize.height / 2), "Little Painter");
    sf::View defaultView(sf::FloatRect(0.f, 0.f, 1280, 1024));

    window.setView(defaultView);

    window.setFramerateLimit(60);

    sf::Event event;

    sf::Vector2f dotPosition;

    sf::Mouse mouse;
    sf::RectangleShape dotColorGUI(sf::Vector2f(200, 30)), canvas(sf::Vector2f(1020, 800)), clearCanvasGUI(sf::Vector2f(200, 30));

    clearCanvasGUI.setPosition(202, 0);

    sf::Text dotColorText, clearCanvasText;
    sf::Font font;

    sf::Time sleepTime = sf::milliseconds(10);

    font.loadFromFile("expressway rg.ttf");

    dotColorText.setString("Dot Color");
    dotColorText.setCharacterSize(24);
    dotColorText.setFillColor(sf::Color::White);
    dotColorText.setFont(font);
    dotColorText.setPosition(44, 1);

    clearCanvasText.setString("Clear Canvas");
    clearCanvasText.setCharacterSize(24);
    clearCanvasText.setFillColor(sf::Color::White);
    clearCanvasText.setFont(font);
    clearCanvasText.setPosition(230, 1);

    canvas.setPosition(120 ,112);

    std::vector<sf::CircleShape*> circles;

    int defaultSize = 15, r = 0, g = 100, b = 0;;

    while(window.isOpen() == true)
    {

        while(window.pollEvent(event))
        {
            dotColorGUI.setFillColor(sf::Color(33, 33, 33));
            clearCanvasGUI.setFillColor(sf::Color(33, 33, 33));

            sf::Vector2i mousePos = sf::Mouse::getPosition(window);
            sf::Vector2f mouseInBox = window.mapPixelToCoords(mousePos);

            sf::FloatRect dotColorGUIBounds = dotColorGUI.getGlobalBounds();
            sf::FloatRect clearCanvasGUIBounds = clearCanvasGUI.getGlobalBounds();
            sf::FloatRect canvasBounds = canvas.getGlobalBounds();

            if(event.type == sf::Event::Closed)
            {
                window.close();
            }

            if(event.type == sf::Event::Resized)
            {
                window.setView(defaultView);
            }

            if(event.type == sf::Event::MouseButtonPressed)
            {
                if(event.mouseButton.button == sf::Mouse::Right)
                {
                   if(canvasBounds.contains(mouseInBox))
                    {
                        dotPosition = static_cast<sf::Vector2f>(mouse.getPosition(window));

                        circles.push_back(drawDot(dotPosition, defaultSize, r, g, b));
                    }
                }
            }

            if(dotColorGUIBounds.contains(mouseInBox))
            {
                dotColorGUI.setFillColor(sf::Color(40, 50, 95));

                if(event.type == sf::Event::MouseButtonPressed)
                {
                    if(event.mouseButton.button == sf::Mouse::Left)
                    {
                        r = rand() % 255;
                        g = rand() % 255;
                        b = rand() % 255;
                    }
                }
            }

            if(clearCanvasGUIBounds.contains(mouseInBox))
            {
                clearCanvasGUI.setFillColor(sf::Color(40, 50, 95));

                if(event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Left)
                {
                    for(const auto it : circles)
                    {
                        delete it;
                    }
                }
            }

            if(event.type == sf::Event::MouseWheelMoved)
            {
                defaultSize += event.mouseWheel.delta;
            }

            window.clear(sf::Color(61,61,61));

            window.draw(dotColorGUI);
            window.draw(dotColorText);

            window.draw(clearCanvasGUI);
            window.draw(clearCanvasText);

            window.draw(canvas);
            for(const auto it : circles)
            {
                window.draw(*it);
            }

            window.display();
        }
    }

}

 

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Dot going out of the canvas.
« Reply #13 on: June 12, 2018, 01:31:28 am »
I know this is about a week old now but I think I know what your problem might be.
First, remember that the view that you are setting to 1280x1024 specifies the co-ordinate system within the window, whatever size that window might be.
You don't actually change the view, it seems.
Note that resizing a window does not change its view; that means there is no reason to set the view to the same one again when the window was resized.

Also, I don't understand why you created an instance of sf::Mouse

Anyway, you do get the mouse position of the window perfectly fine and you do then map the pixel location to co-ordinates perfectly well. However, you then pass the pixel location to the draw the dot, which, for some reason, you 'get' again.

Actually, since you're using events, the mouse's pixel location is already contained in the MouseButtonPressed event! You just need to map it as vector:
const sf::Vector2f mousePosition = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y));
(instead of "dotPosition = static_cast<sf::Vector2f>(mouse.getPosition(window));")
This is the position you want to pass instead of "dotPosition".


If you do change the view, make sure that you are mapping using the correct view. As it is, though, your view is static so this is fine.



IMPORTANT: do not forget that the update of the window should be done regardless of if there are events so the clear/draw/display section should not be in the event loop.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything