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

Chapter 5

When we are drawing this screen, we can assume that the game has been already drawn. The backgroundShape rectangle fits the whole screen as a way to darken what we see on the background. If we wanted an opaque screen and cease to see the game we could simply set the fill color of backgroundShape with full alpha (255).

On the event handling topic, we simply define PauseState to pop it again and return to game if Escape is pressed again. Besides that, we also return to the main menu when Backspace is pressed:

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

{

requestStateClear();

requestStackPush(States::Menu);

}

So, why call requestStateClear() instead of requestStatePop()? Easy! The

PauseState class has no idea how many states are lying underneath it in the stack.

Even though usually there will be only GameState living under it, this may not be a truth quite easily. GameState might have pushed other game play states on its top, like tutorial states or information displayers.

Therefore, to be safe, we request a complete clearing of the stack and only then a push of the main menu.

The last thing that is very important to notice about PauseState is the return false; statement in the end of handleEvent() and update() functions.

If you were paying close attention earlier this chapter, it will be obvious to you what those mean in this context; nevertheless, returning false in those functions works as a smooth trick to automatically pause our GameState. Because PauseState is the top screen and it doesn't let any underlying states update or handle events, all those are inherently paused by absence of input or discrete time updates.

For convenience, we could have a pause method in the GameState class but we don't even need it thanks to the state system!

The loading screen – sample

While our example game does not use a loading screen up to this point, we have decided to provide a possible implementation of such a state. You can find its source code together with the sources of this chapter, as well as guide yourself through the following paragraphs into understanding it.

[ 129 ]

www.it-ebooks.info

Diverting the Game Flow – State Stack

A loading screen is a state like any other, except for one thing; it performs a task in the background, using a parallel thread of execution. Using threads and understanding them in full is out of the scope of this book; however, SFML does

provide sf::Thread, a cross-platform implementation for launching and managing multiple branches of execution in a program. Because of this, we will briefly introduce the use of sf::Thread and apply it directly into our loading screen.

But why do we need to use threads? Simply because a loading screen will most often be passing a number of resources from the hard drive into memory and this will be a lengthy process, and even worse, a blocking process.

We need to ensure that our state remains fluid in its execution, that all calls are finished as fast as they can, and the game has a solid frame rate. Having our loading screen stuck in a method loading a huge list of resources would defeat this purpose, as while a resource loading operation is being executed, the state couldn't display

a smooth progress bar. Due to this issue, we let the loading operation happen in a parallel thread, while the loading state keeps running without interruption!

In order to implement such a state we create two classes, LoadingState and ParallelTask. LoadingState is responsible for displaying information of what is being loaded and a progress bar so the user has some perception of how much time is left to begin playing. The ParallelTask class will manage the actual loading operation and give some feedback to the LoadingState class.

Please note that while these two classes are not integrated in the chapter's sample application, you can find their sources in LoadingState.hpp, LoadingState.cpp,

ParallelTask.hpp, and ParallelTask.cpp in the source directory of the chapter.

Progress bar

To better understand the implementation of LoadingState which is not that different from the other screens, lets take a look at its members:

sf::Text

mLoadingText;

sf::RectangleShape

mProgressBarBackground;

sf::RectangleShape

mProgressBar;

ParallelTask

mLoadingTask;

We have sf::Text to display our Loading Resources string, two sf::RectangleShape objects for the progress bar background and fill, and a

ParallelTask object.

[ 130 ]

www.it-ebooks.info

Chapter 5

First things first, constructing the objects happens as follows:

mLoadingText.setFont(font); mLoadingText.setString("Loading Resources"); centerOrigin(mLoadingText);

mLoadingText.setPosition(window.getSize().x / 2u, window.getSize().y / 2u + 50);

mProgressBarBackground.setFillColor(sf::Color::White); mProgressBarBackground.setSize(sf::Vector2f(window.getSize().x - 20, 10));

mProgressBarBackground.setPosition(10, mLoadingText.getPosition().y + 40);

mProgressBar.setFillColor(sf::Color(100,100,100)); mProgressBar.setSize(sf::Vector2f(200, 10)); mProgressBar.setPosition(10, mLoadingText.getPosition().y + 40);

setCompletion(0.f);

mLoadingTask.execute();

The mLoadingText function is configured with position, font, and string. Then, the background of the progress bar is initialized with a white color and a size that fits the window horizontally except for a 20 pixel wide margin, split between each side.

Both mProgressBar and mProgressBarBackground are at the exact same position, so that mProgressBar can grow inside the background correctly. The progress bar is set with a grey color, so it can be seen over its background.

To finalize, we simply ensure the progress bar is at 0 percent completion, with a width of 100 pixels and then launch the parallel task.

The setCompletion() method is nothing more than the following:

void LoadingState::setCompletion(float percent)

{

if (percent > 1.f)

percent = 1.f; // clamp

mProgressBar.setSize(sf::Vector2f( mProgressBarBackground.getSize().x * percent, mProgressBar.getSize().y));

}

[ 131 ]

www.it-ebooks.info

Diverting the Game Flow – State Stack

It merely resets the width of the progress bar fill color to a percent of the background width, as you can see.

This is enough to provide us a static progress bar, while a parallel task is already executing in the background; now it is important to go fetch data from the task to update the state:

bool LoadingState::update(sf::Time)

{

// Update the progress bar from the remote task or finish it if (mLoadingTask.isFinished())

{

requestStackPop();

requestStackPush(States::Game);

}

else

{

setCompletion(mLoadingTask.getCompletion());

}

return true;

}

This method's body is just as simple as it looks, if the parallel task has finished already, it is time to spawn the game state, because in theory it already has the needed resources to run. Otherwise, if the task is still executing, we will only update the progress bar.

ParallelTask

So far we have been able to see that a ParallelTask object runs in the background and allows querying some information about the task's progress.

To remain as simple as possible explaining the concept of a task executed in a parallel thread, we decided to implement the sample class as a dummy operation that does not do any actual loading, but rather just waits ten seconds for a timer to expire and finalize the task.

But, before explaining our implementation, let's approach a couple of concepts rapidly.

[ 132 ]

www.it-ebooks.info

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