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

Author Topic: Problem with "Manage different screens in a game"  (Read 8228 times)

0 Members and 2 Guests are viewing this topic.

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Problem with "Manage different screens in a game"
« on: August 30, 2012, 10:25:38 pm »
I ported the "Manage different screens in a game" from SFML 1.6 to 2.0 but have a problem I can't figure out.  Am running VC++ Express 2010.  The link to the 1.6 code on the web is:
https://github.com/SFML/SFML/wiki/TutorialScreens

screen_0:
When the project is run via debug, screen_0.hpp runs fine and the "presentation.png" image is displayed fine.  Everything works as expected.  If I highlight "Exit" and press ENTER, it exits.  I highlight "Play" and execution progresses to screen_1.

screen_1:
When screen_1 is displayed, I see the "presentation.png" image with "Play" and "Exit" on it.  A lot of horizontal black lines are cycling through out the display really fast at random.  No sprite rectangle is displayed.  Pressing any arrow key does nothing.

Pressing the ESC key takes me back to screen_0 as it should.  The "presentation.png" image is displayed and the "Continue" and "Exit" text are displayed properly.  Everything works in screen_0.  Highlighting "Continue" takes me back to screen_1 and the same problem for screen_1 is repeated.

In the code for screen_1, I set a breakpoint on the "App.display();" line.  Pressing the F5 key to continue VC++ debug, I see that the screen alternates between the ("presentation.png" image with the "Play" and "Exit" text on it) and a (black screen with no sprite rectangle on it).  When I step through the execution for screen_1, it steps from "while(Running)" to "App.display();" in a loop as it should.

So why is the screen_1 alternating between ("presentation.png" with Play and Exit on it) and a (black screen with no sprite rectangle on it)?

PS:  I didn't know how to convert the "App.SetBackgroundColor(sf::Color(0, 0, 0, 0));" from SFML 1.6 to 2.0 so I commented those lines out and replaced them with "App.clear();".

All of my converted SFML 2.0 code follows:

// SFML 2.0 - Manage Different Screens In A Game *** Main.cpp ***
//

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <sfml/Graphics.hpp>
#include "screens.hpp"


int _tmain(int argc, _TCHAR* argv[])
{
    //Applications variables
    std::vector<cScreen*> Screens;
    int screen = 0;

    //Window creation
    sf::RenderWindow App(sf::VideoMode(640, 480, 32), "SFML Demo 3");
    App.setPosition(sf::Vector2i(10, 10));   //Set topleft corner of window to 10, 10.

    //Mouse cursor no more visible
    App.setMouseCursorVisible(false);

    //Screens preparations
    screen_0 s0;
    Screens.push_back (&s0);
    screen_1 s1;
    Screens.push_back (&s1);

    //Main loop
    while (screen >= 0)
    {
        screen = Screens[screen]->Run(App);
    }

    return EXIT_SUCCESS;

}
 

// SFML 2.0 - Manage Different Screens In A Game  *** Screen.hpp ***

/* When speaking about screens, I mean Menu screen, Config screen, Game screen,
   etc... Those screens you find in every games. The problem here is that each
   screen can be compared to a small SFML application : Each screen will have
   its own events and will use some variables useless for other screens.

   So, we need to separate each screen in order to avoid conflicts. With SFML,
   it's very simple to do that! You just have to create a cScreen class which
   will represent each screen. This is an virtual object and it's containing
   only one method:
*/


#pragma once;   // Must have this statement or get compile errors.

class cScreen
{
public :
    virtual int Run (sf::RenderWindow &App) = 0;
};

// SFML 2.0 - Manage Different Screens In A Game  *** Screens.hpp ***

/* screens.hpp contains the cScreen include, plus the hpp of each screens of the
   game. Here, screen_0 is a menu, and screen_1 is the game. Each screen
   inherits from cScreen :
*/


#ifndef SCREENS_HPP_INCLUDED
#define SCREENS_HPP_INCLUDED

//Basic Screen Class
#include "screen.hpp"

//Including each screen of application
#include "screen_0.hpp"
#include "screen_1.hpp"

#endif // SCREENS_HPP_INCLUDED

// SFML 2.0 - Manage Different Screens In A Game  *** Screen_0.hpp ***

/* screen_0.hpp contains the object definition and its code. "Run" is like the
   main loop you can have in a simple SFML application. The constructor defines
   the first value of private members which are finally more like static
   variables in our case. This permits to have a fade presentation at first
   loading, since the menu will appear directly. Once background is shown, we
   use two string to make a menu in which you can navigate with direction's key.
   Choosing "Play" will go to the game, "Exit" will exit the application by
   returning -1 to the main function :
*/


#pragma once;

#include <iostream>
#include "screen.hpp"

class screen_0 : public cScreen
{
private:
    int alpha_max;
    int alpha_div;
    bool playing;
public:
    screen_0 (void);
    virtual int Run (sf::RenderWindow &App);
};

screen_0::screen_0 (void)
{
    alpha_max = 3*255;
    alpha_div = 3;
    playing = false;
}

int screen_0::Run (sf::RenderWindow &App)
{
    sf::Event Event;
    bool Running = true;
    sf::Texture Image;
    sf::Sprite Sprite;
    int alpha = 0;
    sf::Font Font;
    sf::Text Menu1;
    sf::Text Menu2;
    sf::Text Menu3;
    int menu = 0;

    if (!Image.loadFromFile("presentation.png"))
    {
        std::cerr<<"Error loading presentation.png"<<std::endl;
        return (-1);
    }
    Sprite.setTexture(Image);
    Sprite.setColor(sf::Color(255, 255, 255, alpha));
    if (!Font.loadFromFile("verdanab.ttf"))
    {
        std::cerr<<"Error loading verdanab.ttf"<<std::endl;
        return (-1);
    }
    Menu1.setFont(Font);
    Menu1.setCharacterSize(20);
    Menu1.setString ("Play");
    Menu1.setPosition(280.0, 160.0);
    Menu2.setFont(Font);
    Menu2.setCharacterSize(20);
    Menu2.setString("Exit");
    Menu2.setPosition(280.0, 220.0);
    Menu3.setFont(Font);
    Menu3.setCharacterSize(20);
    Menu3.setString("Continue");
    Menu3.setPosition(280.0, 160.0);

    //Clearing screen
    App.clear();

    if (playing)
    {
        alpha = alpha_max;
    }

    while (Running)
    {
        //Verifying events
        while (App.pollEvent(Event))
        {
            // Window closed
            if (Event.type == sf::Event::Closed)
            {
                return (-1);
            }
            //Key pressed
            if (Event.type == sf::Event::KeyPressed)
            {
                switch (Event.key.code)
                {
                    case sf::Keyboard::Up:
                        menu = 0;
                        break;
                    case sf::Keyboard::Down:
                        menu = 1;
                        break;
                    case sf::Keyboard::Return:
                        if (menu==0)
                        {
                            //Let's get play !
                            playing = true;
                            return (1);
                        }
                        else
                        {
                            //Let's get work...
                            return (-1);
                        }
                        break;
                    default :
                        break;
                }
            }
        }
        //When getting at alpha_max, we stop modifying the sprite
        if (alpha<alpha_max)
        {
            alpha++;
        }
        Sprite.setColor(sf::Color(255, 255, 255, alpha/alpha_div));
        if (menu==0)
        {
            Menu1.setColor(sf::Color(255, 0, 0, 255));
            Menu2.setColor(sf::Color(255, 255, 255, 255));
            Menu3.setColor(sf::Color(255, 0, 0, 255));
        }
        else
        {
            Menu1.setColor(sf::Color(255, 255, 255, 255));
            Menu2.setColor(sf::Color(255, 0, 0, 255));
            Menu3.setColor(sf::Color(255, 255, 255, 255));
        }

        //Drawing
        App.draw(Sprite);
        if (alpha==alpha_max)
        {
            if (playing)
            {
                App.draw(Menu3);
            }
            else
            {
                App.draw(Menu1);
            }
            App.draw(Menu2);
        }
        App.display();
    }

    //Never reaching this point normally, but just in case, exit the application
    return (-1);
}
 

// SFML 2.0 - Manage Different Screens In A Game  *** Screen_1.hpp ***

/* screen_1.hpp contains the game itself. We can't exit from the game directly.
   If you push Escape, you'll go on the Main Menu. If you move the "player" and
   go to the menu, you can go back to the game and your position will stay the
   same. Because your object screen_1 has not been destroyed
*/


#pragma once;

#include <iostream>
#include "screen.hpp"

class screen_1 : public cScreen
{
private:
    int movement_step;
    int posx;
    int posy;
    sf::Sprite Sprite;
public:
    screen_1 (void);
    virtual int Run (sf::RenderWindow &App);
};

screen_1::screen_1 (void)
{
    movement_step = 5;
    posx = 320;
    posy = 240;

    //Setting sprite
    Sprite.setColor(sf::Color(255, 255, 255, 150));
    Sprite.setTextureRect(sf::IntRect(0, 0, 10, 10));
}

int screen_1::Run (sf::RenderWindow &App)
{
    sf::Event Event;
    bool Running = true;

    //Clearing screen
    App.clear();

    while (Running)
    {
        //Verifying events
        while (App.pollEvent(Event))
        {
            // Window closed
            if (Event.type == sf::Event::Closed)
            {
                return (-1);
            }
            //Key pressed
            if (Event.type == sf::Event::KeyPressed)
            {
                switch (Event.key.code)
                {
                    case sf::Keyboard::Escape:
                        return (0);
                        break;
                    case sf::Keyboard::Up:
                        posy -= movement_step;
                        break;
                    case sf::Keyboard::Down:
                        posy += movement_step;
                        break;
                    case sf::Keyboard::Left:
                        posx -= movement_step;
                        break;
                    case sf::Keyboard::Right:
                        posx += movement_step;
                        break;
                    default:
                        break;
                }
            }
        }

        //Updating
        if (posx>630)
            posx = 630;
        if (posx<0)
            posx = 0;
        if (posy>470)
            posy = 470;
        if (posy<0)
            posy = 0;
        Sprite.setPosition(posx, posy);

        //Drawing
        App.draw(Sprite);
        App.display();
    }

    //Never reaching this point normally, but just in case, exit the application
    return -1;
}
 

Thanks for any help,
Raptor
« Last Edit: September 01, 2012, 10:37:16 am by Raptor88 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #1 on: August 30, 2012, 10:37:30 pm »
Quote
A lot of horizontal black lines are cycling through out the display really fast at random.
This is probably because you call App.clear() just once outside the game loop, instead you should call it every single iteration, so move the statement before the actual draw calls.
If you want a diffrent background color, you can pass it on the clear call, e.g. App.clear(sf::Color::Red).
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #2 on: August 30, 2012, 10:43:48 pm »
setbackgroundcolor is from 1.3 which is ancient by now.
I'm digging through code and seeing mistakes already: loading image and font in run method, should be moved to c-tor. Actually this method just looks weird, the flow gets stuck in infinite while(Running) untill switch to other screen happens.
I'm not really sure, the way I do it is push the screens onto a stack and call run and render of the top one and the screens can request a pop(request as in, not pop themselves because that would cause the flow to return to function of object that got destroyed, but tell the wrapper around stack to do a pop next loop).
« Last Edit: August 30, 2012, 10:50:50 pm by FRex »
Back to C++ gamedev with SFML in May 2023

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #3 on: August 30, 2012, 10:50:39 pm »
setbackgroundcolor is from 1.3 which is ancient by now.
Yeah I knew that wasn't SFML 1.6, since I've never seen it. ;D

@Raptor88: If you want a state/screen manager you can take a look at my implementation on GitHub of the tutorial from DevGeek.com on state manager. Feel free to use it. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #4 on: August 30, 2012, 11:03:13 pm »
Quote
A lot of horizontal black lines are cycling through out the display really fast at random.
This is probably because you call App.clear() just once outside the game loop, instead you should call it every single iteration, so move the statement before the actual draw calls.
If you want a diffrent background color, you can pass it on the clear call, e.g. App.clear(sf::Color::Red).

Yep, calling the "App.clear();" statement every iteration works.  Revised code snippet is:

        App.clear(sf::Color::Blue);
        App.draw(Sprite);
        App.display();

Thanks for showing me how to set the background color too.

Now the problem is that the sprite rectangle does not display.  Any ideas on that?

Thanks!
Raptor

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #5 on: August 30, 2012, 11:10:10 pm »
FRex and eXpl0it3r,

I just want to get the code working as it is advertised, to see if it really preserves the state of screen-1 as it is when exiting back to screen_0.  I want that feature for my craps game so if the user exits play to change some setup, he can return to exactly where he left off and continue without a lot of extra coding on my part.

Thanks,
Raptor

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #6 on: August 30, 2012, 11:11:11 pm »
Now the problem is that the sprite rectangle does not display.  Any ideas on that?
I'm not sure what you mean by that? Do you mean you don't see a sprite or white rectangle at all?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #7 on: August 30, 2012, 11:47:49 pm »
Now the problem is that the sprite rectangle does not display.  Any ideas on that?

I'm not sure what you mean by that? Do you mean you don't see a sprite or white rectangle at all?
No, I don't see a sprite or any rectangle at all in screen_1.  All I see is a solid blue screen.

Thanks,
Raptor
« Last Edit: August 30, 2012, 11:52:39 pm by Raptor88 »

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #8 on: August 31, 2012, 01:58:09 am »
Got screen_1.hpp working. 

Replaced:
sf::Sprite Sprite; (and associated code)
-with-
sf::RectangleShape rectangle;  (and associated code)

Also replaced the "magic numbers" in the posx and posy bounds checking, with variable names.
I'll replace the "magic numbers" for the rectangle size later.

Everything works now.  And yes, the position of the rectangle is saved when exiting to screen_0 and returning back to screen_1.

Here's the working code for screen_1:
// SFML 2.0 - Manage Different Screens In A Game  *** Screen_1.hpp ***

/* screen_1.hpp contains the game itself. We can't exit from the game directly.
   If you push Escape, you'll go on the Main Menu. If you move the "player" and
   go to the menu, you can go back to the game and your position will stay the
   same. Because your object screen_1 has not been destroyed
*/


#pragma once;

#include <iostream>
#include "screen.hpp"


class screen_1 : public cScreen
{
private:
    int movement_step;
    int posx;
    int posy;
    int topBoundry, leftBoundry, rightBoundry, bottomBoundry;

public:
    screen_1 (void);
    virtual int Run (sf::RenderWindow &App);
};

// Constructor
screen_1::screen_1 (void)
{
    movement_step = 10;
    posx = 320;
    posy = 240;

    // Setup boundries for rectangle
    // (Note RenderWindow size is 640 x 480)
    topBoundry = 5;
    leftBoundry = 5;
    rightBoundry = 605;
    bottomBoundry = 445;
}

int screen_1::Run (sf::RenderWindow &App)
{
    sf::Event Event;
    bool Running = true;

    // rectangle size
    sf::Vector2f v(30.0f,30.0f);

    // Setup rectangle shape
    sf::RectangleShape rectangle;
    rectangle.setSize(v);
    rectangle.setOutlineColor(sf::Color(33,233,22));
    rectangle.setFillColor(sf::Color(144,33,223));
    rectangle.setOutlineThickness(5);
    rectangle.setPosition(50, 120);
       
    while (Running)
    {
        //Verifying events
        while (App.pollEvent(Event))
        {
            // Window closed
            if (Event.type == sf::Event::Closed)
            {
                return (-1);
            }
            //Key pressed
            if (Event.type == sf::Event::KeyPressed)
            {
                switch (Event.key.code)
                {
                   case sf::Keyboard::Escape:
                        return (0);
                        break;
                   case sf::Keyboard::Up:
                        posy -= movement_step;
                        break;
                   case sf::Keyboard::Down:
                        posy += movement_step;
                        break;
                   case sf::Keyboard::Left:
                        posx -= movement_step;
                        break;
                   case sf::Keyboard::Right:
                        posx += movement_step;
                        break;
                   default:
                        break;
                }
            }
        }

        // Insure rectange with outline no go beyond frame.
        if (posx < leftBoundry)
            posx = leftBoundry;
        if (posx > rightBoundry)
            posx = rightBoundry;
        if (posy < topBoundry)
            posy = topBoundry;
        if (posy > bottomBoundry)
            posy = bottomBoundry;
        rectangle.setPosition(posx, posy);

        //Drawing
        App.clear(sf::Color::Blue);
        App.draw(rectangle);
        App.display();
    }

    //Never reaching this point normally, but just in case, exit the application
    return -1;
}
 
« Last Edit: August 31, 2012, 02:10:23 am by Raptor88 »

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #9 on: August 31, 2012, 02:06:11 am »
Could someone explain the following to me?

    // Setup boundries for rectangle
    // (Note RenderWindow size is 640 x 480)
    topBoundry = 5;
    leftBoundry = 5;
    rightBoundry = 605;
    bottomBoundry = 445;

Using the values above, the rectangle is limited to just touching the inside of the frame.  I had to set the top and left boundries 5 less than zero to achieve this.  Why do the right and bottom boundries have to be 35 units less than the screen size of 640 x 480?

Thanks,
Raptor

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #10 on: August 31, 2012, 10:29:37 am »
This has nothing to do with the window itself, you're comparing the position of the sprite, which is represented through one point, but your sprite is a rectangle not a point, thus if you check posx > rightBoundary you're actually checking if the left side of your sprite has moved over the right border of the window, but in the mean time the right side of the sprite has long passed the right border. So by offsetting the boundary you take the sprite size into account. ;)
It's simpile axis-aligned collision detection (google can give you some hints on it).
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Raptor88

  • Full Member
  • ***
  • Posts: 111
    • View Profile
    • Email
Re: Problem with "Manage different screens in a game"
« Reply #11 on: August 31, 2012, 09:09:27 pm »
This has nothing to do with the window itself, you're comparing the position of the sprite, which is represented through one point, but your sprite is a rectangle not a point, thus if you check posx > rightBoundary you're actually checking if the left side of your sprite has moved over the right border of the window, but in the mean time the right side of the sprite has long passed the right border. So by offsetting the boundary you take the sprite size into account. ;)
It's simpile axis-aligned collision detection (google can give you some hints on it).

eXpl0it3r,

Thanks for pulling the chain that clicks the light bulb in my head  ;) .
Of course, it's all so clear now.  The position of the rectangle is defined by the point at its upper left corner.

Thanks once again for your help,
Raptor

 

anything