Open the Engine.h
file and add a new prototype for a populateEmitters
function and a new STL vector
of Vector2f
objects:
...
...
...
// Run will call all the private functions
bool detectCollisions(PlayableCharacter& character);
// Make a vector of the best places to emit sounds from
void populateEmitters(vector <Vector2f>& vSoundEmitters,
int** arrayLevel);
// A vector of Vector2f for the fire emitter locations
vector <Vector2f> m_FireEmitters;
public:
...
...
...
The populateEmitters
function takes as a parameter a vector
of Vector2f
objects, as well as a pointer to int
(a two-dimensional array). The vector
will hold the location of each emitter in a level and the array is our two-dimensional array, which holds the layout of a level.
The job of the populateEmitters
function is to scan through all the elements of arrayLevel
and decide where to put the emitters. It will store its results in m_FireEmitters
.
Right-click Source Files in the Solution Explorer and select Add | New Item.... In the Add New Item window, highlight (by left-clicking) C++ File (.cpp
) and then in the Name field, type PopulateEmitters.cpp
. Finally, click the Add button. Now we can code the new function, populateEmitters
.
Add the code in its entirety; be sure to study the code as you do, and then we can discuss it:
#include "stdafx.h" #include "Engine.h" using namespace sf; using namespace std; void Engine::populateEmitters( vector <Vector2f>& vSoundEmitters, int** arrayLevel) { // Make sure the vector is empty vSoundEmitters.empty(); // Keep track of the previous emitter // so we don't make too many FloatRect previousEmitter; // Search for fire in the level for (int x = 0; x < (int)m_LM.getLevelSize().x; x++) { for (int y = 0; y < (int)m_LM.getLevelSize().y; y++) { if (arrayLevel[y][x] == 2)// fire is present { // Skip over any fire tiles too // near a previous emitter if (!FloatRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE).intersects(previousEmitter)) { // Add the coordiantes of this water block vSoundEmitters.push_back( Vector2f(x * TILE_SIZE, y * TILE_SIZE)); // Make a rectangle 6 blocks x 6 blocks, // so we don't make any more emitters // too close to this one previousEmitter.left = x * TILE_SIZE; previousEmitter.top = y * TILE_SIZE; previousEmitter.width = TILE_SIZE * 6; previousEmitter.height = TILE_SIZE * 6; } } } } return; }
Some of the code might appear complex at first glance. Understanding the technique we use to choose where an emitter will make it simpler. In our levels, there are, regularly, large blocks of fire tiles. In one of the levels I designed there are more than 30 fire tiles together. The code makes sure that there is only one emitter within a given rectangle. This rectangle is stored in previousEmitter
and is 300 pixels by 300 pixels (TILE_SIZE * 6
).
The code sets up a nested for
loop that loops through arrayLevel
looking for fire tiles. When it finds one, it makes sure that it does not intersect with previousEmitter
. Only then does it use the pushBack
function to add another emitter to vSoundEmitters
. After doing so, it also updates previousEmitter
to avoid getting large clusters of sound emitters.
Let's make some noise.
3.16.135.36