Changed Generator to use std::map and Tile::Type.
This commit is contained in:
parent
079c4b539b
commit
f7b0d1348b
2 changed files with 70 additions and 78 deletions
|
@ -8,7 +8,6 @@
|
||||||
#include "Generator.h"
|
#include "Generator.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <bitset>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
@ -20,9 +19,15 @@
|
||||||
#include "../Pathfinder.h"
|
#include "../Pathfinder.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
|
||||||
/// For usage with simplexnoise.h
|
/// Seed for usage with simplexnoise.h
|
||||||
uint8_t perm[512];
|
uint8_t perm[512];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of tiles extra to generate, to get consistent walls
|
||||||
|
* across multiple generateTiles calls for bordering areas.
|
||||||
|
*/
|
||||||
|
const int Generator::MARGIN = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates new random seed.
|
* Generates new random seed.
|
||||||
*/
|
*/
|
||||||
|
@ -32,17 +37,15 @@ Generator::Generator(World& world, Pathfinder& pathfinder) :
|
||||||
std::mt19937 mersenne(time(nullptr));
|
std::mt19937 mersenne(time(nullptr));
|
||||||
std::uniform_int_distribution<int> distribution(0, 255);
|
std::uniform_int_distribution<int> distribution(0, 255);
|
||||||
|
|
||||||
for (int i = 0; i < 512; i++) {
|
for (int i = 0; i < 512; i++)
|
||||||
perm[i] = distribution(mersenne);
|
perm[i] = distribution(mersenne);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill Tile with procedurally generated tiles.
|
* Fill world with procedurally generated tiles.
|
||||||
*
|
*
|
||||||
* @param tm Tile instance to set tiles in.
|
* @param area Size and position of area to generate tiles for. Width and
|
||||||
* @param area Size and position of area to generate tiles for. Must be
|
* height must each be a power of two.
|
||||||
* power of two.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Generator::generateTiles(const sf::IntRect& area) {
|
Generator::generateTiles(const sf::IntRect& area) {
|
||||||
|
@ -50,37 +53,35 @@ Generator::generateTiles(const sf::IntRect& area) {
|
||||||
assert(area.width && !(area.width & (area.width - 1)));
|
assert(area.width && !(area.width & (area.width - 1)));
|
||||||
assert(area.height && !(area.height & (area.height - 1)));
|
assert(area.height && !(area.height & (area.height - 1)));
|
||||||
|
|
||||||
std::vector<std::vector<Tile::Type> >
|
array noise;
|
||||||
noise(area.width, std::vector<Tile::Type>(area.height));
|
array filtered;
|
||||||
std::vector<std::vector<Tile::Type> >
|
for (int x = area.left - MARGIN; x < area.left + area.width + MARGIN; x++) {
|
||||||
filtered(area.width, std::vector<Tile::Type>(
|
for (int y = area.top - MARGIN; y < area.top + area.height + MARGIN; y++) {
|
||||||
area.height, Tile::Type::FLOOR));
|
noise[x][y] =
|
||||||
|
|
||||||
for (int x = area.left; x < area.left + area.width; x++) {
|
|
||||||
for (int y = area.top; y < area.top + area.height; y++) {
|
|
||||||
noise[x-area.left][y-area.top] =
|
|
||||||
(scaled_octave_noise_2d(2, 2, 0.05f, 0.5f, -0.5f, x, y) +
|
(scaled_octave_noise_2d(2, 2, 0.05f, 0.5f, -0.5f, x, y) +
|
||||||
scaled_octave_noise_2d(2, 2, 0.5f, 0.15f, -0.15f, x, y)
|
scaled_octave_noise_2d(2, 2, 0.5f, 0.15f, -0.15f, x, y)
|
||||||
< -0.1f)
|
< -0.1f)
|
||||||
? Tile::Type::WALL
|
? type::WALL
|
||||||
: Tile::Type::FLOOR;
|
: type::FLOOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int x = 0; x < (int) noise.size(); x++) {
|
fill(filtered, area, type::FLOOR);
|
||||||
for (int y = 0; y < (int) noise[x].size(); y++) {
|
|
||||||
|
for (int x = area.left; x < area.left + area.width; x++) {
|
||||||
|
for (int y = area.top; y < area.top + area.height; y++) {
|
||||||
filterWalls(noise, filtered, x, y, 2, 1, 0);
|
filterWalls(noise, filtered, x, y, 2, 1, 0);
|
||||||
filterWalls(noise, filtered, x, y, 6, 1, 2);
|
filterWalls(noise, filtered, x, y, 6, 1, 2);
|
||||||
filterWalls(noise, filtered, x, y, 10, 1, 4);
|
filterWalls(noise, filtered, x, y, 10, 1, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = area.left; x < area.left + area.width; x++) {
|
for (int x = area.left; x < area.left + area.width; x++) {
|
||||||
for (int y = area.top; y < area.top + area.height; y++) {
|
for (int y = area.top; y < area.top + area.height; y++) {
|
||||||
mWorld.insert(std::shared_ptr<Sprite>(
|
mWorld.insert(std::shared_ptr<Sprite>(
|
||||||
new Tile(filtered[x-area.left][y-area.top], x, y)));
|
new Tile(filtered.at(x).at(y), x, y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generateAreas(filtered, area,
|
generateAreas(filtered, area, sf::Vector2f(area.left, area.top));
|
||||||
sf::Vector2f(area.left, area.top));
|
|
||||||
mPathfinder.generatePortals();
|
mPathfinder.generatePortals();
|
||||||
mGenerated = filtered;
|
mGenerated = filtered;
|
||||||
}
|
}
|
||||||
|
@ -88,34 +89,30 @@ Generator::generateTiles(const sf::IntRect& area) {
|
||||||
/**
|
/**
|
||||||
* Fills a rectangular area with the specified value.
|
* Fills a rectangular area with the specified value.
|
||||||
*
|
*
|
||||||
* @param[in] Rectangular map.
|
* @param[in,out] Array to set values to.
|
||||||
* @param area The area to fill.
|
* @param area The area to fill.
|
||||||
* @param value The value to set.
|
* @param value The value to set.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Generator::fill(std::vector<std::vector<Tile::Type> >& image,
|
Generator::fill(array& image, const sf::IntRect& area, Tile::Type value) {
|
||||||
const sf::IntRect& area, Tile::Type value) {
|
for (int x = area.left; x < area.left + area.width; x++) {
|
||||||
for (int x = area.left;
|
for (int y = area.top; y < area.top + area.height; y++)
|
||||||
x < area.left + area.width && x < (int) image.size(); x++) {
|
|
||||||
for (int y = area.top;
|
|
||||||
y < area.top + area.height && y < (int) image[x].size(); y++) {
|
|
||||||
image[x][y] = value;
|
image[x][y] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of walls in the area in tiles.
|
* Counts and returns the number of walls within the area.
|
||||||
*
|
*
|
||||||
|
* @param[in] tiles Array of tile values.
|
||||||
* @param area The area to count in.
|
* @param area The area to count in.
|
||||||
* @param tiles Array of tile values.
|
|
||||||
*/
|
*/
|
||||||
int Generator::countWalls(const sf::IntRect& area,
|
int
|
||||||
std::vector<std::vector<Tile::Type> >& tiles) {
|
Generator::countWalls(const array& tiles, const sf::IntRect& area) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int x = area.left; x < area.left + area.width; x++) {
|
for (int x = area.left; x < area.left + area.width; x++) {
|
||||||
for (int y = area.top; y < area.top + area.height; y++)
|
for (int y = area.top; y < area.top + area.height; y++)
|
||||||
count += (int) (tiles[x][y] == Tile::Type::WALL);
|
count += (int) (tiles.at(x).at(y) == type::WALL);
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -124,8 +121,9 @@ int Generator::countWalls(const sf::IntRect& area,
|
||||||
* Finds rectangles of specific size inside vector in and
|
* Finds rectangles of specific size inside vector in and
|
||||||
* puts them into vector out.
|
* puts them into vector out.
|
||||||
*
|
*
|
||||||
* @param[in] in Rectangular map of tiles.
|
* @param[in] in Perlin noise values.
|
||||||
* @param[out] out Rectangular map of tiles.
|
* @param[in,out] out Tiles to be placed. Does not explicitly set floor values
|
||||||
|
* (keeps previous values).
|
||||||
* @param x Position to check from (top left corner for rectangle).
|
* @param x Position to check from (top left corner for rectangle).
|
||||||
* @param y Position to check from (top left corner for rectangle).
|
* @param y Position to check from (top left corner for rectangle).
|
||||||
* @param longside Length of the longer side of the rectangle.
|
* @param longside Length of the longer side of the rectangle.
|
||||||
|
@ -134,39 +132,31 @@ int Generator::countWalls(const sf::IntRect& area,
|
||||||
* tiles is not walls (tilecount >= longside * shortside - subtract).
|
* tiles is not walls (tilecount >= longside * shortside - subtract).
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Generator::filterWalls(std::vector<std::vector<Tile::Type> >& in,
|
Generator::filterWalls(const array& in, array& out, int x, int y, int longside,
|
||||||
std::vector<std::vector<Tile::Type> >& out,
|
int shortside, int subtract) {
|
||||||
int x, int y, int longside, int shortside, int subtract) {
|
|
||||||
// Skip if we would go out of range.
|
|
||||||
if ((x + longside >= (int) in.size()) ||
|
|
||||||
(y + longside >= (int) in[0].size()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Filter in horizontal direction.
|
// Filter in horizontal direction.
|
||||||
if (countWalls(sf::IntRect(x, y, longside, shortside), in) >=
|
if (countWalls(in, sf::IntRect(x, y, longside, shortside)) >=
|
||||||
shortside * longside - subtract)
|
shortside * longside - subtract)
|
||||||
fill(out, sf::IntRect(x, y, longside, shortside), Tile::Type::WALL);
|
fill(out, sf::IntRect(x, y, longside, shortside), type::WALL);
|
||||||
// Filter in vertical direction.
|
// Filter in vertical direction.
|
||||||
if (countWalls(sf::IntRect(x, y, shortside, longside), in) >=
|
if (countWalls(in, sf::IntRect(x, y, shortside, longside)) >=
|
||||||
shortside * longside - subtract)
|
shortside * longside - subtract)
|
||||||
fill(out, sf::IntRect(x, y, shortside, longside), Tile::Type::WALL);
|
fill(out, sf::IntRect(x, y, shortside, longside), type::WALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts tile if all values within area are the same, otherwise divides area
|
* Inserts tile if all values within area are the same, otherwise divides area
|
||||||
* into four and continues recursively.
|
* into four and continues recursively.
|
||||||
*
|
*
|
||||||
* @param tiles Array of tile values.
|
* @param in Array of tile values.
|
||||||
* @param area The area to generate areas for.
|
* @param area The area to generate areas for.
|
||||||
* @param offset Offset of tiles[0][0] from World coordinate (0, 0).
|
* @param offset Offset of tiles[0][0] from World coordinate (0, 0).
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Generator::generateAreas(
|
Generator::generateAreas(const array& in, const sf::IntRect& area,
|
||||||
std::vector<std::vector<Tile::Type> >& tiles,
|
const sf::Vector2f& offset) const {
|
||||||
const sf::IntRect& area, const sf::Vector2f& offset) {
|
|
||||||
assert(area.width > 0 && area.height > 0);
|
assert(area.width > 0 && area.height > 0);
|
||||||
int count = countWalls(sf::IntRect(area.left - offset.y, area.top - offset.x,
|
int count = countWalls(in, area);
|
||||||
area.width, area.height), tiles);
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
mPathfinder.insertArea(sf::IntRect(area));
|
mPathfinder.insertArea(sf::IntRect(area));
|
||||||
}
|
}
|
||||||
|
@ -176,13 +166,13 @@ Generator::generateAreas(
|
||||||
else {
|
else {
|
||||||
int halfWidth = area.width / 2.0f;
|
int halfWidth = area.width / 2.0f;
|
||||||
int halfHeight = area.height / 2.0f;
|
int halfHeight = area.height / 2.0f;
|
||||||
generateAreas(tiles, sf::IntRect(area.left,
|
generateAreas(in, sf::IntRect(area.left,
|
||||||
area.top, halfWidth, halfHeight), offset);
|
area.top, halfWidth, halfHeight), offset);
|
||||||
generateAreas(tiles, sf::IntRect(area.left + halfWidth,
|
generateAreas(in, sf::IntRect(area.left + halfWidth,
|
||||||
area.top, halfWidth, halfHeight), offset);
|
area.top, halfWidth, halfHeight), offset);
|
||||||
generateAreas(tiles, sf::IntRect(area.left,
|
generateAreas(in, sf::IntRect(area.left,
|
||||||
area.top + halfHeight, halfWidth, halfHeight), offset);
|
area.top + halfHeight, halfWidth, halfHeight), offset);
|
||||||
generateAreas(tiles, sf::IntRect(area.left + halfWidth,
|
generateAreas(in, sf::IntRect(area.left + halfWidth,
|
||||||
area.top + halfHeight, halfWidth, halfHeight), offset);
|
area.top + halfHeight, halfWidth, halfHeight), offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,15 +182,15 @@ Generator::generateAreas(
|
||||||
*/
|
*/
|
||||||
sf::Vector2f
|
sf::Vector2f
|
||||||
Generator::getPlayerSpawn() const {
|
Generator::getPlayerSpawn() const {
|
||||||
sf::Vector2i spawn = findClosestFloor(sf::Vector2i(mGenerated.size() / 2,
|
sf::Vector2i spawn = findClosestFloor(sf::Vector2i(0, 0));
|
||||||
mGenerated[0].size() / 2));
|
return sf::Vector2f(spawn.x * Tile::TILE_SIZE.x,
|
||||||
return sf::Vector2f(
|
spawn.y * Tile::TILE_SIZE.y);
|
||||||
(spawn.x - mGenerated.size() / 2.0f) * Tile::TILE_SIZE.x,
|
|
||||||
(spawn.y - mGenerated[0].size() / 2.0f) * Tile::TILE_SIZE.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the point array index closest to position which has a floor tile.
|
* Finds the point array index closest to position which has a floor tile.
|
||||||
|
*
|
||||||
|
* @position Point to start search for a floor tile from.
|
||||||
*/
|
*/
|
||||||
sf::Vector2i
|
sf::Vector2i
|
||||||
Generator::findClosestFloor(const sf::Vector2i& position) const {
|
Generator::findClosestFloor(const sf::Vector2i& position) const {
|
||||||
|
@ -219,7 +209,7 @@ Generator::findClosestFloor(const sf::Vector2i& position) const {
|
||||||
const sf::Vector2i& current = open.begin()->first;
|
const sf::Vector2i& current = open.begin()->first;
|
||||||
open.erase(current);
|
open.erase(current);
|
||||||
closed.insert(current);
|
closed.insert(current);
|
||||||
if (mGenerated[current.x][current.y] == Tile::Type::FLOOR)
|
if (mGenerated.at(current.x).at(current.y) == Tile::Type::FLOOR)
|
||||||
return current;
|
return current;
|
||||||
else {
|
else {
|
||||||
if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end())
|
if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end())
|
||||||
|
|
|
@ -22,21 +22,23 @@ public:
|
||||||
sf::Vector2f getPlayerSpawn() const;
|
sf::Vector2f getPlayerSpawn() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::Vector2i findClosestFloor(const sf::Vector2i& position) const;
|
typedef Tile::Type type;
|
||||||
static void fill(std::vector<std::vector<Tile::Type> >& image,
|
typedef std::map<int, std::map<int, type> > array;
|
||||||
const sf::IntRect& area, Tile::Type value);
|
|
||||||
static void filterWalls(std::vector<std::vector<Tile::Type> >& in,
|
|
||||||
std::vector<std::vector<Tile::Type> >& out,
|
|
||||||
int x, int y, int longside, int shortside, int subtract);
|
|
||||||
static int countWalls(const sf::IntRect& area,
|
|
||||||
std::vector<std::vector<Tile::Type> >& tiles);
|
|
||||||
void generateAreas(std::vector<std::vector<Tile::Type> >& tiles,
|
|
||||||
const sf::IntRect& area, const sf::Vector2f& offset);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
sf::Vector2i findClosestFloor(const sf::Vector2i& position) const;
|
||||||
|
static void fill(array& in, const sf::IntRect& area, type value);
|
||||||
|
static void filterWalls(const array& in, array& out, int x, int y,
|
||||||
|
int longside, int shortside, int subtract);
|
||||||
|
static int countWalls(const array& in, const sf::IntRect& area);
|
||||||
|
void generateAreas(const array& in, const sf::IntRect& area,
|
||||||
|
const sf::Vector2f& offset) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int MARGIN;
|
||||||
World& mWorld;
|
World& mWorld;
|
||||||
Pathfinder& mPathfinder;
|
Pathfinder& mPathfinder;
|
||||||
std::vector<std::vector<Tile::Type> > mGenerated;
|
array mGenerated;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DG_GENERATOR_H_ */
|
#endif /* DG_GENERATOR_H_ */
|
||||||
|
|
Reference in a new issue