Search code examples
c++sfmlgame-development

Game does not launch from Menu


I am new to Game Development. I managed to create a simple game (like Space Invaders) as well as a simple start Menu using C++ and SFML. However, upon pressing "Enter" on the main menu, the game is not being launched. How do I link it properly? I appreciate your help. This is not homework.

main.cpp codes

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

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

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

The console window would print:

"Play button has been pressed"

But it does not proceed to the game. Nothing else happens.


Solution

  • "window redefinition" error occurs because both your RenderWindow objects have the same identifiers (i.e. window). You might want to change the name of the second window or better yet use the same window.

    The second error, sf::Text::setColor() is deprecated means that it is no longer "useable" or "is not suggested to be used". SFML has two new better functions for this:

    sf::Text::setFillColor() : to set the fill of your text.

    sf::Text::setOutlineColor() : to give your text an outline (you also need to do change the thickness using setOutlineThickness()).

    Moreover, I'd suggest you to use a State Machine for different scenes instead of two separate windows. It really isn't that difficult and will help you learn a few more things. You're somewhat already achieving this with your gameObjectManager. You just need to abstract it and implement it for your menu class as well. And since you have only two scenes you can simply use an integer or boolean to switch between these two.

    EDIT: an idea of what you need to do to your main.cpp file

    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;
    

    }