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.
Related
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
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 give my Sprite some extra speed when you press the spacebar for 3 seconds. After that you should wait 10 Seconds before using it again.
I tried using SFML's Time, but the clock starts right away as the program starts so it starts anyway....
Short Question: How can I delay a function without freezing the program like Sleep() does.
Code(console only for dev progess as it slows):
#include "SFML/Graphics.hpp"
#include <iostream>
#include <Windows.h>
int main()
{
using namespace std;
sf::Clock ClockSpeedFunc, Cooldown;
ClockSpeedFunc.restart();
bool Timer, CooldownTimer = false;
sf::RenderWindow window(sf::VideoMode(600, 600), "SFML WORK!");
sf::Texture texture;
if (!texture.loadFromFile("PlayerTexture.jpg"))
{
std::cout << "Error loading PlayerTexture.jpg" << std::endl;
}
sf::Sprite sprite;
sprite.setTexture(texture);
sprite.setPosition(sf::Vector2f(50, 40));
sprite.setPosition(sf::Vector2f(50, 40));
sprite.setPosition(sf::Vector2f(50, 40));
sprite.setPosition(sf::Vector2f(50, 40));
float PlayerSpeed = 0.1;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
window.close();
break;
}
}
//###Controls ::
//If W is pressed, move upwards
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
sprite.move(sf::Vector2f(0, -PlayerSpeed));
}
//If A is pressed, move left
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
sprite.move(sf::Vector2f(-PlayerSpeed, 0));
}
//If S is pressed, move downwards
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
sprite.move(sf::Vector2f(0, PlayerSpeed));
}
//If D is pressed, move right
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
sprite.move(sf::Vector2f(PlayerSpeed, 0));
}
//If Space is pressed, set Timer to true and set Speed to 0.5
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space) && CooldownTimer == false) {
cout << "Turbo started" << endl;
Timer = true;
CooldownTimer == false;
PlayerSpeed = 0.5;
}
//If Timer = true, start a clock
if (Timer = true) {
sf::Clock ClockSpeedFunc;
}
//aafter 3 Seconds set Playerspeed back to 0.1
//Set Cooldowntimer to true and restart timer clock.
sf::Time elapsed1 = ClockSpeedFunc.getElapsedTime();
sf::Time elapsed2 = Cooldown.getElapsedTime();
if (elapsed1.asSeconds() >= 3) {
PlayerSpeed = 0.1;
cout << "Turbo ended." << endl;
ClockSpeedFunc.restart();
CooldownTimer = true;
}if (CooldownTimer == true) {
cout << "Cooldown started" << endl;
sf::Clock Cooldown;
}if (elapsed2.asSeconds() >= 10) {
cout << "Cooldown ended" << endl;
Cooldown.restart();
CooldownTimer = false;
}
//Draw everything
window.clear();
window.draw(sprite);
window.display();
}
}`
First of all make sure you do not use "using namespace". That is a bad habit. And why did you have a #include there. I did not need it.
It is not part of the problem, but I highly recommend to have a look on https://gafferongames.com/post/fix_your_timestep/ and manage your delta time.
I think I would use a class for this. But here you can see how to use it with states. I added some comments in the code so you can see what I did.
#include "SFML/Graphics.hpp"
#include <iostream>
// Define the different states of the player
enum class m_State{
POWERUP, NORMAL, COOLDOWN
};
int main(){
sf::Clock m_Clock;
// Record elapsed time of power up
float m_SecondsSincePowerUp;
// Set initial state
m_State m_State = m_State::NORMAL;
sf::RenderWindow window(sf::VideoMode(600, 600), "SFML WORK!");
sf::Texture texture;
if (!texture.loadFromFile("PlayerTexture.jpg")){
std::cout << "Error loading PlayerTexture.jpg" << std::endl;
}
sf::Sprite sprite;
sprite.setTexture(texture);
sprite.setPosition(sf::Vector2f(50, 40));
sprite.setPosition(sf::Vector2f(50, 40));
sprite.setPosition(sf::Vector2f(50, 40));
sprite.setPosition(sf::Vector2f(50, 40));
float PlayerSpeed = 0.1;
while (window.isOpen()){
sf::Time elapsedTime = m_Clock.restart();
sf::Event event;
while (window.pollEvent(event)){
switch (event.type){
case sf::Event::Closed:
window.close();
break;
}
}
//###Controls ::
//If W is pressed, move upwards
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
sprite.move(sf::Vector2f(0, -PlayerSpeed));
}
//If A is pressed, move left
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
sprite.move(sf::Vector2f(-PlayerSpeed, 0));
}
//If S is pressed, move downwards
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
sprite.move(sf::Vector2f(0, PlayerSpeed));
}
//If D is pressed, move right
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
sprite.move(sf::Vector2f(PlayerSpeed, 0));
}
//If Space is pressed, set Timer to true and set Speed to 0.5
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space) && (m_State == m_State::NORMAL)){
std::cout << "Turbo started" << std::endl;
// Set state to PowerUp
m_State = m_State::POWERUP;
PlayerSpeed = 0.5;
}
// If state is PowerUp count the seconds in a variable
if (m_State == m_State::POWERUP){
// Add elapsed time in seconds
m_SecondsSincePowerUp += elapsedTime.asSeconds();
// After 3 seconds switch the state to Cooldown
if (m_SecondsSincePowerUp > 3.0f){
std::cout << "Turbo ended." << std::endl;
m_State = m_State::COOLDOWN;
PlayerSpeed = 0.1;
}
}
// After 10 seconds switch to normal
if (m_State == m_State::COOLDOWN){
m_SecondsSincePowerUp += elapsedTime.asSeconds();
if (m_SecondsSincePowerUp > 10.0f){
std::cout << "Cooldown ended." << std::endl;
m_State = m_State::NORMAL;
m_SecondsSincePowerUp = 0;
}
}
//Draw everything
window.clear();
window.draw(sprite);
window.display();
}
}
You can use a thread to create a sleep while normal code continues to execute in unison. They are quite complex for a full explanation but look up an example and see if you think it's worth trying to implement for use with this.
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.
So I am learning C++ through game development and I recently ran across an error when I was trying to load an image called image1.png.
I tried using directories and that didn't work and then i moved the image to the same directory as the .cpp file and it still doesn't load the texture.
// defining libraries
#include <SFML/Graphics.hpp>
#include<iostream>
//global variables, functions, and classes
int main () {
//SETUPS
sf::RenderWindow window(sf::VideoMode(800, 600),"SFML Game");
window.setFramerateLimit(60);
window.setKeyRepeatEnabled(false);
bool play = true;
sf::Event event;
bool aPressed = false;
bool aReleased = false;
bool leftClick = false;
bool space = false;
bool returnReleased = false;
bool rightClick = false;
int numberOfClicks = 0;
int mouseX, mouseY;
int rectX = 0;
int rectY = 0;
sf::Texture image1;
if (image1.loadFromFile("image1.png") == -1) {
return 1;
}
sf::RectangleShape rect;
rect.setSize(sf::Vector2f(100, 50));
rect.setPosition(0, 0);
rect.setTexture(&image1);
sf::CircleShape circle;
circle.setRadius(50);
circle.setPosition(50,50);
circle.setFillColor(sf::Color::Magenta);
//Game Loop
while (play == true) {
//EVENTS
while (window.pollEvent(event)) {
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::A) {
aPressed = true;
}
if (event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::A) {
aReleased = true;
}
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) {
space = true;
}
if (event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Space) {
space = false;
}
if (event.type == sf::Event::Closed) {
play = false;
}
if (event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Escape) {
play = false;
}
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
leftClick = true;
}
if (event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Return) {
returnReleased = true;
}
if (event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Right){
rightClick = true;
}
}
//LOGIC
if (aPressed == true) {
std::cout << "Key has been pressed\n";
aPressed = false;
}
if (aReleased == true) {
std::cout << "Key has been released\n";
aReleased = false;
}
if (leftClick == true) {
numberOfClicks++;
std::cout << "Number of clicks: " << numberOfClicks << "\n";
leftClick = false;
}
if (event.type == sf::Event::MouseMoved) {
mouseX = event.mouseMove.x;
mouseY = event.mouseMove.y;
//std::cout << "X:" << mouseX << "\n";
//std::cout << "Y:" << mouseY << "\n";
}
if (returnReleased == true) {
std::cout << "Return Released \n";
returnReleased = false;
}
if (rightClick == true) {
numberOfClicks--;
std::cout << "Number of clicks: " << numberOfClicks << "\n";
rightClick = false;
}
rectX += 2;
rectY += 1;
rect.setPosition(rectX, rectY);
rect.setTexture(&image1);
//RENDERING
window.clear();
window.draw(rect);
window.draw(circle);
window.display();
}
//Clean Up
window.close();
return 0;
}
From SFML's page about image loading: http://www.sfml-dev.org/tutorials/2.0/graphics-sprite.php
The loadFromFile function sometimes fails with no obvious reason. First, check the error message printed by SFML in the standard output (check the console). If the message is „unable to open file”, make sure that the working directory (which is the directory any file path will be interpreted relatively to) is what you think it is: when you run the application from the explorer, the working directory is the executable folder, but when you launch your program from your IDE (Visual Studio, Code::Blocks, ...) the working directory is sometimes set to the project directory instead. This can generally be changed easily in the project settings.
Please check the error messages and post the error message.