Launching a new window in SFML (C++) - c++

This semester we have to make a game in C++. As a junior in game development in C++ I choosed SFML for graphics (Is that a good choice ? ). All started well, I made my menu and my button and so on. But when I click on this button my window is just closed. And I want to lauch a new window. Anyone can help me ?
Thanks.
#include <iostream>
#include <SFML/Graphics.hpp>
#include "Button.h"
#include "game.h"
using namespace std;
int main() {
sf::RenderWindow window;
sf::Color Color;
sf::Vector2i centerWindow((sf::VideoMode::getDesktopMode().width / 2) - 445, (sf::VideoMode::getDesktopMode().height / 2) - 480);
window.create(sf::VideoMode(900, 900), "SFML Textbox", sf::Style::Titlebar | sf::Style::Close);
window.setPosition(centerWindow);
window.setKeyRepeatEnabled(true);
sf::Font font;
if (!font.loadFromFile("font.ttf"))
std::cout << "Font not found!\n";
//Création de l'image
sf::Texture texture[1];
texture[0].loadFromFile("logo.jpg");
sf::RectangleShape rectangle;
sf::Sprite sprite[1];
rectangle.setSize(sf::Vector2f(750,182));
sprite[0].setTexture(texture[0]);
sprite[0].setPosition(100,50);
//Création du texte
sf::Text text;
text.setFont(font);
text.setCharacterSize(20);
text.setColor(sf::Color(200,0,0));
text.setString("~Made by Théo Manea - 2019/2020 Paris-Sud University~");
text.setStyle(sf::Text::Bold);
text.setPosition(300,850);
//Création du bouton
Button btn1("Jouer", { 200, 100 }, 30, sf::Color::Green, sf::Color::White);
btn1.setFont(font);
btn1.setPosition({ 350, 300 });
//Main Loop:
while (window.isOpen()) {
sf::Event Event;
//Event Loop:
while (window.pollEvent(Event)) {
switch (Event.type) {
case sf::Event::Closed:
window.close();
case sf::Event::MouseMoved:
if (btn1.isMouseOver(window)) {
btn1.setBackColor(sf::Color(200,0,0));
}
else {
btn1.setBackColor(sf::Color(6,164,154));
}
break;
case sf::Event::MouseButtonPressed:
if (btn1.isMouseOver(window)) {
Squadro squadro;
window.close();
}
}
}
window.clear(sf::Color::White);
btn1.drawTo(window);
window.draw(rectangle);
window.draw(sprite[0]);
window.draw(text);
window.display();
}
}
And my game.h :
'''
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
class Squadro{
private:
public:
void Test();
void MainFunctions();
};
void Squadro::Test()
{
cout << "okkkkkkkkkkkkkkkkkkkk" << endl;
}
void Squadro::MainFunctions()
{
sf::Window window(sf::VideoMode(800, 600), "My window");
// 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))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
}
}
#endif // GAME_H_INCLUDED
'''
N.B : I know it's maybe a dumbie question but I need help ! Thanks :D

In general, SFML can be an as good choice for graphics library as can be SDL, Allegro, etc. you just have to use it right (yes, that's the hard part, I know. :)) But that's really subjective, so off-topic here. Let's get to your issue…
The problem is this part:
if (btn1.isMouseOver(window)) { // This is true, if the cursor is over the button
Squadro squadro; // Here you create an object of the other class that shows its own window
window.close(); // now you close the "main" window
} // once you reach this line, "squadro" is destroyed as well, since we're leaving the scope ({...}) it's defined in.
Can this be fixed? Of course. All you have to do is ensure that your Squadro object doesn't get destroyed immediately (plus the outer program code has to ensure it keeps running/updating the Squadro code as well. This can get a bit tricky, so in general I'd recommend sticking to one window only.
Here's the structure I'd use:
For your simple game you should first of all look into two basic concepts:
Main Loop: Have your program run within one main loop (i.e. "while the window is open and the game is running, repeat this"), within which you first process events (such as mouse movement or keyboard presses) and then you update your game and finally draw it.
Finite State Machine: Which allows your game to have different screens or states (but it can also be used for more basic elements such as buttons, enemies, objects, levels, etc.).
A website (and book!) I'd absolutely recommend is Game Programming Patterns. It might be a bit tricky to understand everything at once as a starter, but this website will explain you most important concepts that can make developing your game (of any scale) significantly easier. Just keep in mind the best or most complex approach might be overkill based on the scope and size of your game.
If you want to know more about finite state machines, definitely have a look at their section about it.
Without going too much into details, here's a basic template for a main Game class one might use with SFML (code is simplified/condensed; this is basically what you have already:
class Game {
private:
sf::RenderWindow mWindow;
public:
Game() {
mWindow.create({640, 480}, "My Game");
// Other initialization code
}
~Game() {
// Code to shutdown the game
}
// This is your main game loop
int run() {
while (mWindow.isOpen()) {
handleEvents();
updateGame();
drawGame();
}
return 0;
}
private:
handleEvents() {
// Event handling as you do already
}
updateGame() {
// Update the game
}
drawGame() {
// Draw the game
}
}
In your program's main() you now just have to create an object of the Game class and tell it to run:
int main(int argc, char **argv) {
Game myGame;
return myGame.run();
}
Now to the actual finite state machine. There are many different approaches to this, but the most basic one is just using one variable and an enumeration to identify the current state of the game. Add both to the class:
```cpp
enum GameState {
TitleScreen = 0,
MainGame,
GameOver
} mCurrentState;```
When initializing the game, you set a default state:
```cpp
mCurrentState = TitleScreen;
And now, if you want to switch to a different screen, all you have to do is update this variable, e.g. when the player clicks on a "Start" button:
mCurrentState = MainGame;
The three functions from your main loop, handling events, updating the game, and drawing everything, can then use this variable to determine what to do:
drawGame() {
switch (mCurrentState) {
case TitleScreen:
// Draw the title screen here
break;
case MainGame:
// Draw the actual game here
break;
case GameOver:
// Draw the game over screen here
break;
}
}
In a very similar way, you can give your button it's own internal state as well:
enum ButtonState {
Idle = 0,
Hovered,
Pushed
} mCurrentState;```

Related

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.

Can't load image with SFML

Am trying to load an image with SFML using Xcode, but everytime I run the program, the window (which has been created using the code) flashes and disappears...
Here's the code I am using:
#include <SFML/Graphics.hpp>
#include <iostream>
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 1024
int main()
{
sf::RenderWindow window(sf::VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT), "Orsome Game");
while(window.isOpen())
{
sf::Event e;
while(window.pollEvent(e))
{
switch (e.type)
{
case sf::Event::Closed:
window.close();
break;
}
}
sf::Image image;
if(!image.loadFromFile("sprite.png")){
return -1;
}
window.clear(sf::Color(255,255,255));
window.display();
}
return EXIT_SUCCESS;
}
Have also put the image file where the c++ file is, but it still doesn't work!
I would put an sf::Style::Default in the RenderWindow arguments, straight after "Orsome Game" window name. Because you are using the pollEvent, that would allow you to exit the window by pressing the x button in the top right corner, like a default application layout.
Is the picture in the same directory as your solution file? Or your main.cpp?
It should be, of course.
And, maybe, try loading your image with Texture and Sprite, like this:
sf::Texture texture;
texture.loadFromFile("picturename.png");
sf::Sprite sprite;
sprite.setTexture(texture);
inside the while window is open loop.
To draw it:
// after window.clear() ...
//... your code
window.draw(sprite);
//... other things to draw
// and then, your window.display();
But, probably, your sf::Image should also work. Tell me how it goes
EDIT:
Try this code and see if the window opens.
Otherwise, that might be the problem of setting up the SFML on your computer and you will have to find some good tutorial on how to set it up properly! But let's see:
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
int main()
{
RenderWindow window(VideoMode(640, 640), "Test", Style::Default);
while (window.isOpen()) {
Event _event;
while (window.pollEvent(_event)) {
switch (_event.type) {
case Event::Closed:
window.close();
break;
}
}
window.clear();
// draw
// ...
window.display();
}
return 0;
}

Developing SFML framework

I created an exemple in which i have 2 windows opened at the same time and window1 cant handle events while window2 is open. I changed the current window's color to ilustrate that its working(while window1 is open if i move the mouse, window2 gets greener and greener). But even though window1 cant handle events while window 2 is open, i cant still change window1 position. I want to be unable to do that.
#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
using namespace std;
sf::Event event;
int main()
{
sf::RenderWindow window1(sf::VideoMode(600, 600), "Window1");
sf::RenderWindow window2(sf::VideoMode(300, 300), "Window2");
int r=0,g=0;
while (window1.isOpen())
{
if(window2.isOpen()==false)
while (window1.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window1.close();
r=(r+1)%255;
}
else
{
while (window2.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window2.close();
g=(g+1)%255;
}
}
window1.clear(sf::Color(r,0,0));
window1.display();
window2.clear(sf::Color(0,g,0));
window2.display();
}
return 0;
}
How do i do that?
There isn't direct functionality in SFML for this (although I expect it's possible using platform specific code), but there are a couple of work arounds:
Change the window style to sf::Style::None. This is quick and easy, but has the effect of removing the title bar and window border, which you may not want.
Brute force the window position, either by manually setting the position each render, or checking for a position change and reversing it.

C++ sfml receives close event just after window opens

I am trying to follow a SFML tutorial from this link, however, for some reason my application seems to be caling the close event as soon as my program enters into the event loop.
Here is my code.
#include <SFML/Graphics.hpp>
#include <iostream>
// Here is a small helper for you ! Have a look.
#include "ResourcePath.hpp"
int main()
{
sf::RenderWindow Window(sf::VideoMode(500,400),"SFML tutorial");
/* Or we can do this
* sf::RenderWindow Window
* Window.create (sf::VideoMode(800,600),"SFML tutorial");
*/
//Game loop
while(Window.isOpen())
{
sf::Event Event;
while(Window.pollEvent(Event));
{
if(Event.type == sf::Event::Closed)
{
Window.close();
std::cout << "Close" << std::endl;
}
}
}
return 0;
}
For some reason as soon as my program enters the event loop it receives a sf::Event::Closed event. I have done some research and this is not because the window is too big for my screen.
To fix my issue I have had to ad a int variable canClose to 0 then modify the event loop to this.
if(Event.type == sf::Event::Closed)
{
if(canClose == 1)
{
Window.close();
} else {
canClose = 1;
}
}
After I do this the window now opens and runs as expected.
P.S this is made using xcode and the SFML template.
Edit:
Just made a new xcode SFML project and removed some code in it to make a empty window and it seems to whork. Code looks exactly the same. This seams strange because it is exactly the same code.
From what i have seen, do not use an if statement for checking events, use a switch statement. Also Use a while(window.isOpen()) when trying to poll events
Have you read through the tutorials on http://www.sfml-dev.org ? Because i can guarantee that it is the best source for learning sfml. Use it before using another source.
Your problem is that you declared the variable Event Event type, you have to change the name of the variable to lowercase.
in this way
#include <SFML/Graphics.hpp>
#include <iostream>
// Here is a small helper for you ! Have a look.
#include "ResourcePath.hpp"
int main()
{
sf::RenderWindow Window(sf::VideoMode(500,400),"SFML tutorial");
/* Or we can do this
* sf::RenderWindow Window
* Window.create (sf::VideoMode(800,600),"SFML tutorial");
*/
//Game loop
while(Window.isOpen())
{
sf::Event event;
while(Window.pollEvent(event));
{
if(event.type == sf::Event::Closed)
{
Window.close();
std::cout << "Close" << std::endl;
}
}
}
return 0;
that way you will not have any problems

SFML textEntered not working properly

so today I started looking into SFML and I found it quite interesting so decided to learn how to play with it, but I am already hitting some problems, I am trying to use textEntered event, but it is not working properly, it shows complete nonsense and text writes itself even without me pressing any key. Heres link
Code
#include <SFML/Graphics.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(400, 400), "SFML works!");
std::string display;
sf::Font font;
font.loadFromFile("arial.ttf");
sf::Text text;
text.setFont(font);
text.setCharacterSize(30);
text.setStyle(sf::Text::Bold);
text.setColor(sf::Color::Red);
text.setPosition(50, 50);
while (window.isOpen())
{
sf::Event Revent;
while (window.pollEvent(Revent))
{
if (sf::Event::TextEntered)
{
std::cout << static_cast<char>(Revent.text.unicode);
//text.setString(display);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
window.close();
}
window.clear();
//window.draw(text);
window.display();
}
return 0;
}
You wrote if (sf::Event::TextEntered), which evaluates to true (since it's not equal to 0).
You probably meant
if (Revent.type == sf::Event::TextEntered).
Using Revent.text is undefined behavior in this case (when you're not sure what type of event Revent contains) because sf::Event is an union, so only one of its members is usable at a time. You can read more about SFML events here.