在 SFML (C++) 中启动一个新的 window

Launching a new window in SFML (C++)

这个学期我们要用C++做一个游戏。作为 C++ 游戏开发的大三学生,我为图形选择了 SFML(这是一个不错的选择吗?)。一切都开始顺利,我做了我的菜单和我的按钮等等。但是当我点击这个按钮时,我的 window 就被关闭了。我想发布一个新的 window。任何人都可以帮助我吗?

谢谢。

#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();
}
}

还有我的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:我知道这可能是个愚蠢的问题,但我需要帮助!谢谢 :D

一般来说,SFML 与 SDL、Allegro 等图形库一样,都是不错的选择。您只需要正确使用它(是的,我知道这是困难的部分。:))但就是这样真的很主观,所以这里离题了。让我们来解决您的问题……

问题出在这部分:

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.

这可以修复吗?当然。您所要做的就是确保您的 Squadro 对象不会立即被销毁(加上外部程序代码必须确保它也保留 running/updating Squadro 代码。这可以得到有点棘手,所以一般来说,我建议只使用一个 window。


这是我要使用的结构:

对于您的简单游戏,您应该首先了解两个基本概念:

  • 主循环:让您的程序 运行 在一个主循环中(即 "while the window is open and the game is running, repeat this"),您首先在其中处理事件(例如鼠标移动或键盘按键),然后您更新您的游戏并最终绘制它。
  • 有限状态机: 允许您的游戏具有不同的屏幕或状态(但它也可以用于更基本的元素,例如按钮、敌人、对象、关卡、等)。

我绝对推荐的网站(和书!)是 Game Programming Patterns。作为初学者,一次理解所有内容可能有点棘手,但本网站将向您解释最重要的概念,这些概念可以使您的游戏(任何规模)的开发变得更加容易。请记住,根据您游戏的范围和规模,最好或最复杂的方法可能有些矫枉过正。

如果你想了解更多关于有限状态机的知识,一定要看看their section


无需赘述太多细节,这里有一个主要 Game class 可能与 SFML 一起使用的基本模板(代码是 simplified/condensed;这基本上就是您已经拥有的模板:

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

在您的程序 main() 中,您现在只需创建 Game class 的对象并将其告诉 运行:

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;

现在,如果你想切换到不同的屏幕,你所要做的就是更新这个变量,例如当玩家点击 "Start" 按钮时:

mCurrentState = MainGame;

主循环中的三个函数,即处理事件、更新游戏和绘制所有内容,然后可以使用此变量来确定要做什么:

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

以非常相似的方式,您也可以为按钮提供它自己的内部状态:

enum ButtonState {
    Idle = 0,
    Hovered,
    Pushed
} mCurrentState;```