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

Author Topic: Overriding sf::RectangleShape::draw  (Read 5602 times)

0 Members and 2 Guests are viewing this topic.

yannik

  • Newbie
  • *
  • Posts: 5
    • View Profile
Overriding sf::RectangleShape::draw
« on: April 16, 2017, 12:52:43 pm »
Hello,
I derive a class Square from RectangleShape. The Square also contains a text I want to draw. But when I override draw to draw the text, how do I also draw the rectangle? Do I have to create yet another class or is there something I'm missing? Here's the code

#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderWindow.hpp>

#include <string>

class Square : public sf::RectangleShape
{
private:
    sf::Text            mText;

public:
                                Square(const sf::Font& font, sf::Vector2f position, const std::string& s = "");

    void                        update();

private:
    void                        draw(sf::RenderTarget& target, sf::RenderStates states) const;
};

Square::Square(const sf::Font& font, sf::Vector2f position, const std::string& s)
{
        mText.setFont(font);
        mText.setString(s);
        mText.setCharacterSize(26);
        mText.setFillColor(sf::Color::White);
        mText.setPosition(sf::Vector2f(position.x + 16, position.y + 8));

        setPosition(position);
        setSize(sf::Vector2f(48, 48));
        setFillColor(sf::Color::Transparent);
        setOutlineColor(sf::Color::White);
        setOutlineThickness(1.3f);
}

void Square::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        target.draw(mText);
}

void Square::update()
{
        RectangleShape::update();
}

int main()
{
        sf::RenderWindow window(sf::VideoMode(640, 480), "");
        sf::Font font;
        font.loadFromFile("arial.ttf");
        Square square(font, sf::Vector2f(10, 10), "A");
        while(window.isOpen())
        {
                window.clear();
                square.update();
                window.draw(square);
                window.display();
        }
}
 

Thanks in advance.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Overriding sf::RectangleShape::draw
« Reply #1 on: April 16, 2017, 01:29:01 pm »
Your Square is not a sf::RectangleShape anymore and thus should not derive from it. Instead you can derive from sf::Drawable (and sf::Transformable if needed) and have the rectangle shape as member variable that you can then draw.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

yannik

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Overriding sf::RectangleShape::draw
« Reply #2 on: April 16, 2017, 01:46:21 pm »
Hm, okay. I just thought a square is a rectangle and doesn't just own one, and should therefore be derived from it.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Overriding sf::RectangleShape::draw
« Reply #3 on: April 16, 2017, 02:38:16 pm »
It's the main example used to show that it violates the Liskov substitution principle. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

yannik

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Overriding sf::RectangleShape::draw
« Reply #4 on: April 16, 2017, 03:09:31 pm »
Ah okay, didn't know that. Thank you :)

yannik

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Overriding sf::RectangleShape::draw
« Reply #5 on: April 16, 2017, 07:45:49 pm »
But then I have another question: If I now want to change the outline thickness or color of the Square, do I have to call RectangleShape::update afterwards? If so, how can I call a protected function from this context? I tried changing the color, but the Square doesn't change, and I can't call update because it's protected (which is actually why I derived from it in the first place  :D)

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Overriding sf::RectangleShape::draw
« Reply #6 on: April 16, 2017, 10:50:08 pm »
The rectangle shape is now a member of your own class, so if you want to change the color or outline thickness, you simply call the public API functions of the member variable.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Overriding sf::RectangleShape::draw
« Reply #7 on: April 17, 2017, 01:31:44 am »
There is a compromise here: try inheriting from sf::Shape (as sf::RectangleShape etc. do) instead of sf::Drawable and sf::Transformable directly, although you will need to write the code to determine its points etc. but you could probably look at rectangle shape's code to help.
Example of inheriting from sf::Shape to create an ellipse class is in the Shapes tutorial:
https://www.sfml-dev.org/tutorials/2.4/graphics-shape.php#custom-shape-types
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

chudek123

  • Newbie
  • *
  • Posts: 1
    • View Profile
Re: Overriding sf::RectangleShape::draw
« Reply #8 on: January 22, 2021, 01:00:02 pm »
Hello, I would like to share with my solution which allows for inheriting from sf::RectangleShape class. I met troubles with deriving from sf::Drawable and sf::Transformable, because then I couldn't use sf::Shape::setFillColor, so I tried to inherit from sf::Shape like our friend said above. Inheriting from sf::Shape was still problematic, because I had to define points like in eclipse example, I didn't want to do this in my case of drawing rectangle with grid. Finally, inheriting from sf::RectangleShape gave me a possibility for overriding draw function:
void CustomRectangleShape::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
    states.transform *= this->getTransform();
    sf::VertexArray rect_shape(sf::Quads, 4);
    sf::Color rect_color = this->getFillColor();
    rect_shape[0].position = this->getPoint(0);
    rect_shape[1].position = this->getPoint(1);
    rect_shape[2].position = this->getPoint(2);
    rect_shape[3].position = this->getPoint(3);
    rect_shape[0].color = rect_color;
    rect_shape[1].color = rect_color;
    rect_shape[2].color = rect_color;
    rect_shape[3].color = rect_color;
    target.draw(rect_shape,states);
    if(this->grid_){
        this->drawGrid(target,states);
    }
}

void CustomRectangleShape::drawGrid(sf::RenderTarget &target, sf::RenderStates states) const
{
    states.transform = grid_rec_->getTransform().Identity;
    for(int i = 0; i < grid_size_.x; i++){
        for(int j = 0; j < grid_size_.y; j++){
            grid_rec_->setPosition(this->getPosition().x + i * grid_rec_->getSize().x, this->getPosition().y + j * grid_rec_->getSize().y);
            target.draw(*grid_rec_, states);
        }
    }
}
 

I also created class fields for grid code, to be clear:
bool grid_;
sf::RectangleShape* grid_rec_;
sf::Vector2i grid_size_;
.
« Last Edit: January 27, 2021, 02:56:42 pm by chudek123 »