Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SFML Game Development.pdf
Скачиваний:
194
Добавлен:
28.03.2016
Размер:
4.19 Mб
Скачать

Chapter 5

Navigating between states

So far we have our state machine in place and running smoothly, the title screen starts up the program, but how to make the title screen call another state to its place when someone hits a key?

That is exactly what the StateStack class's delayed push and pop mechanism is for. Inside a state handleEvent() and update(), you are given three methods to control the execution and transitions of states: requestStackPush(), requestStackPop(),

and requestStackClear().

It is appropriate to use these methods to request new states to be pushed, or to show and replace the current one, as you will verify that our example states do throughout this chapter.

Creating the game state

So far we have covered the theory and practice for inserting the state stack into our sample game. It is fully functional but yet empty, so, it is finally time to create our first state, the game state.

For this, we create a class named GameState and we proceed to relocate the code that could be found in the Game class related to the actual aircraft gameplay to its new home:

class GameState : public State

{

public:

 

GameState(StateStack& stack,

 

Context context);

virtual void

draw();

virtual bool

update(sf::Time dt);

virtual bool

handleEvent(const sf::Event& event);

private:

 

World

mWorld;

Player&

mPlayer;

};

 

[ 123 ]

www.it-ebooks.info

Diverting the Game Flow – State Stack

The title screen

Because a good place to start is always the beginning, we are about to create the title screen; that initial screen you sometimes see in games. Before you enter the main menu of the game, it asks you to press any key.

We decided to go with the name TitleState, and define it as follows:

class TitleState : public State

{

public:

 

TitleState(StateStack& stack,

 

Context context);

virtual void

draw();

virtual bool

update(sf::Time dt);

virtual bool

handleEvent(const sf::Event& event);

private:

 

sf::Sprite

mBackgroundSprite;

sf::Text

mText;

bool

mShowText;

sf::Time

mTextEffectTime;

};

 

Our implementation of this screen is not very different from what you are used to see. It shows a background with a little information about the game, besides its title and then blinks a big old Press any key to continue message.

Here's how we detect the key stroke and use our state system to trigger a new state:

bool TitleState::handleEvent(const sf::Event& event)

{

if (event.type == sf::Event::KeyPressed)

{

requestStackPop();

requestStackPush(States::Menu);

}

return true;

}

[ 124 ]

www.it-ebooks.info

Chapter 5

The background is merely an image covering the whole window and the blinking effect on the sf::Text object is achieved through this little trick:

bool TitleState::update(sf::Time dt)

{

mTextEffectTime += dt;

if (mTextEffectTime >= sf::seconds(0.5f))

{

mShowText = !mShowText; mTextEffectTime = sf::Time::Zero;

}

return true;

}

The magic happening here is simple. The variable mShowText determines the visibility of the sf::Text object, so we toggle it every half second, achieving the blinking effect.

Every time the state updates, we have a time counter mTextEffectTime that increments with the elapsed time. Then, when that elapsed time is greater than half a second, we just toggle the mShowText variable and restart the counter.

Main menu

Okay, our title screen just finished, the user pressed a key and it is time to launch another screen, the famous main menu!

This is probably the most common state you will find in virtually every game, it is responsible for presenting the user its options and what can be done with the game. This is usually the point where you change settings, start or continue your game, watch videos and artwork, or simply exit the game.

For simplicity, we created the most basic main menu possible. It only presents two options: play and exit. Then, you can select which one you want by pressing the return key or alternate between the options with the up and down arrow keys.

Please notice this is a basic form of graphical user interface, which is the topic in the next chapter, therefore you can expect interesting improvements to it when we introduce the user interfaces in more depth!

[ 125 ]

www.it-ebooks.info

Diverting the Game Flow – State Stack

This state is not so different from the title screen but it does implement the option selection, and here is how we did it:

enum OptionNames

{

Play,

Exit,

};

 

std::vector<sf::Text>

mOptions;

std::size_t

mOptionIndex;

First we declare the containers of our options in the MenuState class, as well as the enumerator of the available options.

Then, we setup and push to the mOptions array the sf::Text objects, in the constructor, as follows:

sf::Text playOption; playOption.setFont(font); playOption.setString("Play"); centerOrigin(playOption);

playOption.setPosition(context.window->getView().getSize() / 2.f); mOptions.push_back(playOption);

The mOptionIndex integer variable is present so that we can track which is the currently selected option between all those in the mOptions array; it will have a value between 0 and n-1, n being the number of options in the menu, which is two in our example.

Finally, we define the most important function that helps controlling this menu:

void MenuState::updateOptionText()

{

if (mOptions.empty()) return;

//White all texts FOREACH(sf::Text& text, mOptions)

text.setColor(sf::Color::White);

//Red the selected text mOptions[mOptionIndex].setColor(sf::Color::Red);

}

[ 126 ]

www.it-ebooks.info

Chapter 5

This function is called once after constructing mOptions and again every time the mOptionIndex value changes. It ensures that only the selected option is highlighted in red, and the remaining is in white.

About what makes the mOptionIndex value actually change, it is merely simple handling of key presses in the handleEvent() function:

if (event.key.code == sf::Keyboard::Up)

{

if (mOptionIndex > 0) mOptionIndex--;

else

mOptionIndex = mOptions.size() - 1;

updateOptionText();

}

else if (event.key.code == sf::Keyboard::Down)

{

if (mOptionIndex < mOptions.size() - 1) mOptionIndex++;

else

mOptionIndex = 0;

updateOptionText();

}

Now that we handled the selection of an action between multiple options, it is time to actually make them push their own states and give the game continuity:

if (event.key.code == sf::Keyboard::Return)

{

if (mOptionIndex == Play)

{

requestStackPop();

requestStackPush(States::Game);

}

else if (mOptionIndex == Exit)

{

requestStackPop();

}

}

[ 127 ]

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]