【问题标题】:Game does not launch from Menu游戏无法从菜单启动
【发布时间】:2021-06-24 07:25:16
【问题描述】:

我是游戏开发的新手。我设法使用 C++ 和 SFML 创建了一个简单的游戏(如 Space Invaders)以及一个简单的开始菜单。 但是,在主菜单上按“Enter”后,游戏并没有启动。我如何正确链接它?我感谢您的帮助。这不是家庭作业。

main.cpp 代码

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

菜单.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];    
};

菜单.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]);
    }
}

控制台窗口将打印:

"Play button has been pressed"

但它不会继续游戏。没有其他事情发生。

【问题讨论】:

  • “不使用状态”。我几乎会自动为此使用一个状态。可能只是一个布尔值,但仍然。有什么你不想要的特殊原因吗?
  • 多态性呢?在处理项目时,我经常使用它来将菜单与游戏玩法分开。你可以有一个gameplay 类和menu 类,它们都继承了一个抽象的scene 类,具有纯虚函数,如update()render()。然后让两个场景对象始终处于活动状态,并让scene 指向其中一个场景的指针,或者让scene 指针管理当前场景的内存,可能使用std::unique_ptr。前者你会改变场景比如scene = &amp;gameplay来切换到游戏,后者你会使用scene = std::make_unique&lt;gameplay&gt;()
  • 'window': redefinition; multiple initialization 表示您在两个不同的地方制作窗口;在main.cpp 的第 15 行和第 40 行。您可以有两个窗口,它们只需要不同的变量名,或者您可以通过更改窗口大小、标题等替换第 40 行来使用相同的窗口。'sf::Text::setColor': was declared deprecated 表示此功能已从 SFML 中删除。 SFML 的文档指出“现在有填充和轮廓颜色,而不是单一的全局颜色。请改用 setFillColor()setOutlineColor()。”
  • @Lily Hi Lily,感谢您的详细解释。它确实帮助我更多地了解了 SFML。错误也已解决。目前,在主菜单上按“播放”后游戏不会启动。我认为这是我的 main.cpp 文件中的一些链接问题

标签: c++ sfml game-development


【解决方案1】:

“窗口重新定义”错误是因为您的两个 RenderWindow 对象具有相同的标识符(即窗口)。您可能想要更改第二个窗口的名称,或者更好地使用相同的窗口。

第二个错误,sf::Text::setColor() is deprecated 表示它不再“可用”或“不建议使用”。 SFML 对此有两个更好的新功能:

sf::Text::setFillColor() :设置文本的填充。

sf::Text::setOutlineColor():给你的文本一个轮廓(你还需要使用setOutlineThickness()改变粗细)。

此外,我建议您将状态机用于不同的场景,而不是两个单独的窗口。它真的没有那么难,并且会帮助你学习更多的东西。您已经通过 gameObjectManager 实现了这一点。您只需要抽象它并为您的菜单类实现它。由于您只有两个场景,您可以简单地使用整数或布尔值在这两个场景之间切换。

编辑:了解您需要对 main.cpp 文件做什么

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;

}

【讨论】:

  • 感谢您的详细解释。当然有助于澄清我的疑虑并了解有关 SFML 的更多信息。我设法解决了错误并启动并运行了主菜单。但是,它不允许我在主菜单上按 Enter(播放)后继续游戏。我认为这是 main.cpp 上的链接问题。我也更新了这个问题。谢谢。
  • 那是因为你只调用了一次更新和渲染函数,只有在按下回车键时才会在事件循环中调用。您的更新需要在事件循环之外,并且您在 'window.clear()' 和 'window.display()' 函数之间进行渲染。此外,您没有检查您处于哪个状态。是菜单吗?还是游戏?我已经更新了答案,提示您必须做什么。
  • 另外,我建议您在继续之前尝试更好地了解状态或场景。另外,了解一下游戏循环和事件的工作原理。互联网上有很多很好的资源。
  • 你能帮忙link
猜你喜欢
  • 2015-07-05
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多