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

Forge of the Gods – Shaping Our World

As a practical case, we can picture a texture that is only a square, such as a floor's tile. Using this texture with a sf::Sprite object would normally

allow us to see only one tile, no matter how big dimensions we have set with sf::Sprite::setTextureRect(). However, as soon as the texture activates its repeating mode, sf::Sprite would now render a nice tiled floor, without any extra effort!

Composing our world

Up to now, we have taken a look at entities and the scene graph, we know how to render and update objects in the world, and we have seen how views and scrolling work. We have a concrete knowledge about many building blocks, now it is time to assemble them to shape a model of our fictional world.

Completely unforeseen, we create a new class called World. On one side, our World class must contain all the data related to rendering:

A reference to the render window

The world's current view

A texture holder with all the textures needed inside the world

The scene graph

Some pointers to access the scene graph's layer nodes

On the other hand, we store some logical data:

The bounding rectangle of the world, storing its dimensions

The position where the player's plane appears in the beginning

The speed with which the world is scrolled

A pointer to the player's aircraft

Concerning functionality, we implement public functions to update and draw the world. We also add two private functions to load the texture and to build up the scene. Since we only have one world and we don't want it to be copied, the class derives privately from sf::NonCopyable.

class World : private sf::NonCopyable

{

public:

 

 

 

explicit

World(sf::RenderWindow& window);

void

update(sf::Time dt);

void

draw();

 

 

 

 

 

 

[ 74 ]

 

 

 

 

www.it-ebooks.info

Chapter 3

private:

 

 

void

loadTextures();

 

void

buildScene();

 

private:

 

 

enum Layer

 

 

{

 

 

Background,

 

 

Air,

 

 

LayerCount

 

 

};

 

 

private:

 

 

sf::RenderWindow&

mWindow;

sf::View

 

mWorldView;

TextureHolder

 

mTextures;

SceneNode

 

mSceneGraph;

std::array<SceneNode*, LayerCount>

mSceneLayers;

sf::FloatRect

 

mWorldBounds;

sf::Vector2f

 

mSpawnPosition;

float

 

mScrollSpeed;

Aircraft*

 

mPlayerAircraft;

};

For the scene layers, we use an array of pointers with the size LayerCount.

std::array is a C++11 class template for fixed-size static arrays. It offers the same functionality and performance as C arrays, but has many advantages. It provides value semantics, which allow copies, assignments, and passing or returning objects from functions. There is no implicit conversion to pointers, and index access is checked in debug mode. Additionally, an STL-conforming interface with useful methods such as size(), begin(), or end() is provided. Because of the additional safety and features, std::array should always be preferred over C arrays.

[ 75 ]

www.it-ebooks.info

Forge of the Gods – Shaping Our World

World initialization

In the constructor, we build up the world. The following figure can help to imagine the dimensions of our world:

mWorldBounds.top

World bounds

View after some time

Initial view

mSpawnPosition.y

+

Spawn position

mWorldBounds.top

 

 

+mWorldBounds.height

mWorldBounds.left mWorldBounds.left mSpawnPosition.x +mWorldBounds.width

The constructor initializes the important attributes. The mWorldBounds rectangle is initialized so that the upper-left corner lies at position (0, 0). Its width equals the window's width, and for its height we take an arbitrary value, here 2000. This is rather small value, but it shows already after a short time that the desert texture ceases to repeat any longer, leaving behind a black background.

The mSpawnPosition vector is initialized depending on the world bounds and the window. According to the previous figure, the vector's x coordinate is assigned the middle of the screen, and its y coordinate is the same as the bottom of the world minus a half screen height.

[ 76 ]

www.it-ebooks.info

Chapter 3

: mWindow(window)

 

, mWorldView(window.getDefaultView())

 

, mWorldBounds(

 

0.f,

// left X position

0.f,

// top Y position

mWorldView.getSize().x,

// width

2000.f)

// height

, mSpawnPosition(

 

mWorldView.getSize().x / 2.f,

// X

mWorldBounds.height - mWorldView.getSize()

, mPlayerAircraft(nullptr)

// Y

{

 

loadTextures();

 

buildScene();

 

mWorldView.setCenter(mSpawnPosition);

}

For the scroll speed, we choose a negative value, since we scroll upwards and the y axis points downwards. The aircraft pointer is initialized with a null pointer literal. In the constructor body, we call our two private functions that are in charge of further initialization. Finally, we move the view to the correct start position. As you see in the figure, its center initially matches the player's spawn position.

Loading the textures

Now, let's have a look at texture loading. Thanks to our ResourceHolder class, this part could not be simpler:

void World::loadTextures()

{

mTextures.load(Textures::Eagle, "Media/Textures/Eagle.png"); mTextures.load(Textures::Raptor, "Media/Textures/Raptor.png"); mTextures.load(Textures::Desert, "Media/Textures/Desert.png");

}

We do not handle exceptions here, since the World class cannot react to them. Without the textures, we are not able to construct our world meaningfully, thus it is reasonable that we let possible exceptions abort the constructor.

[ 77 ]

www.it-ebooks.info

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