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

Author Topic: "SFML Works!" test code using Class  (Read 5002 times)

0 Members and 1 Guest are viewing this topic.

andrei186

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
"SFML Works!" test code using Class
« on: December 18, 2021, 12:23:34 pm »
I am trying the book SFML Game Development recommended on www.sfml-dev.org/learn.php
They start with the classic "SFML Works!" test code, but do it using Class:
Quote
class Game
{
 public:
    Game();
    void run();
 private:
    void processEvents();
    void update();
    void render();
 private:
    sf::RenderWindow mWindow;
    sf::CircleShape mPlayer;
};

So far so good. But the following definition of Game() constructor, I cut and copy it here:

Quote
Game::Game()
: mWindow(sf::VideoMode(640, 480), "SFML Application")
, mPlayer()
{
 mPlayer.setRadius(40.f);
 mPlayer.setPosition(100.f, 100.f);
 mPlayer.setFillColor(sf::Color::Cyan);
}
I learned C++  in 1998 using "How to programm C++" by H.M. and P.J. Deitel and this syntax puzzles me. Is this a new version C++ or just slip of pen? Anyway, as is it would not compile.

kojack

  • Sr. Member
  • ****
  • Posts: 309
  • C++/C# game dev teacher.
    • View Profile
Re: "SFML Works!" test code using Class
« Reply #1 on: December 18, 2021, 01:34:21 pm »
If you mean the two lines after the Game::Game() part, that's the initializer list. It was apparently introduced in C++98, so you would have just missed it. It lets you pass parameters to member variable constructors as the class is constructed.

As for why it's not compiling, you'll need to say what error the compiler is giving.

andrei186

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: "SFML Works!" test code using Class
« Reply #2 on: December 18, 2021, 02:30:58 pm »
Thank you, this is a great relief!
I tried to modify it to look more familiar to me:
Quote
Game::Game()
{
   sf::RenderWindow mWindow(sf::VideoMode(640, 480), "SFML Application");
   //{mWindow(sf::VideoMode(640, 480), "SFML Application"); this cause error no match for call to '(sf::RenderWindow) (sf::VideoMode, const chat[17])'
    mPlayer.setRadius(40.f);
    mPlayer.setPosition(100.f, 100.f);
    mPlayer.setFillColor(sf::Color::Cyan);
};
The other functions copied from the book:
Quote
void Game::run()
{
    while (mWindow.isOpen())
    {
        processEvents();
        update();
        render();
    }
}

void Game::processEvents()
{
    sf::Event event;
    while (mWindow.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            mWindow.close();
        }
}

void Game::update()
{
}

void Game::render()
{
    mWindow.clear();
    mWindow.draw(mPlayer);
    mWindow.display();
}

int main()
{
    Game game;
    game.run();
    return 0;
}
It compiles and runs with no errors yet it just flashes for a split second that 640x480 window with white background and no circle.
What I am missing?
« Last Edit: December 18, 2021, 04:16:11 pm by andrei186 »

kojack

  • Sr. Member
  • ****
  • Posts: 309
  • C++/C# game dev teacher.
    • View Profile
Re: "SFML Works!" test code using Class
« Reply #3 on: December 19, 2021, 03:01:46 am »
The reason it flickers for a split second is because you have two mWindow variables, one that lasts for the whole game but isn't set up and one that is set up (opens the window) but only exists for one function then cleans itself up.

The first mWindow is in the Game class declaration (the first block of code you posted). So Game contains an mWindow. That's the one that is used by most of the code.

The second mWindow is in the Game constructor definition (declarations say what is in a class, definitions say the actual code inside of the functions. So usually declaration in the .h, definition in the .cpp). The constructor has this line:
sf::RenderWindow mWindow(sf::VideoMode(640, 480), "SFML Application");
This is making a new mWindow variable. When you make a variable with the same name as one in the class like this, it's called "shadowing". The original mWindow exists, but is hidden while the second mWindow is alive. At the end of the constructor, the second mWindow (which actually made the window appear) is deleted as it leaves the scope of the constructor.

In the Game constructor, try replacing the line I quoted above with this instead:
mWindow.create(sf::VideoMode(640, 480), "SFML Application");
This will use the first mWindow and not make a second one.

andrei186

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: "SFML Works!" test code using Class
« Reply #4 on: December 19, 2021, 10:32:17 am »
Thank you, kojack, for taking time to write the detailed explanation. Impressed with the depth of your knowleadge.
Actually I suspected that something wrong was with the line you pointed at:
Quote
sf::RenderWindow mWindow(sf::VideoMode(640, 480), "SFML Application");

Using sf::RenderWindow both inside class definition and outside it might be confusing for compiler. The reason I had to use it outside class definition was:

In Game Class two private members were declared the same way:
Quote
private:
    sf::RenderWindow mWindow;
    sf::CircleShape mPlayer;

However initializing the second member
Quote
mPlayer.setRadius(40.f);
worked, while similar initializing the first member
Quote
mWindow(sf::VideoMode(640, 480), "SFML Application");
generated an error
Quote
no match for call to '(sf::RenderWindow) (sf::VideoMode, const chat[17])'
Why didn't it work and why it required calling "create", while similar declared mPlayer worked without "create"?

kojack

  • Sr. Member
  • ****
  • Posts: 309
  • C++/C# game dev teacher.
    • View Profile
Re: "SFML Works!" test code using Class
« Reply #5 on: December 19, 2021, 11:47:00 am »
mWindow.create(sf::VideoMode(640, 480), "SFML Application")
is effectively doing 2 things:
- creating the actual operating system window
- setting it to have a size of 640x480 and a title of "SFML Application"

If you just make a window and don't initialise it, like this:
sf::RenderWindow mWindow;
That makes the default sfml renderwindow object, but doesn't actually create the operating system window since not enough info is known yet. It needs the resolution to do the actual creation.
This lets you make the variable somewhere accessible, then delay making the OS window until later when the .create() function is called.

There are two alternatives:
One is to declare mWindow and give its constructor the resolution:
sf::RenderWindow mWindow(sf::VideoMode(640, 480), "SFML Application");
This is the same as calling .create() immediately after declaring the variable. Well, it's possibly more efficient, depending on how the code was written, since it's doing it all in one hit.
The downside is where ever you declare mWindow, that determines the lifetime of the window. If you make it in the Game() constructor, it only lives during that constructor.

The other way is what the book apparently had (I haven't read it). The initialiser list style lets you call the window constructor when the Game constructor is called.

Hopefully something in that made sense, usually when I'm teaching C++ it's in a classroom face to face, online is trickier. :)

I'd recommend having a go at some tutorials to refresh thing, C++ has changed a bit over the years. :)
For example:
https://www.cplusplus.com/doc/tutorial
https://www.tutorialspoint.com/cplusplus/index.htm

andrei186

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: "SFML Works!" test code using Class
« Reply #6 on: December 19, 2021, 01:47:49 pm »
Thank you very much. The link to C++ tutorials will certainly be of help. Now I see that things changed since I last used C++. Till now I have not come across the term "operating system window". Against  this term Google returns plenty of links to articles about operating system Windows but none about its meaning in this here context

kojack

  • Sr. Member
  • ****
  • Posts: 309
  • C++/C# game dev teacher.
    • View Profile
Re: "SFML Works!" test code using Class
« Reply #7 on: December 19, 2021, 02:57:43 pm »
Basically your operating system (Windows, Linux, OSX, etc) has some form of Window class that is used to display a window, receive input, etc. SFML hides that from you using it's own classes like sf::RenderWindow.
I mentioned it because the RenderWindow itself isn't the window you see on screen, but it does manage it. You need to give the RenderWindow enough info for it to create the real window. Otherwise nothing appears on screen.

For example, here's how you create a window in Microsoft Windows using C++: https://docs.microsoft.com/en-us/windows/win32/learnwin32/creating-a-window (that's what I meant by operating system window)
SFML hides that stuff, making it easier.

andrei186

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: "SFML Works!" test code using Class
« Reply #8 on: December 19, 2021, 03:29:15 pm »
I see now. Creating window in Windows native way is big pain indeed. Thanks again for the most professional aid