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:
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;```