SFML 2.1 is key pressed - c++

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;
}

Related

Multiple key presses SFML

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

Detecting if a touch pressed, not if its down?

i will make a beat em up game with sfml c++ on mobilephone. So i need to use the Touch function. The problem I have is, what is the best way to detect when the Touch has been pressed, and only execute the code which should be executed when the key has been pressed once? I need it for an animation when the Player make a kick. Now its always repeating the spritesheet animation loop, i wanna fix that, here is the a piece if my code where i need it:
...
if(animHit == true){
if(plrClock.getElapsedTime().asSeconds() > 0.1)
{
animRec.x ++;
if(animRec.x * 103 >= plrtex.getSize().x)
animRec.x = 0;
plrClock.restart();
}
}
FloatRect touchButtonRect = btnSprite.getGlobalBounds();
// the Touch is pressed the button
if(touchButtonRect.contains(worldPos)){
animHit = true;
}
else
{
if(animRec.x * 412<= plrtex.getSize().x){
animHit = false;
}
}
You haven't shown the minimal amount of code needed to replicate the problem, but i think i know where the problem lies. You most likely are trying to get the touch in the while loop without any events. Events are the things that tell your program to run things at, well, a trigger of sorts. This trigger can be a mouse click, resize of window, keyboard buttons or touch events.
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
using namespace std;
using namespace sf;
int main()
{
// create the window
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
window.setFramerateLimit(60);
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
if(event.type == sf::Event::Closed) window.close();
if (event.type == sf::Event::TouchBegan)
{
//do something
}
if (event.type == sf::Event::TouchEnded)
{
//do something
}
if (event.type == sf::Event::TouchMoved)
{
//do something
}
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
// end the current frame
window.display();
}
return 0;
}
With events you can use the triggers really well such as a screen touch. Using touchBegan it will record the single screen touch, even if you hold down the touch it will still be considered single touch.
Hope this helped.

Sfml lostFocus / gainedFocus cpu usage

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.

SFML event::TextEntered not working properly

I'm making a school project about image modifying and I'm using sfml to make something like a console but a bit more "beautiful".
while (window.isOpen()) {
Event event;
while (window.pollEvent(event)) {
if (event.type == Event::Closed)
window.close();
}
if (event.type == sf::Event::TextEntered)
{
//display text on screen
}
}
The problem is that when i press a certain key shortly on the display it appears like I've hold the key for a long period of time...
Example: pressing G, expecting to see only 1 G on the screen but on the screens there appears like 20 G.
Your if belongs inside the event polling loop:
while (window.isOpen())
{
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
window.close();
if (event.type == sf::Event::TextEntered)
{
//display text on screen
}
}
}
From your description, there is probably more going wrong, but you need to post more code to see that.
I think this is because when pressing a key that signal is always transmitted, so
try this :
sf::RenderWindow window(...);
window.setKeyRepeatEnabled(false);
while(...)
{
stuff...
}

SFML - pollEvent double run mouseclick

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.