SFML community forums

Help => General => Topic started by: supdawg on November 28, 2012, 06:26:59 am

Title: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on November 28, 2012, 06:26:59 am
This is my event loop.
while(Window.isOpen()){
    while(Window.pollEvent(ScreenManager::getInstance().event)){
        if(ScreenManager::getInstance().event.type == sf::Event::Closed || ScreenManager::getInstance().event.key.code == sf::Keyboard::Escape){
          Window.close();
        }//end of if Event::Closed

        ScreenManager::getInstance().update(ScreenManager::getInstance().event);
    }//end of while/if Poll event

    Window.clear(sf::Color(0, 0, 0));
    ScreenManager::getInstance().draw(Window);
    Window.display();
  }//end of while isOpen

This changes from SplashScreen to TitleScreen
void SplashScreen::update(const sf::Event event){
  if(input->keyPressed(sf::Keyboard::T))
    ScreenManager::getInstance().addScreen(new TitleScreen()); //input*/

}//end of update()

This changes from TitleScreen to SplashScreen
void TitleScreen::update(const sf::Event event){
  if(input->keyPressed(sf::Keyboard::S))
    ScreenManager::getInstance().addScreen(new SplashScreen());//end of if enter is pressed*/
}//end of update()

If i have separate keys (S to change to SplashScreen and T to change to TitleScreen) it works fine. It changes screens nicely.
However, once i made both the keys the RETURN key, (i.e. press enter to change to SplashScreen and press Enter again to change to TitleScreen) it doesnt work. What it does is if i press enter once, it changes screens and changes back quickly. Note that i dont hold the enter key, i just press it once. I was thinking maybe the event stack has two return keys on it even though i pressed enter once? I have no idea how to fix it

Im on Mac OSX Mountain Lion
I use sublime text 2 with clang++
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: gyscos on November 28, 2012, 07:12:17 am
You don't check the event itself, but the state of the key. Maybe checking for a real KeyPressed event could help things : if some mouse event happen while you press the key for instance, then you may see such behaviour.
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on November 28, 2012, 08:53:51 am
Oh sorry i forgot to post my InputManager code. I do check the event here in another class

bool InputManager::keyPressed(sf::Keyboard::Key key){
  if(ScreenManager::getInstance().event.key.code == key) return true;
  return false;
}//end of keyPressed(int)

Basically, my inputManager class handles input by checking if the event.key.code matches with the given key in the parameter. the event here is the same event that i got from pollEvent in main.
Title: AW: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on November 28, 2012, 09:10:00 am
What gyscos meant is that you have to check first if the event type is KeyPressed or KeyReleased before you can check the key code. If you don't do that you run into undefined behaviour since key code can hold anything...
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on November 29, 2012, 03:04:56 am
im still confused about why event.key.code can have something random. does it not have the code of the key pressed?

and ok so i tried checking for event.KeyPressed like this:

bool InputManager::keyPressed(sf::Keyboard::Key key){
  if(ScreenManager::getInstance().event.KeyPressed && ScreenManager::getInstance().event.key.code == key) return true;
  return false;
}//end of keyPressed

but the problem doesnt go away. if i press enter it switches from splashscreen to titlescreen and back.

im sorry im so noob :(. im kind of new to graphics and windows.
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on November 29, 2012, 04:31:26 am
ok so i changed it to this and it works.
bool InputManager::keyPressed(sf::Keyboard::Key key){
  if(ScreenManager::getInstance().event.type == sf::Event::KeyPressed && ScreenManager::getInstance().event.key.code == key) return true;
  return false;
}//end of keyPressed

and i have one more question. i have seen some people use vectors of sf::Keyboard::Key to check input. can someone tell me what is is the benefit of using a vector of keys rather just checking individual keys like i did above?
Title: AW: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on November 29, 2012, 08:39:56 am
The question is why you don't use sf::Keyboard::isKeyPressed() directly instead of doing the same thing with events, which won't be in real time?

A vector of keys was probably used for key mapping, but I haven't seen that anywhere.

Also your code probably doesn't work since sf::Event::KeyPressed gets only trigerred once.
Title: Re: AW: Pressing Enter causes two screen switches instead of 1!
Post by: gyscos on November 29, 2012, 09:14:32 am
The question is why you don't use sf::Keyboard::isKeyPressed() directly instead of doing the same thing with events, which won't be in real time?

What do you mean ? Events are in real time. Also, since he only wants to trigger it once when the user press the key, it's easier to use events as he did.
That's actually what I was talking about in the previous message : if he uses isKeyPressed on each event, and non-keyboard event happen while the key is pressed, he'll think the key was pressed several time, which is not true.

But the way you check for the event is not really intuitive... What if you need to check other keys ?
Is there a reason you don't use the double-switch structure (one switch on the event type, the other on the event's key or button) ? Have you read the tutorial (http://www.sfml-dev.org/tutorials/2.0/window-events.php) ?

Also, on the code in the original post, you seemed to use different keys (T and S) for the two transitions, which would prevent the double-transition issue you mentioned...
Title: AW: Re: AW: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on November 29, 2012, 09:37:42 am
What do you mean ? Events are in real time. Also, since he only wants to trigger it once when the user press the key, it's easier to use events as he did.
No they are not. ;)
In most cases you won't directly notice the difference but events aren't triggered in realtime. From the logic point of view; with sf::Keyboard::isKeyPressed you simply check for the state of the key which happens as you ask for it, the events get triggered by the OS and first have to propagate through some messages pipelines of the OS before they get to the application, which is not 100% in real time.
You could probably check that by not limiting the framerate and check for both and count the frames in between. There will be a franedifference between sf::Keynoard and events. ;)
Edit: Additionally events can get delayed if the OS is doing some heavy lifting.

If it makes sense in his case to use events? Maybe, but the name is then confusing, it should rather be: wasPressed or pressedOnce and not isPressed since that suggests the current state. ;)
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on November 30, 2012, 11:12:43 pm
Double switch structure? whats that? I know that using a switch structure in the main while(isOpen) loop will allow you to detect cases .

In my main function, i will eventually have a switch case that detects what time of event it is (keypressed, closed etc etc) but then when i want to specifically check which key has been pressed, i use the inputManager functions which returns true or false based on which key has been pressed.

also sorry for asking multiple questions, but, in your opinions, if i have ScreenManager, GameScreen, SplashScreen, TitleScreen, InputManager, and Animation classes, which class should keep info about the time between frames?

I was thinking the ScreenManager should have a sf::Time member which holds the time between each frame. I want to keep track of the time between each frame such that if i want to control movement/ fading animations, i can change alpha values.

oh and yea my inputManager had S and T keys that change between screens but i changed it to the Return key.

and expl0it3r. so you're saying i should first check if the key is pressed by doing
sf::Keyboard::isKeypressed
and then i should check the actual key pressed by doing
event.key.code == key

and the reason to do this is because the event may be delayed so there might be a time difference?
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on November 30, 2012, 11:32:45 pm
Double switch structure? whats that? I know that using a switch structure in the main while(isOpen) loop will allow you to detect cases .
That would be a nested switch statement (see below); but it really depends on what you want to achieve (e.g. use a separated function to process key events).
switch(event.type)
{
    case sf::Event::KeyPressed:
        switch(event.key.code)
        {
                case sf::Keyboard::T:
                    // Do T
                    break;
        }
        break;
}


In my main function, i will eventually have a switch case that detects what time of event it is (keypressed, closed etc etc) but then when i want to specifically check which key has been pressed, i use the inputManager functions which returns true or false based on which key has been pressed.
You just have to make sure that event.type is equal to sf::Event::KeyPressed before you check with the input manager. And you also have to pass the correct event, otherwise event.key.code will only contain a random number.

if i have ScreenManager, GameScreen, SplashScreen, TitleScreen, InputManager, and Animation classes, which class should keep info about the time between frames?
Depends which class references what and how things are structured.

and expl0it3r. so you're saying i should first check if the key is pressed by doing
sf::Keyboard::isKeypressed
and then i should check the actual key pressed by doing
event.key.code == key

and the reason to do this is because the event may be delayed so there might be a time difference?
No! :D
If you want to check the key code you first have to check event.type == sf::Event::KeyPressed (Just read the tutorial!!!) ;)
If you want to check in real time, if a key is pressed, then use sf::Keyboard::isPressed().
Think of this like this:
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on December 01, 2012, 12:42:23 am
Ohh i get it now. That analogy makes it easier to understand.

And sorry to keep bothering but i am trying to achieve a fading animation during screen switches. i looked on the forum and people tried using a for loop to fade in and out and i tried something like this but it doesnt work. (what actually happens is i press enter, instead of fading away the screen just freezes for 2 seconds without dimming and then switches to the next screen) this is the code:

void SplashScreen::update(const sf::Event event, sf::RenderWindow &Window){
  if(input->keyPressed(sf::Keyboard::Return)){
    for(int i = opacity; i >= 0; i -= 5){ //opacity = 255
      Window.clear(sf::Color(0, 0, 0));
      text.setColor(sf::Color(255, 255, 255, i));
      Window.display();
    }
    ScreenManager::getInstance().addScreen(new TitleScreen()); //input*/
  }
}//end of update()

i was wondering how i can fade in and out. ive seen some people use the delta time between frames to fade in and out but why doesnt the above code work?
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on December 01, 2012, 01:04:54 am
Ohh i get it now. That analogy makes it easier to understand.
I'm glad it helped. ;)

I am trying to achieve a fading animation during screen switches. i looked on the forum and people tried using a for loop to fade in and out and i tried something like this but it doesnt work.
No idea where you saw that but it's, as you've noticed yourself, obviously wrong. Fading is a 'process' that needs to be spread over multiple frames. If you do it in a loop and in between frames, the color value certainly gets reduced, but you'll never see anything, since it happens 'in between frames' and gets never drawn to the screen. ;)

i was wondering how i can fade in and out. ive seen some people use the delta time between frames to fade in and out but why doesnt the above code work?
Maybe you want to take a look at my SmallGameEngine (https://github.com/eXpl0it3r/SmallGameEngine/), the code is simple, straight forward and should be quite clean (no global variables, no singletons, no (to me) 'strange' input processing).
The IntroState (https://github.com/eXpl0it3r/SmallGameEngine/blob/master/src/IntroState.cpp) does also have a fading sf::RectangleShape.
The current implementation makes use of the fact that the framerate is limited to 60fps (window.setFramerateLimit(60)), but should actually also depend on the delta time. ;)
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on December 01, 2012, 01:53:55 am
i thought i understood what a frame was but it seems not. in the for loop i call Window.display()... what i initially thought was every time you call Window.display()  it displays your contents to the Window and that is a one "frame". what exactly is a frame? if calling Window.display() doesnt mark the end of one frame and the beginning of the next frame then how exactly does it work?
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on December 01, 2012, 08:59:43 am
Technically you could define it as such; so you're right and your code might show a fade, but the way you do it, is not really a goid one.
For a state you should just have one display call and do the logic separated from the drawing part. Again take a look at the SmallGamEngine; each state has an update() and a draw() function. display() is called only once in the draw function and the decision to increase the alpha value happens in the update() function. ;)
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on December 01, 2012, 08:36:16 pm
Thanks so much expl0it3r. I got my fade to work by calling the update function of my ScreenManager and Animation classes which update the alpha values and screens. But i still have questions because some things still seem a bit strange.

First heres my main loop right now.

bool enableKeyRepeat = false;
  sf::RenderWindow Window(sf::VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32),"Hulq", sf::Style::None);
  Window.clear(sf::Color(0, 0, 0));
  Window.setFramerateLimit(60);
  Window.setKeyRepeatEnabled(enableKeyRepeat);

  ScreenManager::getInstance().initialize();
  ScreenManager::getInstance().loadContent();

  sf::Clock clock;
while(Window.isOpen()){
    while(Window.pollEvent(ScreenManager::getInstance().event)){
      switch (ScreenManager::getInstance().event.type){
        case sf::Event::Closed:
          Window.close();
          break;

        case sf::Event::KeyPressed:
          if(ScreenManager::getInstance().event.key.code == sf::Keyboard::Escape) {
            Window.close();
          }//if escape is pressed close window and skip everything in loop
          else
            ScreenManager::getInstance().update(ScreenManager::getInstance().event, Window);
          break;

        default:
          ScreenManager::getInstance().update(ScreenManager::getInstance().event, Window);
      }//end of switch(event.type)*/


    }//end of while Poll event
    Window.clear(sf::Color(0, 0, 0));
    /****/ScreenManager::getInstance().update(ScreenManager::getInstance().event, Window);
    ScreenManager::getInstance().draw(Window);
    Window.display();
    ScreenManager::getInstance().timeBetwFrame = clock.restart(); //records time between frame
  }//end of while isOpen

The fade in and out only works if i put the line with /****/ in. if i take that line out it doesnt work. basically if i take that line out, i have to continuously press the return key (which switches screens) in order to fade in and out. if i put the line in, then i can press the return key once and it will fade out, switch screens, and fade the new screen in. I have read the events tutorial. From what i deduced, if no event is happening it wont even go inside the while(pollEvent()) and it will just keep looping the while(isOpen()) loop. And my update() function is called inside the while(pollEvent()). So i made a call to update outside (the /****/ line). is this a good way to do things?

Let me try to give u the jist of what im doing. my update function updates everything. screen and alpha too. once the Return key is pressed itll start the fade animation. A bool value called "inTransition" will become true and while thats true it will keep doing the fade animation as long as update() is called. basically to keep changing the alpha value (make it go from 0 to 255 and back to 0 to effectively fade out and then fade in) update() must be called which checks the bool inTransition to see if its true and if true, it proceeds to change the alpha value. now, if i press Return and then dont press anything else, update() wont be called unless i bring it outside to the while(isOpen()) loop. however it makes more sense to keep it only inside the while(pollEvent()) loop because you update() based on whether there are events or not. and yes i did take your advice, and my update function draws various things to the window but i only call Window.display() once. i looked at your SmallGameEngine and it seems your using a stack to push and pop states. it seems kind of advanced and i dont quite understand how you fade in your IntroState. You reduce the alpha value everytime it loops irrespective of keypresses. Its really clean code but i havent really used stacks. How exactly do you use stacks in a game? Doesnt while(pollEvent()) push and pop events for you? And does C++ only support .hpp headers? i used .h headers for my headers.



also sorry i keep bombarding with questions. for my titlescreen i just draw sf::Text to the screen. is there any easy way to center the text in the center of the window? right now im doing this.

    text.setPosition(SCREEN_WIDTH/2 - ( (stringLength/3) * text.getCharacterSize()), SCREEN_HEIGHT/2 - text.getCharacterSize());
 

as you can see, its completely random guessing with numbers. i understand i could load an image with a sprite, but i think id run into the same problem centering a sprite.

btw how do you change a thread to [SOLVED]?

i apologize for the huge essay post.
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on December 01, 2012, 09:40:38 pm
The fade in and out only works if i put the line with /****/ in. if i take that line out it doesnt work. basically if i take that line out, i have to continuously press the return key (which switches screens) in order to fade in and out. if i put the line in, then i can press the return key once and it will fade out, switch screens, and fade the new screen in. I have read the events tutorial. From what i deduced, if no event is happening it wont even go inside the while(pollEvent()) and it will just keep looping the while(isOpen()) loop. And my update() function is called inside the while(pollEvent()). So i made a call to update outside (the /****/ line). is this a good way to do things?
As I already said if you do it with your strange event/input handling then you have to make sure that the event is filled with the correct values otherwise the behavior is undefined...

i looked at your SmallGameEngine and it seems your using a stack to push and pop states. it seems kind of advanced and i dont quite understand how you fade in your IntroState. You reduce the alpha value everytime it loops irrespective of keypresses. Its really clean code but i havent really used stacks.
Well as I said, the framerate is limited to 60fps thus I can rely on the fact the update function is getting called 60 times every second and thus reducing the alpha value by 1 every iteration will need ~4.25 seconds to go from 255 to 0. I'm drawing a rectangle over the whole screen and simply reduce it's alpha channel until it's fully transparent.
But you're right I don't do anything with keys, it just happens when you start that state until it reaches 0. ;)

How exactly do you use stacks in a game?
It's simply the FILO principle (First In Last Out) and you've got the two operations push() to put a new object onto the stack and pop to remove the top object.

Doesnt while(pollEvent()) push and pop events for you?
Yes it pushes the new events into the queue and pops one event every call and puts it into the referenced event object.

And does C++ only support .hpp headers? i used .h headers for my headers.
C++ (the standard) doesn't really say anything about this, but it's the compilers that define what works and what not and to my knowledge all C++ compiler support the .hpp extention and I advise everyone to use it, when they write C++ code, so you'd already see in what language a library or similar is written in: .c/.h = C; .cpp/.hpp = C++

is there any easy way to center the text in the center of the window? right now im doing this.
You should really read the documentation (http://www.sfml-dev.org/documentation/2.0/classsf_1_1Text.php)...
sf::Text text("Hello", font, 20);
text.setOrigin(text.getGlobalBounds().width/2.f, text.getGlobalBounds().height()/2.f);
text.setPosition(static_cast<sf::Vector2f>(window.getSize()/2.f));

btw how do you change a thread to [SOLVED]?
By editing your first post and changing the title there. ;)

FYI: You really shouldn't be using global variables, that is your singletons are global variables too! ;)
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on December 02, 2012, 12:50:41 am
Well as I said, the framerate is limited to 60fps thus I can rely on the fact the update function is getting called 60 times every second and thus reducing the alpha value by 1 every iteration will need ~4.25 seconds to go from 255 to 0. I'm drawing a rectangle over the whole screen and simply reduce it's alpha channel until it's fully transparent.
But you're right I don't do anything with keys, it just happens when you start that state until it reaches 0.

So youre update does get called every frame then. Ah i see. If i do that then my fade works. Before i display i call update everytime even if the user doesnt press any keys. The thing i was worried about is, if there is no event happening, what exactly happens? like say theres no event happening, what does event contain? i couldnt find this in the documentation for events. if the event stack is empty then what happens when u try to access an sf::Event member?
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: eXpl0it3r on December 02, 2012, 01:37:32 am
The thing i was worried about is, if there is no event happening, what exactly happens? like say theres no event happening, what does event contain? i couldnt find this in the documentation for events. if the event stack is empty then what happens when u try to access an sf::Event member?
sf::Event (https://github.com/SFML/SFML/blob/master/include/SFML/Window/Event.hpp) is just a data class, it holds some structs but they never get initialized with any 'default' values, thus if you just instantiate a sf::Event object and try to access a variable you'll get anything that could get casted to that type.
That's why I've been telling you now already a few times, that it's a bad idea to separate the event processing from the event 'capturing'. ;)
Title: Re: Pressing Enter causes two screen switches instead of 1!
Post by: supdawg on December 02, 2012, 02:29:18 am
alrite i get it.

i searched places and couldnt find the difference between global coordinates, screen coordinates and local coordinates. whats the difference between them?

is global your whole monitor and screen just your window?