Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Changing music when Game State changes  (Read 9806 times)

0 Members and 1 Guest are viewing this topic.

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Changing music when Game State changes
« on: August 15, 2013, 07:35:01 pm »
Hello... I am creating a tiny game with four game states... Menu, Intro, Play, Game Over. Each has its own unique music. The states are given within a switch case condition and the GUI and gameplay part of the switching of game states works perfectly fine. My question is how do I do that with music in such a way that music also changes when game state changes? The game state switching is defined in the while(window.isOpen()) loop. Playing the music within the loop won't work, naturally. How do I do it so that music changes when game state changes? Please tell me. Thank you.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Changing music when Game State changes
« Reply #1 on: August 15, 2013, 07:38:16 pm »
Well, it seems like it'd be extremely simple: whatever part of your code changes the state in the first place should be responsible for changing the music as well.

If you want a real answer you'll have to post complete and minimal code for us to look at.

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #2 on: August 15, 2013, 08:00:31 pm »
I get what you mean. I tried putting the music in a switch condition as well. But that didn't change when the game state changed. Yours WAS a real answer, but that doesn't mean I don't want more information.  ;D Here's my code.

This is outside the window.isOpen() loop:
sf::Music MenuMusic, PlayMusic;

if(!MenuMusic.openFromFile("images/menuscore.wav"))
        return EXIT_FAILURE;

if(!PlayMusic.openFromFile("images/score.wav"))
        return EXIT_FAILURE;

switch(CurrentState)
{
        case MENU:
                MenuMusic.play();
                MenuMusic.setLoop(true);
                break;
        case PLAY:
                PlayMusic.play();
                PlayMusic.setLoop(true);
}

This is within the window loop, where (I think) music can't be played:
switch(CurrentState)
{
case MENU:
        Menu MainMenu;
        MainMenu.Show(window, menu, play, quit, CurrentState);
        break;

case PLAY:
        Play PlayGame;
        PlayGame.Show(window, player, background, enemy, CurrentState);
        break;
}

This is the minimal of it. The completeness of it is kinda messy. But this is sufficient, I think (I hope). How do I do it? Please tell me. Thanks.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Changing music when Game State changes
« Reply #3 on: August 15, 2013, 08:12:30 pm »
It seems like you're calling .play() every single loop, which seems like it would be constantly restarting the music from the beginning every single frame.

Incidentally, when say "complete and minimal" code, the complete part is important too. We want to be able to compile it ourselves so we can actually find the problem instead of blindly guessing based on your description (which probably doesn't include the problem since the whole reason you're here is because you don't know what's causing it).

In particular, where's the code that changes the game state? As I said in my last post that's probably where the music switching code should go.

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #4 on: August 15, 2013, 08:51:15 pm »
I don't get you. Isn't the switch case inside the window loop where the game state changes? OK... Here's the complete and minimal code.

HEADERS.H:
#pragma once
#include<iostream>
#include<math.h>
#include<ctype.h>
#include<SFML/Audio.hpp>
#include<SFML/Graphics.hpp>
#include<SFML/Network.hpp>
#include<SFML/System.hpp>
#include<SFML/Window.hpp>
#include<list>
#include<string>

enum GameStates{MENU, INTRO, PLAY, GAMEOVER};

MENU.H:
#include "headers.h"

class Menu
{
public:
        int Show(sf::RenderWindow &window, sf::Sprite &menu, sf::Sprite &play, sf::Sprite &quit, GameStates &CurrentState);
};

MENU.CPP:
#include "menu.h"

int Menu::Show(sf::RenderWindow &window, sf::Sprite &menu, sf::Sprite &play, sf::Sprite &quit, GameStates &CurrentState)
{
        if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
        {
                sf::FloatRect BoundsOfPlay = play.getGlobalBounds();
                sf::FloatRect BoundsOfExit = quit.getGlobalBounds();

                float mouseX = (float)sf::Mouse::getPosition(window).x;
                float mouseY = (float)sf::Mouse::getPosition(window).y;

                if(BoundsOfPlay.contains(mouseX,mouseY))
                        CurrentState = PLAY;

                if(BoundsOfExit.contains(mouseX, mouseY))
                        window.close();
        }
       
        window.draw(menu);
        window.draw(play);
        window.draw(quit);

        return EXIT_SUCCESS;
}

PLAY.H:
#include "headers.h"

class Play
{
public:
        int Show(sf::RenderWindow &window, sf::Sprite &menu, sf::Sprite &background, sf::Sprite &player, GameStates &CurrentState);
};

PLAY.CPP:
#include "play.h"

int Play::Show(sf::RenderWindow &window, sf::Sprite &menu, sf::Sprite &background, sf::Sprite &player, GameStates &CurrentState)
{
        window.draw(background);
        window.draw(player);
        return EXIT_SUCCESS;
}

MAIN.CPP:
#include "menu.h"
#include "player.h"

int main()
{
        // Initializing a Game State
        GameStates CurrentState;

        // Setting the Current Game State
        CurrentState = MENU;

        // Creating a Window
        sf::VideoMode resolution;
        sf::RenderWindow window(resolution.getDesktopMode(), "Game");

        // Initializing Textures
        sf::Texture playertex, backgroundtex, enemytex, menutex, playtex, quittex;

        // Initializing Sprites
        sf::Sprite player, background, menu, play, quit;

        // Loading Menu Background Texture
        if(!menutex.loadFromFile("images/menu.png"))
                return EXIT_FAILURE;
       
        // Setting Menu Background Texture to Menu Background Sprite
        menu.setTexture(menutex);
        menutex.setSmooth(true);

        // Getting Bounding Box of the Menu Background Sprite
        sf::FloatRect menubounds = menu.getGlobalBounds();

        // Initializing Menu Background Orientation
        menu.setOrigin(menubounds.width/2, menubounds.height/2);
        menu.setScale(resolution.getDesktopMode().width/menubounds.width, resolution.getDesktopMode().width/menubounds.width);
        menu.setPosition((float)resolution.getDesktopMode().width/2, (float)resolution.getDesktopMode().height/2);

        // Loading Play Button Texture
        if(!playtex.loadFromFile("images/play.png"))
                return EXIT_FAILURE;

        // Setting Play Button Texture to Play Button Sprite
        play.setTexture(playtex);

        // Getting Bounding Box of the Play Button Sprite
        sf::FloatRect playbounds = play.getGlobalBounds();

        // Initializing Play Button Orientation
        play.setOrigin(playbounds.width/2, playbounds.height/2);
        play.setPosition(resolution.getDesktopMode().width/2 - playbounds.width, resolution.getDesktopMode().height/2 + playbounds.height*2);

        // Loading Exit Button Texture
        if(!quittex.loadFromFile("images/quit.png"))
                return EXIT_FAILURE;

        // Setting Exit Button Texture to Exit Button Sprite
        quit.setTexture(quittex);

        // Getting Bounding Box of the Exit Button Sprite
        sf::FloatRect exitbounds = quit.getGlobalBounds();

        // Initializing Exit Button Orientation
        quit.setOrigin(exitbounds.width/2, exitbounds.height/2);
        quit.setPosition(resolution.getDesktopMode().width/2 + exitbounds.width, resolution.getDesktopMode().height/2 + exitbounds.height*2);

        // Loading Player Texture
        if(!playertex.loadFromFile("images/ship.png"))
                return EXIT_FAILURE;

        // Setting Player Texture to Player Sprite
        player.setTexture(playertex);

        // Getting Bounding Box of the Player Sprite
        sf::FloatRect playerbounds = player.getGlobalBounds();

        // Initializing Player Orientation
        player.setOrigin(playerbounds.width/2, playerbounds.height/2);
        player.setPosition((float)resolution.getDesktopMode().width/2, (float)(resolution.getDesktopMode().height - playerbounds.height/2));

        // Loading Play Background Texture
        if(!backgroundtex.loadFromFile("images/space.jpg"))
                return EXIT_FAILURE;

        // Setting Play Background Texture to Play Background Sprite
        background.setTexture(backgroundtex);

        // Getting Bounding Box of the Play Background Sprite
        sf::FloatRect border = background.getGlobalBounds();

        // Initializing Play Background Orientation
        background.setOrigin(border.width/2, border.height/2);
        background.setScale(resolution.getDesktopMode().width/border.width, resolution.getDesktopMode().height/border.height);
        background.setPosition((float)resolution.getDesktopMode().width/2, (float)resolution.getDesktopMode().height/2);

        sf::Music MenuMusic, PlayMusic;

        if(!MenuMusic.openFromFile("images/menuscore.wav"))
                return EXIT_FAILURE;

        if(!PlayMusic.openFromFile("images/score.wav"))
                return EXIT_FAILURE;

        switch(CurrentState)
        {
                case MENU:
                        MenuMusic.play();
                        MenuMusic.setLoop(true);
                        break;
                case PLAY:
                        PlayMusic.play();
                        PlayMusic.setLoop(true);
        }

        while(window.isOpen())
        {              
                float timer = clock.restart().asSeconds();

                sf::Event event;
               
                while(window.pollEvent(event))
                {
                        if(event.type == sf::Event::Closed)
                                window.close();
                       
                        if(event.key.code == sf::Keyboard::Escape)
                                window.close();
                }

                window.clear();

                switch(CurrentState)
                {
                case MENU:
                        Menu MainMenu;
                        MainMenu.Show(window, menu, play, quit, CurrentState);
                        break;

                case PLAY:
                        Play PlayGame;
                        PlayGame.Show(window, background, player, CurrentState);
                        break;
                }

                window.display();
        }
        return 0;
}

I apologize if the code is too long. And I know it is. But to just copy/paste it and test it right away, this is what I could give you. Again, apologies. Now, where might the problem be? Please tell me. Thank you.
« Last Edit: August 15, 2013, 09:00:52 pm by WDR »

OniLinkPlus

  • Hero Member
  • *****
  • Posts: 500
    • View Profile
Re: Changing music when Game State changes
« Reply #5 on: August 15, 2013, 09:17:02 pm »
If there's one thing that code is not, it's minimal. Minimal means one source file, with ALL code removed except for what is ABSOLUTELY necessary to demonstrate the problem.
I use the latest build of SFML2

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #6 on: August 15, 2013, 09:47:44 pm »
OK... I have absolutely no idea what to reply to that. If the tone of this statement conveys rudeness, my apologies, but it is not. It's confusion. One person says minimal and complete is copy-paste-execute code. Another person says minimal should only be the problematic part. If that is the case, then my second post was minimal. Anyways, anything I say at this point may offend people, which I think already happened. So... Minimal.

#include<iostream>
#include<SFML/Audio.hpp>
#include<SFML/Graphics.hpp>
#include<SFML/Network.hpp>
#include<SFML/System.hpp>
#include<SFML/Window.hpp>

int main()
{
        // Initializing a Game State
        GameStates CurrentState;

        // Setting the Current Game State
        CurrentState = MENU;

        // Creating a Window
        sf::VideoMode resolution;
        sf::RenderWindow window(resolution.getDesktopMode(), "Game", sf::Style::Fullscreen);

        sf::Music MenuMusic, PlayMusic;

        if(!MenuMusic.openFromFile("images/menuscore.wav"))
                return EXIT_FAILURE;

        if(!PlayMusic.openFromFile("images/score.wav"))
                return EXIT_FAILURE;

        switch(CurrentState)
        {
                case MENU:
                        MenuMusic.play();
                        MenuMusic.setLoop(true);
                        break;
                case PLAY:
                        PlayMusic.play();
                        PlayMusic.setLoop(true);
        }

        while(window.isOpen())
        {
                window.clear();

                switch(CurrentState)
                {
                case MENU:
                        Menu MainMenu;
                        MainMenu.Show(window, menu, play, quit, CurrentState);
                        break;

                case PLAY:
                        Play PlayGame;
                        PlayGame.Show(window, background, player, CurrentState);
                        break;
                }

                window.display();
        }
        return 0;
}

Once again... If any of that seemed impolite, my apologies. No offence intended. Confusion intended.

OniLinkPlus

  • Hero Member
  • *****
  • Posts: 500
    • View Profile
Re: Changing music when Game State changes
« Reply #7 on: August 15, 2013, 10:02:42 pm »
What? Why do you think anybody was offended? Your code was complete before, but not minimal.

Complete - You can copy, paste, and execute it with no modification.

Minimal - The only code there is is the code that relates to the problem, AND there is ideally only one source file.

So now, your code is minimal, but it is not complete. We need complete and minimal code in order to give you the best advice we can.

Anyways, your problem here is that you only tell the music to play once - in a switch statement before the while loop. Your code will never go back to that switch statement, so there is no way for the music to change to the new track. I have an idea of how to fix this, but I don't know the internals of the classes you use.
I use the latest build of SFML2

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #8 on: August 15, 2013, 10:23:55 pm »
What? Why do you think anybody was offended?

I don't know, dude! (Or, if you're a woman... ma'am!) It's late, in the middle of the night, I'm tired, I'm sloppy and cranky. I'm not able to do things properly. So, when I don't get my expected answer (even though it was my information lacking questions in the first place), I get irritated, I say something offensive, people get offended, they criticize my noobishness, they don't respond anymore. It is my need, so I gotta keep my ass shut and get my job done. And people just love to pick on noobs, so...   :-X

Anyways, back on topic... The classes I use. If you mean the two classes Menu and Play, they only have a single function Show() which draws the sprites. That's it. I can post them here, but they're already there in my previous post. Menu.h, Menu.cpp, Play.h, Play.cpp. Thanks for responding, by the way.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Changing music when Game State changes
« Reply #9 on: August 15, 2013, 10:32:20 pm »
Code: [Select]
[quote author=WDR link=topic=12659.msg88485#msg88485 date=1376592675]
I don't get you. Isn't the switch case inside the window loop where the game state changes?

The window loop is just code that gets executed as long as the window is open. Each iteration of the loop represents a frame.  The "game state" is something you've defined, which has no inherent connection to that loop.

If you define the game state as something which changes with every iteration of the isOpen loop, you're saying your game changes state every single frame.  Since your states are "play" and "menu," I'm pretty sure that's not actually what you want at all.

Now there should be a switch statement to make the appropriate draw() calls, since drawing has to happen every frame, but everything else should probably be functions outside the isOpen loop that get called when the state is supposed to change.  If the escape key opens menus, then your isOpen loop will contain an even loop checking for keypressed events, and if it sees Escape it will call switchToMenuState() (or maybe Menu.switchTo() or something), and part of that function will be setting the new music. That's the kind of thing I was suggesting.

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #10 on: August 15, 2013, 10:57:18 pm »
OK... But even if I define the functions outside, won't they be looping when they are called? Still confused.  :-\

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Changing music when Game State changes
« Reply #11 on: August 15, 2013, 11:36:26 pm »
Not if you call them when an event occurs.  You may be looping the checks for the events, but the events themselves (mouse clicks, button presses, etc) don't loop, with the exception of holding down a key to generate multiple key presses.

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #12 on: August 16, 2013, 02:47:33 pm »
OK, OK... Now I understand what you mean. But I am not able to implement it practically. It sucks not knowing stuff even after reading and practicing it so many times.  :'(

Stupid amateur teachers. Not you guys... My college teachers!  >:(

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email

WDR

  • Jr. Member
  • **
  • Posts: 82
    • View Profile
Re: Changing music when Game State changes
« Reply #14 on: August 19, 2013, 07:23:55 pm »
OK... I kinda got it figured out... Not quite... But still... Here's what I got so far.

sf::Music MenuMusic, PlayMusic;

if(!MenuMusic.openFromFile("images/menuscore.wav"))
        return EXIT_FAILURE;

if(!PlayMusic.openFromFile("images/score.wav"))
        return EXIT_FAILURE;

MenuMusic.play();
MenuMusic.setLoop(true);

while(window.isOpen())
{              
        sf::Event event;

        while(window.pollEvent(event))
        {
                if(event.type == sf::Event::Closed)
                        window.close();
                       
                if(event.key.code == sf::Keyboard::Escape)
                        window.close();

                if(event.type == sf::Event::MouseButtonPressed)
                {
                        if(CurrentState == PLAY)
                        {
                                MenuMusic.stop();
                                PlayMusic.play();
                                PlayMusic.setLoop(true);
                        }
                }
        }
}

This works! Thankfully! But... The event for changing from MENU state to PLAY state is caused by a mouse click, so it works. But the change from PLAY to GAME OVER occurs due to collision between player and enemy sprites. sf::Event::MouseButtonPressed is a pre-defined event, so that worked. Can I define my own events for other state changes? Also... One mouse click goes to PLAY state. And after going to PLAY state, if I click mouse button again, it is distorting the music. Why is that? Please help.