【问题标题】:Launching a new window in SFML (C++)在 SFML (C++) 中启动新窗口
【发布时间】:2019-11-18 21:15:11
【问题描述】:

这个学期我们必须用 C++ 制作一个游戏。作为 C++ 游戏开发的大三学生,我为图形选择了 SFML(这是一个不错的选择吗?)。一切开始都很好,我制作了菜单和按钮等等。但是当我点击这个按钮时,我的窗口刚刚关闭。我想启动一个新窗口。任何人都可以帮助我吗?

谢谢。

#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

'''

注:我知道这可能是一个愚蠢的问题,但我需要帮助!谢谢:D

【问题讨论】:

  • 还有一个很好的实践方法:为所有类和变量使用英文名称。这样,即使他们不会说您的语言(意大利语?),其他人也可以更轻松地阅读和理解您的代码。

标签: c++ sfml


【解决方案1】:

一般来说,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 对象不会立即被破坏(加上外部程序代码必须确保它继续运行/更新 Squadro 代码。这可能会有点棘手,所以在一般情况下,我建议只使用一个窗口。


这是我要使用的结构:

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

  • 主循环:让您的程序在一个主循环中运行(即“当窗口打开并且游戏正在运行时,重复此操作”),您首先在其中处理事件(例如鼠标移动或键盘按下),然后您更新您的游戏并最终绘制它。
  • 有限状态机:它允许您的游戏拥有不同的屏幕或状态(但它也可以用于更基本的元素,例如按钮、敌人、对象、关卡等)。

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

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


无需过多介绍,这里是一个基本的Game 类的基本模板,可以与 SFML 一起使用(代码被简化/压缩;这基本上是你已经拥有的:

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 类的对象并告诉它运行:

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;

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

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

【讨论】:

  • 中肯的建议,尽管我怀疑初学者能否从固态机中获益良多。无论哪种方式,OP都会从研究这个答案中获益良多。
  • @laancelot 我同意,这可能很棘手。因此,我选择了简化的开关版本,而不是使用自定义类和/或堆栈等。
  • 哇非常感谢马里奥!幸运的是,像你这样的人存在 :D 所以如果我理解制作一个新窗口可能会非常棘手。我在这里尝试使用此方法,因为我在 Tkinter 中用 Python 制作了几个 GUI(并且效果很好!)。再次感谢您在我的问题上花费的时间。今晚我会试试你的解决方案。最好的问候。
  • @ThéoExagon 不要忘记通过选中投票附近的复选框来接受马里奥的回答(如果你愿意,你也可以投票给他)。
猜你喜欢
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 2013-02-01
  • 1970-01-01
  • 2013-12-11
  • 2012-01-31
  • 1970-01-01
相关资源
最近更新 更多