SFML community forums

Help => Window => Topic started by: Fanjad on September 17, 2012, 02:39:08 am

Title: Draw from multiple classes
Post by: Fanjad on September 17, 2012, 02:39:08 am
Hey guys,

I'm new to SFML and currently trying to draw to one window from multiple classes:
My plan is to create a little "Pong clone" with different classes; one for the window, one for the players and one for the ball (maybe one for collisions, don't mind yet). But I don't know how to draw from the "Player"-class or the "Ball"-Class to the window created by the "Window"-Class. A - very - little example would be extremly helpful :)

Thanks!
Title: Re: Draw from multiple classes
Post by: eXpl0it3r on September 17, 2012, 02:57:23 am
There are multiple ways to achieve such a thing and it largely depends on the structure you chose for your 'engine'. ;)

One way would be to assume that every class than can get displayed are derived from sf::Drawable. Thus the class that is responsible to 'manage' those drawables could simply hold a std::vector of std::unique_ptr to all your drawables.

Here's some quickly cooked code which defines just two drawable classes and one application class. Everything should of course get extended and properly declared & defined in header and source files, etc...
Be warned the code uses some C++11 features which aren't supported by all compilers, specially not MSVC.
#include <SFML/Graphics.hpp> // sf::Drawable, sf::RenderTarget, sf::RenderStates, sf::Sprite, sf::CircleShape, sf::RenderWindow, sf::Event

#include <vector> // std::vector
#include <memory> // std::unique_ptr

class Player : public sf::Drawable
{
private:
        void draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
                target.draw(m_sprite, states);
        }
       
private:
        sf::Sprite m_sprite;
};

class Ball : public sf::Drawable
{
private:
        void draw(sf::RenderTarget& target, RenderStates states) const
        {
                target.draw(m_circle, states);
        }

private:
        sf::CircleShape m_circle;
};

class App
{
public:
        App()
        {
                m_drawables.push_back(std::make_unique(Ball));
                m_drawables.push_back(std::make_unique(Player));
        }

        void run()
        {
                sf::Event event;
                while(m_window.pollEvent(event))
                {
                        if(event.type == sf::Event::Closed)
                                m_window.close;
                }
               
                m_window.clear();
               
                for(auto it = m_drawables.begin(); it != m_drawables.end(); it++)
                        m_window.draw(*(*it));
               
                m_window.draw();
        }
       
private:
        sf::RenderWindow m_window;
        std::vector<std::unique_ptr<sf::Drawable>> m_drawables;
};

int main()
{
        App app;
        app.run();
}

Obviously it's all untested, but it should demonstrate one possible principle.
There are many other ways and all have their ups and downs... ;)
Title: Re: Draw from multiple classes
Post by: Fanjad on September 17, 2012, 04:20:39 am
Thanks a lot :) I will test it as soon as possible :)

/E: Tested your code, but my compiler (MSVC 2010) is not very happy :(
m_drawables.push_back(std::make_unique(Ball));
m_drawables.push_back(std::make_unique(Player));

The compiler doesn't allow type names here. (He even doesn't know make_unique)
Title: Re: Draw from multiple classes
Post by: masskiller on September 17, 2012, 05:36:01 am
The only thing that comes to mind is that that code is C++ 11 and your compiler doesn't support it, get the latest version of GCC and it should work if it is what I just said.
Title: Re: Draw from multiple classes
Post by: Nexus on September 17, 2012, 09:46:02 am
The only thing that comes to mind is that that code is C++ 11 and your compiler doesn't support it, get the latest version of GCC and it should work if it is what I just said.
No. std::make_unique() just doesn't exist. Yesterday I wrote my own version (http://en.sfml-dev.org/forums/index.php?topic=7330.msg62014#new) of it...

Apart from that, VS 2010 supports some C++11 features like std::unique_ptr and move semantics.
Title: Re: Draw from multiple classes
Post by: Hiura on September 17, 2012, 11:13:40 am
The implementation of draw is not correct. If you try player.move(100, 100); and you'll be disappointed because the player won't move at all.

You have to update the states. Here is an example (https://github.com/mantognini/sftools/blob/develop/include/sftools/Animation/Animation.hpp#L116-122) that also use a sprite as renderer.
Title: Re: Draw from multiple classes
Post by: eXpl0it3r on September 17, 2012, 11:45:41 am
The implementation of draw is not correct. If you try player.move(100, 100); and you'll be disappointed because the player won't move at all.
The implementation is correct. ;)
I just didn't inherit from sf::Transformable thus not implementing move()/setPosition() etc, thus a call to getTransform() wouldn't even work within the current class.
Of course it can be a good idea to inherit from sf::Transformable, but then the questions is if one really wants to use a sf::Sprite internally since it would then be code repetition (a sprite is already a Drawable and Transformable)...
Title: Re: Draw from multiple classes
Post by: Hiura on September 17, 2012, 12:18:51 pm
Indeed, I read your code too fast.

Quote
since it would then be code repetition
I wouldn't say it's repetition, but more reusing what already exists. The difference is kind of subtle so it could lead to an interesting debate, unfortunately I don't have time right now to open a new thread about this.

The thing is I've implement SFML on mac for some time now but I never had the opportunities of creating an application that really uses SFML (school is time consuming, you know) and now that I've this opportunity all those design question become really interesting and motivating. But I'm completely out of topic now.  ::)