I wanted to disable repetitive key presses on holding so I used this command
window.setKeyRepeatEnabled(false)
It does not seem to work
#include<iostream>
#include<SFML/Graphics.hpp>
int main(int argc, char const *argv[])
{
sf::RenderWindow window(sf::VideoMode(800,600),"shape change color",sf::Style::Close);
window.setKeyRepeatEnabled(false);
int a=0;
while (window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
if (event.key.code == sf::Keyboard::Escape)
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
a++;
std::cout << a << std::endl;
window.clear();
window.display();
}
}
It is recommended to check the following sections in the documentation such as Events and Keyboard
If a key is held, multiple KeyPressed events will be generated, at the default operating system delay (ie. the same delay that applies when you hold a letter in a text editor). To disable repeated KeyPressed events, you can call window.setKeyRepeatEnabled(false). On the flip side, it is obvious that KeyReleased events can never be repeated.
sf::Keyboard::isKeyPressed is the real-time input interface, it has nothing to do with events and it doesn't make sense to mix them.You can try:
while(window.pollEvent(event))
{
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
window.close();
}
and
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::A)
std::cout << a << std::endl;
Please:
read the documentation and tutorials
use the forum when you have problems
Related
I am new to Game Development. I managed to create a simple game (like Space Invaders) as well as a simple start Menu using C++ and SFML. However, upon pressing "Enter" on the main menu, the game is not being launched. How do I link it properly? I appreciate your help. This is not homework.
main.cpp codes
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include "GameObjectManager.h"
#include "Menu.h"
using namespace std;
int main()
{
sf::Texture galaxyBackgroundTexture;
sf::Sprite galaxyBackground;
if (!galaxyBackgroundTexture.loadFromFile("Textures/galaxybackground.png")) {
cout << "Failed to load Image" << endl;
}
galaxyBackground.setTexture(galaxyBackgroundTexture);
sf::RenderWindow window(sf::VideoMode(1200, 800), "Space Invader Test");
Menu menu(window.getSize().x, window.getSize().y);
window.setFramerateLimit(144);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Key::Return)
{
menu.GetPressedItem();
cout << "Play button has been pressed." << endl;
GameObjectManager* gameObjectManagerManager = new GameObjectManager(&window);
gameObjectManager->update();
gameObjectManager->render(window);
}
else if (event.type == sf::Event::Closed)
{
window.close();
}
else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
{
window.close();
}
}
window.clear();
window.draw(galaxyBackground);
menu.draw(window);
window.display();
}
return 0;
}
Menu.h
#pragma once
#include "SFML/Graphics.hpp"
#define MAX_NUMBER_OF_ITEMS 2
class Menu
{
public:
Menu(float width, float height);
~Menu();
void draw(sf::RenderWindow& window);
int GetPressedItem() { return selectedItemIndex; }
private:
int selectedItemIndex;
sf::Font font;
sf::Text menu[MAX_NUMBER_OF_ITEMS];
};
Menu.cpp
#include "Menu.h"
Menu::Menu(float width, float height)
{
if (!font.loadFromFile("arial.ttf"))
{
cout << "can't load font" << endl;
}
// initialise Menu items
menu[0].setFont(font);
menu[0].setColor(sf::Color::Red);
menu[0].setString("Play");
menu[0].setPosition(sf::Vector2f(width / 2, height / (MAX_NUMBER_OF_ITEMS + 1) * 1));
// EXIT
menu[1].setFont(font);
menu[1].setColor(sf::Color::White);
menu[1].setString("Exit");
menu[1].setPosition(sf::Vector2f(width / 2, height / (MAX_NUMBER_OF_ITEMS + 1) * 2));
}
selectedItemIndex = 0;
Menu::~Menu()
{
}
void Menu::draw(sf::RenderWindow &window)
{
for (int i = 0; i < MAX_NUMBER_OF_ITEMS; i++)
{
window.draw(menu[i]);
}
}
The console window would print:
"Play button has been pressed"
But it does not proceed to the game. Nothing else happens.
"window redefinition" error occurs because both your RenderWindow objects have the same identifiers (i.e. window). You might want to change the name of the second window or better yet use the same window.
The second error, sf::Text::setColor() is deprecated means that it is no longer "useable" or "is not suggested to be used". SFML has two new better functions for this:
sf::Text::setFillColor() : to set the fill of your text.
sf::Text::setOutlineColor() : to give your text an outline (you also need to do change the thickness using setOutlineThickness()).
Moreover, I'd suggest you to use a State Machine for different scenes instead of two separate windows. It really isn't that difficult and will help you learn a few more things. You're somewhat already achieving this with your gameObjectManager. You just need to abstract it and implement it for your menu class as well. And since you have only two scenes you can simply use an integer or boolean to switch between these two.
EDIT: an idea of what you need to do to your main.cpp file
int main()
{
sf::RenderWindow window(sf::VideoMode(1200, 800), "Space Invader Test");
GameObjectManager* gameObjectManagerManager = nullptr;
bool inGame = false; //true = game has started, false = menu screen
while (window.isOpen())//this is the main loop
{
sf::Event event;
while (window.pollEvent(event)) //this is the event loop
{
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Key::Return)
{
if(!inGame)
{
if(menu.GetPressedItem() == PlayButton) //assuming your function returns which button in the menu has been pressed
{
cout << "Play button has been pressed." << endl;
inGame = true;
gameObjectManagerManager = new GameObjectManager(&window);
}
else
{
window.close(); //since the other button is exit
}
}
}
if (event.type == sf::Event::Closed) window.close();
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) window.close();
}
//this is the place where you call your updates
if(inGame) gameObjectManagerManager->update();
window.clear();
window.draw(galaxyBackground);
if(!inGame)menu.draw(window);
if(inGame) gameObjectManagerManager->render();
window.display();
}
return 0;
}
I want to use the keyboard input as a parameter for a function. I'm trying to get a keyboard input that returns a char: the key pressed.
Is there a better way to do it than how I'm doing it now?
char getKey() {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
return 'A';
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
return 'A';
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::B))
{
return 'B';
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::C))
{
return 'C';
}
//...
return '\0';
}
I know you can get use TextEntered, but I don't want to get other ASCII keys(å, ∫, ç, ...)
Is there an easier way to do this without going through every letter?
You can just handle events in your code
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
break;
}
else if(event.type == sf::Event::KeyPressed)
{
const sf::Keyboard::Key keycode = event.key.code;
if (keycode == sf::Keyboard::A)
std::cout << "A is pressed";
}
}
Enum fields for letters are arranged in the same way as in the ASCII. By using this property you can get a char by adding abd subtracting:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
int main() {
sf::RenderWindow window(sf::VideoMode(1200, 650), "");
std::string enteredChars;
enteredChars.reserve(1000);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed || event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
window.close();
} else if (event.type == sf::Event::KeyPressed) {
const sf::Keyboard::Key keycode = event.key.code;
if (keycode >= sf::Keyboard::A && keycode <= sf::Keyboard::Z) {
char chr = static_cast<char>(keycode - sf::Keyboard::A + 'a');
enteredChars.push_back(chr);
}
}
}
window.clear();
window.display();
}
std::cout << enteredChars << "\n";
}
I am trying to use sfml to build a app that is functionally running multiple windows at once. In order to do this I am trying to do what would usually be done from the while running loop inside of a function that has a for loop that goes through a vector of RenderWindows. There is another function that adds to that vector. The issue is that RenderWindows are non-copyable. Any help is appreciated.
My Vectors
vector <MakeKey::NewKey> KeyArray;
vector <sf::RenderWindow> WindowArray;
int VectorSize;
May Main
int main()
{
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::Default);
MakeKey MakeKey;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A)
MakeKey.DrawKey("A");
else if (event.key.code == sf::Keyboard::D)
MakeKey.DrawKey("D");
//Ect
}
if (event.type == sf::Event::Closed)
window.close();
}
MakeKey.StepWindows();
}
return EXIT_SUCCESS;
}
My StepWindows Function
void MakeKey::StepWindows()
{
for (int i{ 0 }; i > VectorSize; i++)
{
cout << "Inside Step Windows For Loop" << endl;
WindowArray[i].setActive(true);
WindowArray[i].clear(sf::Color::Transparent);
WindowArray[i].draw(KeyArray[i].Sprite);
WindowArray[i].display();
}
}
My DrawKey Function
void MakeKey::DrawKey(string input)
{
MakeKey::NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
VectorSize++;
//WindowArray.reserve(VectorSize);
//attempting to reference deleted function error
//WindowArray.emplace_back();
//same error
WindowArray[VectorSize].create(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
KeyArray.emplace_back(move(Key));
cout << "KeyArray Has " << KeyArray.size() << " Elements\n" << "WindowArray Has " << WindowArray.size() << " Elements" << endl;
}
And My Key struct
typedef struct KeyStruct {
sf::Image Img;
sf::Texture Tex;
sf::Sprite Sprite;
}NewKey;
Store a pointer instead. std::unique_ptr<sf::RenderWindow> should be suitable. Initialize it with new or std::make_unique<sf::RenderWindow> (C++14).
Note that your main loop will need to be radically different as you would need to poll several windows. pollEvent is unsuitable as it blocks: if you call it on wnd1, you won’t be able to process events arriving to other windows until some event arrives to wnd1 as well.
Ok so I have a program that has a void that opens a new window then draws a image on that window every time I call the void. It will let me open a second window but won't let me open it again till I close the second window. I think I am thinking about it wrong if I am can someone give me a better way to do it. Here's my code I don't think its 100% necessary but idk.
My goal is to get it to allow me to open multiple windows doing their own thing on the screen. I am trying to open a new window by calling the DrawKey void.
It is opening a window when I press a key the first time but it is limiting me to the main window and one key window. I want to be able to have as many key windows open as I feel the need for.
class MakeKey
{
public:
typedef struct KeySprite {
sf::Image Img;
sf::Texture Tex;
sf::Sprite Sprite;
}Key;
static bool setTransparency(HWND hwnd, unsigned char alpha) { ... }
static bool setShape(HWND hwnd, const sf::Image& image) { ... }
static sf::Vector2i RandSpawn(sf::Image image) { ... }
static void MakeTopWindow(HWND hwnd) { ... }
static void DrawKey(string key)
{
const unsigned char opacity = 1000;
Key Key;
Key.Img.loadFromFile("Assets/Images/A.png");
sf::RenderWindow window(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
setTransparency(window.getSystemHandle(), opacity);
if (key == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (key == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
else if (key == "E")
Key.Img.loadFromFile("Assets/Images/E.png");
else if (key == "Q")
Key.Img.loadFromFile("Assets/Images/Q.png");
else if (key == "S")
Key.Img.loadFromFile("Assets/Images/S.png");
else if (key == "W")
Key.Img.loadFromFile("Assets/Images/W.png");
else if (key == "X")
Key.Img.loadFromFile("Assets/Images/X.png");
else if (key == "Z")
Key.Img.loadFromFile("Assets/Images/Z.png");
else if (key == "Esc")
Key.Img.loadFromFile("Assets/Images/esc.png");
setShape(window.getSystemHandle(), Key.Img);
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
window.setPosition(MakeKey::RandSpawn(Key.Img));
while (window.isOpen())
{
MakeTopWindow(window.getSystemHandle());
window.clear(sf::Color::Transparent);
window.draw(Key.Sprite);
window.display();
}
}
};
Main
int main()
{
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::None);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
MakeKey::MakeTopWindow(window.getSystemHandle());
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A)
MakeKey::DrawKey("A");
else if (event.key.code == sf::Keyboard::D)
MakeKey::DrawKey("D");
else if (event.key.code == sf::Keyboard::E)
MakeKey::DrawKey("E");
else if (event.key.code == sf::Keyboard::Q)
MakeKey::DrawKey("Q");
else if (event.key.code == sf::Keyboard::S)
MakeKey::DrawKey("S");
else if (event.key.code == sf::Keyboard::W)
MakeKey::DrawKey("W");
else if (event.key.code == sf::Keyboard::X)
MakeKey::DrawKey("X");
else if (event.key.code == sf::Keyboard::Z)
MakeKey::DrawKey("Z");
else if (event.key.code == sf::Keyboard::Escape)
MakeKey::DrawKey("Esc");
}
if (event.type == sf::Event::Closed)
window.close();
}
MakeKey::MakeTopWindow(window.getSystemHandle());
window.clear(sf::Color::Transparent);
window.display();
}
return EXIT_SUCCESS;
}
There is no error just no doing quite what I want and I want help figuring out how to make it do what I want.
I'm working on a little SFML game in C++. What I'm trying to do is start the game with an introductory text that flashes two different colors, like "Arturo Girona Presents." I made it work by using a counter that incremented inside the while (window.isOpen()) loop, but then I tried using an sf::Clock to see if it made the flashing look less random. However, for some reason, the clock keeps resetting after each loop when I haven't explicitly told it too, so it's not transitioning from the text screen. How's the clock resetting by itself and how do I fix it?
Here's my while loop:
int count = 0;
sf::Clock clock;
int timer = clock.getElapsedTime().asMilliseconds();
while (window.isOpen())
{
count++;
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
while (timer < 5000)
{
if (timer < 200 && introText1.getColor() == sf::Color::Red)
{
introText1.setColor(sf::Color::White);
window.draw(introText1);
window.display();
}
if (timer < 200 && introText1.getColor() == sf::Color::White)
{
introText1.setColor(sf::Color::Red);
window.draw(introText1);
window.display();
}
break;
}
if (timer == 5000) {
window.clear();
window.draw(door);
window.draw(doorWindow1);
window.display();
}
cout << timer << endl;
if (timer > 0)
cout << "Time is moving" << endl;
}
The clock is not being reset, you simply never read the new value. ;-)
Move int timer = clock.getElapsedTime().asMilliseconds(); inside the main loop.
Additionally, you don't want the while (timer < 5000) loop especially with a break as last statement.