This is my main game loop.
while (running)
{
window.Clear();
sceneManager.Update(&event);
window.SetColor(23, 23, 23, 255);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
running = false;
}
}
window.Display();
}
I want to detect keyboard input in my class called 'Scene'. To do this, I attempted to pass in the SDL_Event object to my scene manager every frame, which would then pass it to my scene where I could detect input. When I press a key, nothing is printed. I am wondering how I could correctly get input in a separate class outside of my main loop.
Scene.cpp:
void LoadingScene::Update(SDL_Event* event)
{
rain.Update();
text.Update();
if (event->type == SDL_KEYDOWN)
{
cout << "Keydown" << endl;
}
}
scene manager should be called within the event loop
Like this
while (running)
{
window.Clear();
window.SetColor(23, 23, 23, 255);
while (SDL_PollEvent(&event))
{
sceneManager.Update(&event);
if (event.type == SDL_QUIT)
{
running = false;
}
}
window.Display();
}
Related
I'm trying to detect keyPress only once, but it goes for random amount of presses. I'm using keyrelease, and it work normally if I have breakpoint.
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
} else {
characterScreen.handleEvent(event, window);
}
}
bool keyReleased = event.type == sf::Event::KeyPressed;
bool rightArrowKey = event.key.code == sf::Keyboard::Right;
bool leftArrowKey = event.key.code == sf::Keyboard::Left;
if (keyReleased&&leftArrowKey)
{
if (selectedCharacter == 0)
{
selectedCharacter = characterList.size() - 1;
}
else
{
selectedCharacter--;
}
changeCharacters(characterList[selectedCharacter], font, characterScreen);
std::cout << "left pressed" << std::endl;
keyReleased = false;
std::cout << keyReleased << std::endl;
}
else if (keyReleased && rightArrowKey)
{
if (selectedCharacter == characterList.size()-1)
{
selectedCharacter = 0;
}
else
{
selectedCharacter++;
}
changeCharacters(characterList[selectedCharacter], font, characterScreen);
}
window.clear(sf::Color::White);
characterScreen.update();
characterScreen.render(window);
window.display();
}
I've tryed window.setKeyRepeatEnabled(false); and keypressed, still nothing. Tryed different keyboard aswell.
When using (C)SMFL, we generally have a main loop condition rendering the main frame (the windows) and checking events, it can be an infinite loop (such as while (1)) or a more recomanded one like your while (window.isOpen()).
It means that the windows and all events listener are refreshed / updated each loop's turn, so if you press a key on your keyboard, you will trigger your keyboard's event listener, fine, and you will continue your code until re-enter in your main loop, and re-refreshing the windows and re-updating your event listener.
What the point of explaining that ? it just means by only pressing once a key, your computer will process maybe 10, 100 or maybe 1000 iteration of your main loop (depending on it's performances and more). So it's "normal" to works fine when you use convenient features like breakpoints, but in reality you can't.
You have a lot of possibilities, bad ones (like "use delay / pause" who's not recommended since it will halt your window's refresh and can be interpreted by a crash by your OS) or good ones like tampon variables, who'll cancel the entrance of some conditions by their state:
Example:
bool tmp_var = false;
while (window.isOpen()) {
// Warn, you called your variable keyReleased but it check keyPressed
if (event.type == sf::Event::KeyPressed && tmp_var == false) {
// Check wich key is pressed and perform required actions
tmp_var = true;
} else if (event.type == sf::Event::KeyReleased) {
tmp_var = false;
}
}
Note that the code can be not correct, I wanted to point out the reasoning
Why when I run this simple code and just doing nothing CPU usage by this app is around 0.4%
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 800), "hi", sf::Style::Close | sf::Style::Titlebar);
window.setFramerateLimit(60);
sf::Event event;
bool lostFocus = false;
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
else if (event.type == sf::Event::LostFocus)
lostFocus = true;
else if (event.type == sf::Event::GainedFocus)
lostFocus = false;
}
if (!lostFocus)
{
window.clear(sf::Color::White);
window.display();
}
}
}
But when I click on other app, CPU usage by this app increases to 12%.
Does GainedFocus actually eat so much cpu power or what?
(I just wanted to make a simple pause of game and saw this cpu usage)
As already mentioned, when your window doesn't have focus and you're not updating the window, the loop goes into a hot spin where it's continuously checking for events. When you've lost focus, you instead want to block and wait for a GainedFocus event to occur. As a very simple example, you could do something like
void block_until_gained_focus(sf::Window& window) {
sf::Event event;
while (true) {
if (window.waitEvent(event) && event.type == sf::Event::GainedFocus) {
return;
}
}
}
Then your main game loop could look something like
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
else if (event.type == sf::Event::LostFocus)
wait_until_gained_focus(window);
}
window.clear(sf::Color::White);
window.display();
}
Now if you wanted to do additional work while focus is lost you'll need a different implementation, but the key here is to use waitEvent instead of pollEvent.
I have main like this :
#include <SFML/Graphics.hpp>
#include <iostream>
#include "okno.h"
using namespace sf;
int main()
{
// Create the main window
RenderWindow app(VideoMode::getDesktopMode(), "Okno" ,Style::Fullscreen);
app.setKeyRepeatEnabled(false);
okno aplikacja(app);
// Start the game loop
while (app.isOpen())
{
// Process events
Event event;
event.type=Event::JoystickButtonPressed;
event.mouseButton.button = Mouse::Right;
while (app.pollEvent(event))
{
// Close window : exit
if (event.type == Event::Closed)
app.close();
if( event.type == Event::KeyPressed && event.key.code == Keyboard::Escape )
app.close();
}
aplikacja.click_przyciski(event);
aplikacja.obsluga_przyciskow();
event.type=Event::JoystickButtonPressed;
event.mouseButton.button = Mouse::Right;
aplikacja.rysuj();
aplikacja.menu=true;
event.type=Event::JoystickButtonPressed;
event.mouseButton.button = Mouse::Right;
//sleep(seconds(5));
// Update the window
//app.display();
}
return EXIT_SUCCESS;
}
And class okno.cpp like this :
#include "okno.h"
#include <iostream>
using namespace std;
int wyswietlanie =0;
okno::okno(RenderWindow &app): window(app)
{
textures[0].loadFromFile("grafika/tlo.png");
textures[1].loadFromFile("grafika/logo.png");
textures[2].loadFromFile("grafika/siatka.png");
textures[3].loadFromFile("grafika/button_start.png");
textures[4].loadFromFile("grafika/button_informacje.png");
textures[5].loadFromFile("grafika/button_wyjscie.png");
textures[6].loadFromFile("grafika/button_cofnij.png");
czcionka.loadFromFile("czcionki/czcionka_1.ttf");
for (int j=0;j<i;j++)
sprites[j].setTexture(textures[j]);
float x,y;
x=window.getView().getSize().x;
y=window.getView().getSize().y;
tekst.setString("Projekt wykonal : \n Wojciech Sorota.");
tekst.setCharacterSize(30);
tekst.setPosition(x/10,y/10);
tekst.setColor(sf::Color::Red);
tekst.setFont(czcionka);
sprites[0].setScale(x/sprites[0].getTextureRect().width,y/sprites[0].getTextureRect().height);
sprites[1].setPosition(x/2 - sprites[1].getTextureRect().width/2,y/2 - sprites[1].getTextureRect().height/2);
sprites[3].setPosition(x/10,y/10);
sprites[2].setScale(x/2/sprites[2].getTextureRect().width,y/2/sprites[2].getTextureRect().height);
sprites[2].setPosition(x/8,y/4);
sprites[4].setPosition( x/10+ sprites[3].getPosition().x + x/ 15,y/10 );
sprites[5].setPosition( x/10 +sprites[4].getPosition().x +x/15,y/10);
sprites[6].setPosition(x/10 + tekst.getPosition().x + tekst.getGlobalBounds().width,y/10);
menu=true;
}
okno::~okno()
{}
void okno::rysuj()
{
this->rysuj_intro();
this->rysuj_menu();
}
void okno::start_gra()
{
}
void okno::click_przyciski(Event &event)
{
if(event.type == Event::MouseButtonReleased && event.mouseButton.button == Mouse::Left)
{
if(click_sprite(sprites[3]))
start_gra();
else if(click_sprite(sprites[5]))
window.close();
else if( click_sprite(sprites[4]))
wyswietl_info(event);
}
}
void okno::wyswietl_info(Event &event)
{
{
while(1)
{
if(sf::Mouse::isButtonPressed(sf::Mouse::Left) && click_sprite(sprites[6]))
{
event.type=Event::JoystickButtonPressed;
event.mouseButton.button = Mouse::Right;
return;
}
window.clear();
window.draw(sprites[0]);
window.draw(sprites[2]);
window.draw(sprites[6]);
window.draw(tekst);
obsluga_przyciskow();
window.display();
}
}}
bool okno::click_sprite(Sprite a)
{
// transform the mouse position from window coordinates to world coordinates
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
// retrieve the bounding box of the sprite
sf::FloatRect bounds = a.getGlobalBounds();
// hit test
if (bounds.contains(mouse))
{
return true;
}
return false;
}
void okno::obluga_cofnij()
{
}
void okno::obsluga_przyciskow()
{
if(mysz_nad_sprite(sprites[3]))
sprites[3].setColor(sf::Color(100,100,100));
else
sprites[3].setColor(sf::Color(255,255,255));
if(mysz_nad_sprite(sprites[4]))
sprites[4].setColor(sf::Color(100,100,100));
else
sprites[4].setColor(sf::Color(255,255,255));
if(mysz_nad_sprite(sprites[5]))
sprites[5].setColor(sf::Color(100,100,100));
else
sprites[5].setColor(sf::Color(255,255,255));
if(mysz_nad_sprite(sprites[6]))
sprites[6].setColor(sf::Color(100,100,100));
else
sprites[6].setColor(sf::Color(255,255,255));
}
bool okno::mysz_nad_sprite(Sprite a)
{
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
if (a.getGlobalBounds().contains(mouse))
return true;
return false;
}
void okno::rysuj_intro()
{
if (wyswietlanie == 0)
{
for ( int n=0;n<=254;n++)
{
window.clear();
sprites[0].setColor(sf::Color(255, 255, 255, n));
sprites[1].setColor(sf::Color(255,255,255,n));
sleep(milliseconds(n/15));
window.draw(sprites[0]);
window.draw(sprites[1]);
window.display();
}
for (int n=254;n>=0;n--)
{
window.clear();
sprites[1].setColor(sf::Color(255, 255, 255, n));
sleep(milliseconds(n/15));
window.draw(sprites[0]);
window.draw(sprites[1]);
window.display();
}
wyswietlanie++;
}
}
void okno::rysuj_menu()
{
window.clear();
if (wyswietlanie==1)
for ( int n=0;n<=254;n++)
{
window.clear();
sprites[2].setColor(sf::Color(255,255,255,n));
window.draw(sprites[0]);
window.draw(sprites[2]);
window.draw(sprites[3]);
window.draw(sprites[4]);
window.draw(sprites[5]);
window.display();
if (n==254)
wyswietlanie++;
window.clear();
}
window.draw(sprites[0]);
window.draw(sprites[2]);
window.draw(sprites[3]);
window.draw(sprites[4]);
window.draw(sprites[5]);
window.display();
}
My question is why after i click on sprites[6] then i go back to loop [ pollEvent ] and then pollEvent return last event , but last event is mouseclick soo then it run script on mouseclick how to protect my function for this ?
SFML Event handling
Events should be handled something like this:
sf::Event event;
while (app.pollEvent(event))
{
// handle each event you want
switch (event.type)
{
case sf::Event::Closed:
closed(event);
Exit();
break;
case sf::Event::KeyPressed:
keyPressed(event);
break;
case sf::Event::KeyReleased:
keyReleased(event);
break;
case sf::Event::MouseButtonPressed:
mouseButtonPressed(event);
break;
case sf::Event::MouseButtonReleased:
mouseButtonReleased(event);
break;
case sf::Event::MouseMoved:
mouseMoved(event);
break;
/* ...many more events exist */
default:
cerr << "unhandle event of type: " << event.type << endl;
break;
}
}
And then, have a function for each event you want to handle.
void mouseMoved(const sf::Event& event)
{
// do something with the mouse event
mRelMousePos.x = event.mouseMove.x - mMousePos.x;
mRelMousePos.y = event.mouseMove.y - mMousePos.y;
mMousePos.x = event.mouseMove.x;
mMousePos.y = event.mouseMove.y;
}
As mentionned by #Hiura, you can't assign an event type to an sf::event and then reuse it in the pollEvent method, to be more precise, it's more the event.mouseButton.button = Mouse::Right; part that is problematic here. This is partly because the sf::Event class stores its event parameters (mouseButton, key, etc.) inside a union and partly because that's not the use intended for the sf::Event class.
Your code
Please code in english, always, you never know when you'll need to share a piece of code. And I'm not saying this because I'm a self-centered english speaking individual, in fact, I'm a french canadian.
Now, let's take a look specifically at the code you provided.
// Process events
Event event;
// these are problematic, you shouldn't do that.
//event.type=Event::JoystickButtonPressed;
//event.mouseButton.button = Mouse::Right;
while (app.pollEvent(event))
{
// using a switch or else if here would lower code repetition
// and useless check.
// Since both cases do the same thing, you could have just merge them.
// Close window : exit
if ((event.type == Event::Closed)
|| (event.type == Event::KeyPressed
&& event.key.code == Keyboard::Escape ))
{
app.close();
}
else if (event.type == Event::MouseButtonReleased
&& event.mouseButton.button == Mouse::Left)
{
// this should really go here
aplikacja.click_button(event); // thanks Google Translation
}
}
// Why? Why do you send the last event from your event loop to that?
//aplikacja.click_przyciski(event);
Some unnecessary tweaks here just for fun:
bool okno::click_sprite(Sprite sprite) // remember, meaningful names
{
// transform the mouse position from window coordinates to world coordinates
sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
// see how it's clearer and I just removed 7-8 LOC and the comments
// are now unnecessary here. The if clause was redundant since the contains
// method already returns a bool value.
return sprite.getGlobalBounds().contains(mouse);
}
I'm not going to go through the entire code, but you are close to a working app with SFML. There is some nice tutorials and the SFML source code is quite clear, see the SFML Github repo and the SFML game dev book for more info on how to use each part of SFML.
I am using SFML and C++ and I am getting an odd problem,
Here is my main game update method
while (renderService.Window.isOpen())
{
//Poll events
sf::Event event;
while (renderService.Window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
renderService.Window.close();
running = false;
}
MouseMovment(event);
MouseClick(event);
Update();
Draw();
}
and here is my MouseClick method
void Game::MouseClick(sf::Event event)
{
sf::Vector2i position = sf::Mouse::getPosition(renderService.Window);
if (event.mouseButton.button == sf::Mouse::Left && event.type == sf::Event::MouseButtonReleased)
{
std::cout << "Mouse released" << std::endl;
}
}
now here is the weird part, in my console sometimes my cout will be spammed like 10/20 times, but sometimes it will work perfectly, am I calling the event wrongly?
You're doing it wrong, suppose that a MouseButtonReleased event is fired and your polling function grabs it (follows the numbers in the comments):
while (renderService.Window.isOpen()) // 4) The loop starts again
{
//Poll events
sf::Event event;
while (renderService.Window.pollEvent(event)) // 1) Grabs the event // 5) No more events
{
if (event.type == sf::Event::Closed) // 2) Nope, it's not this one
renderService.Window.close();
running = false;
}
MouseMovment(event);
MouseClick(event); // 3) Yes, handle it // 6) Uses the unmodified event variable - undefined behavior
Update();
Draw();
}
you should rather do something like:
sf::Event event;
// while there are pending events...
while (window.pollEvent(event))
{
// check the type of the event...
switch (event.type)
{
// window closed
case sf::Event::Closed:
...
break;
// mouse button released
case sf::Event::MouseButtonReleased:
{
if (event.mouseButton.button == sf::Mouse::Left)
...
} break;
// we don't process other types of events
default:
break;
}
}
In SFML 2.1 on c++, is there a sf::Keyboard function that checks if any letter in the alphabet being pressed?
I know how to check if a certain key is pressed, like this:
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key))
Do I have to type all this:
if(sf::Keyboard::isKeyPressed(sf::Keyboard::A)&&sf::Keyboard::isKeyPressed(sf::Keyboard::B)&&sf::Keyboard::isKeyPressed(sf::Keyboard::C))
...all the way to sf::Keyboard::Z,
Or is there an easier way?
From the SFML website:
Many programmers use the KeyPressed event to get user input, and start to implement crazy algorithms that try to interpret all the possible key combinations to produce correct characters. Don't do that!
sf::Keyboard::isKeyPressed is for checking whether a key is pressed, which is good for things like movement: as long as the player is holding the 'left' key down, we wish to keep moving their character left. A KeyPressed event is for checking which key is pressed at the time it is pressed, which is good for things that happen only once: if the player jumps with the spacebar, we typically don't want them to keep jumping as long as the spacebar is held down.
When it comes to checking entered text, though, neither of these solutions are very good. In the official tutorials, we are advised against using these for checking text input - we have actually been given a different event for exactly this type of situation. The appropriate thing to do is to get the text-based contents of the key via the TextEntered event as described here. Get the text from the event then apply the logic you need to ensure its validity, or (if possible) use the text from the event directly.
Here's a solution with a counter increased every time when a letter key is pressed. window.setKeyRepeatEnabled() must be set to false to avoid getting multiple events while pressing a key:
#include <SFML/Graphics.hpp>
#include <iostream>
int main() {
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML");
int keyCounter = 0;
window.setKeyRepeatEnabled(false);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
else if(event.type == sf::Event::KeyPressed) {
if(event.key.code >= sf::Keyboard::A && event.key.code <= sf::Keyboard::Z) {
keyCounter++;
}
} else if(event.type == sf::Event::KeyReleased) {
if(event.key.code >= sf::Keyboard::A && event.key.code <= sf::Keyboard::Z) {
keyCounter--;
}
} else if(event.type == sf::Event::MouseMoved) {
/* move cursor inside the window to observe how the counter
behaves while pressing the keys */
std::cout << keyCounter << std::endl;
}
}
window.clear();
window.display();
}
return 0;
}
Alternative approach - iterating over enum:
#include <SFML/Graphics.hpp>
#include <iostream>
int main() {
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML");
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
} else if(event.type == sf::Event::MouseButtonPressed) {
/* click inside window to see if there is key pressed */
bool isp = false;
for (int i = sf::Keyboard::A; i <= sf::Keyboard::Z; ++i ) {
if(sf::Keyboard::isKeyPressed(static_cast<sf::Keyboard::Key>(i))) {
isp = true;
break;
}
}
std::cout << isp << std::endl;
}
}
window.clear();
window.display();
}
return 0;
}