From 602cc605e8f29f3e28aeeb81d7d55ee345197cab Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 7 Aug 2013 00:13:04 +0200 Subject: [PATCH] Changed procedural generation to use minimum spanning trees. --- source/generator/Generator.cpp | 606 ++++++++++++++++----------------- source/generator/Generator.h | 115 +++---- source/sprites/Tile.h | 4 +- 3 files changed, 358 insertions(+), 367 deletions(-) diff --git a/source/generator/Generator.cpp b/source/generator/Generator.cpp index 57efb6b..8b94cb3 100644 --- a/source/generator/Generator.cpp +++ b/source/generator/Generator.cpp @@ -1,305 +1,301 @@ -/* - * Generator.cpp - * - * Created on: 07.04.2013 - * Author: Felix - */ - -#include "Generator.h" - -#include -#include -#include -#include - -#include - -#include - -#include "../Pathfinder.h" -#include "../World.h" -#include "../sprites/Enemy.h" - -const int Generator::GENERATE_AREA_SIZE = 4; -const float Generator::GENERATE_AREA_RANGE = 4.0f; - -/** - * Generates new random seed. - */ -Generator::Generator(World& world, Pathfinder& pathfinder) : - mWorld(world), - mPathfinder(pathfinder) { -} - -/** - * Generates tiles near player position (maximum distance is determined by - * GENERATE_AREA_SIZE and GENERATE_AREA_RANGE). - */ -void -Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& playerPosition) { - auto compare = [](const sf::Vector2i& a, const sf::Vector2i& b) { - return a.x < b.x || (a.x == b.x && a.y < b.y); - }; - std::map open(compare); - std::set closed(compare); - - sf::Vector2i start((int) floor(playerPosition.x / Tile::TILE_SIZE.x), - (int) floor(playerPosition.y / Tile::TILE_SIZE.y)); - start /= GENERATE_AREA_SIZE; - auto makePair = [&start](const sf::Vector2i& point) { - return std::make_pair(point, thor::length(sf::Vector2f(point - start))); - }; - - open.insert(makePair(start)); - while (!open.empty()) { - auto intComp = [](const std::pair& left, - const std::pair& right) { - return left.second < right.second; - }; - sf::Vector2i current = - std::min_element(open.begin(), open.end(), intComp)->first; - float distance = open[current]; - open.erase(current); - closed.insert(current); - if (!mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) { - mGenerated[current.x][current.y] = true; - sf::IntRect area(current * GENERATE_AREA_SIZE - - sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2, - sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE)); - generateTiles(area); - for (const auto& enemyPosition : getEnemySpawns(area)) { - float distance = thor::length(enemyPosition - playerPosition); - if (distance > Character::VISION_DISTANCE) { - mWorld.insertCharacter(std::shared_ptr(new Enemy(mWorld, mPathfinder, enemyPosition))); - } - } - } - if (mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) { - if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x + 1, current.y))); - if (closed.find(sf::Vector2i(current.x, current.y + 1)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x, current.y + 1))); - if (closed.find(sf::Vector2i(current.x - 1, current.y)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x - 1, current.y))); - if (closed.find(sf::Vector2i(current.x, current.y - 1)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x, current.y - 1))); - } - } -} - -/** - * Fill world with procedurally generated tiles. - * - * @param area Size and position of area to generate tiles for. Width and - * height must each be a power of two. - */ -void -Generator::generateTiles(const sf::IntRect& area) { - // Check if width and height are power of two. - assert(area.width && !(area.width & (area.width - 1))); - assert(area.height && !(area.height & (area.height - 1))); - - array generatedTiles; - fill(generatedTiles, area, type::FLOOR); - - for (int x = area.left; x < area.left + area.width; x++) { - for (int y = area.top; y < area.top + area.height; y++) { - filterWalls(generatedTiles, x, y, 2, 1, 0); - filterWalls(generatedTiles, x, y, 6, 1, 2); - filterWalls(generatedTiles, x, y, 10, 1, 4); - } - } - - for (int x = area.left; x < area.left + area.width; x++) - for (int y = area.top; y < area.top + area.height; y++) { - // Merge map that we just generated with stored map. - mTiles[x][y] = generatedTiles[x][y]; - // Actually generate physical tiles. - mWorld.insert(std::shared_ptr( - new Tile(generatedTiles.at(x).at(y), x, y))); - } - - generateAreas(area); - mPathfinder.generatePortals(); -} - -/** - * Returns coordinates where enemies should spawn. - */ -std::vector -Generator::getEnemySpawns(const sf::IntRect& area) { - auto compare = [](const sf::Vector2f& a, const sf::Vector2f& b) { - return a.x < b.x || (a.x == b.x && a.y < b.y); - }; - std::set ret(compare); - for (int x = area.left; x < area.left + area.width; x++) { - for (int y = area.top; y < area.top + area.height; y++) { - if (mCharacterNoise.getNoise(x, y) < -0.85f) { - sf::Vector2i tilePosition = findClosestFloor(sf::Vector2i(x, y)); - ret.insert(sf::Vector2f(tilePosition.x * Tile::TILE_SIZE.x, - tilePosition.y * Tile::TILE_SIZE.y)); - } - } - } - return std::vector(ret.begin(), ret.end()); -} - -/** - * Fills a rectangular area with the specified value. - * - * @param[in,out] Array to set values to. - * @param area The area to fill. - * @param value The value to set. - */ -void -Generator::fill(array& tiles, const sf::IntRect& area, Tile::Type value) { - for (int x = area.left; x < area.left + area.width; x++) { - for (int y = area.top; y < area.top + area.height; y++) - tiles[x][y] = value; - } -} - -/** - * Counts and returns the number of walls within the area. - * - * @param area The area to count in. - */ -int -Generator::countWalls(const sf::IntRect& area) { - int count = 0; - for (int x = area.left; x < area.left + area.width; x++) { - for (int y = area.top; y < area.top + area.height; y++) - count += (int) (getTileType(mTileNoise.getNoise(x, y)) == - type::WALL); - } - return count; -} - -/** - * Finds rectangles of specific size with mTileNoise and - * puts them into vector out. - * - * @param[in,out] tiles 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 y Position to check from (top left corner for rectangle). - * @param longside Length of the longer side of the rectangle. - * @param shortside Length of the shorter side of the rectangle. - * @param subtract Still accepts rectangle if at least this amount of - * tiles is not walls (tilecount >= longside * shortside - subtract). - */ -void -Generator::filterWalls(array& tiles, int x, int y, int longside, - int shortside, int subtract) { - // Filter in horizontal direction. - if (countWalls(sf::IntRect(x, y, longside, shortside)) >= - shortside * longside - subtract) - fill(tiles, sf::IntRect(x, y, longside, shortside), type::WALL); - // Filter in vertical direction. - if (countWalls(sf::IntRect(x, y, shortside, longside)) >= - shortside * longside - subtract) - fill(tiles, sf::IntRect(x, y, shortside, longside), type::WALL); -} - -/** - * Inserts floor tiles into path finder, using a quadtree approach to group - * tiles where possible. - * - * @param area The area to generate areas for. - */ -void -Generator::generateAreas(const sf::IntRect& area) { - assert(area.width > 0 && area.height > 0); - - int wallCount = 0; - for (int x = area.left; x < area.left + area.width; x++) - for (int y = area.top; y < area.top + area.height; y++) - wallCount += (int) (mTiles[x][y] == type::WALL); - - if (wallCount == 0) - mPathfinder.insertArea(sf::FloatRect(area.left, area.top, area.width, area.height)); - else if (wallCount == area.width * area.height) - return; - else { - int halfWidth = area.width / 2; - int halfHeight = area.height / 2; - generateAreas(sf::IntRect(area.left, - area.top, halfWidth, halfHeight)); - generateAreas(sf::IntRect(area.left + halfWidth, - area.top, halfWidth, halfHeight)); - generateAreas(sf::IntRect(area.left, - area.top + halfHeight, halfWidth, halfHeight)); - generateAreas(sf::IntRect(area.left + halfWidth, - area.top + halfHeight, halfWidth, halfHeight)); - } -} - -/** - * Defines if a perlin noise result value is converted to a wall or floor tile. - * - * @param value Perlin noise value within [-1, 1] - */ -Generator::type -Generator::getTileType(float value) { - return (value < -0.2f) - ? type::WALL - : type::FLOOR; -} - -/** - * Returns a valid position (floor) for the player to spawn at. - */ -sf::Vector2f -Generator::getPlayerSpawn() const { - sf::Vector2i spawn = findClosestFloor(sf::Vector2i(0, 0)); - return sf::Vector2f(spawn.x * Tile::TILE_SIZE.x, - spawn.y * Tile::TILE_SIZE.y); -} - -/** - * Finds the point array index closest to position which has a floor tile. - * - * @warn Will fail if no floor tile has been generated yet. - * @position Point to start search for a floor tile from. - */ -sf::Vector2i -Generator::findClosestFloor(const sf::Vector2i& position) const { - auto compare = [](const sf::Vector2i& a, const sf::Vector2i& b) { - return a.x < b.x || (a.x == b.x && a.y < b.y); - }; - std::map open(compare); - std::set closed(compare); - sf::Vector2i start = position; - auto makePair = [&start](const sf::Vector2i& point) { - return std::make_pair(point, thor::length(sf::Vector2f(point - start))); - }; - - open.insert(makePair(start)); - while (!open.empty()) { - auto intComp = [](const std::pair& left, - const std::pair& right) { - return left.second < right.second; - }; - sf::Vector2i current = std::min_element(open.begin(), open.end(), intComp)->first; - open.erase(current); - closed.insert(current); - if (mTiles.count(current.x) != 0 && - mTiles.at(current.x).count(current.y) != 0 && - mTiles.at(current.x).at(current.y) == type::FLOOR) { - return current; - } - else { - if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x + 1, current.y))); - if (closed.find(sf::Vector2i(current.x, current.y + 1)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x, current.y + 1))); - if (closed.find(sf::Vector2i(current.x - 1, current.y)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x - 1, current.y))); - if (closed.find(sf::Vector2i(current.x, current.y - 1)) == closed.end()) - open.insert(makePair(sf::Vector2i(current.x, current.y - 1))); - } - } - // No floor tile found in the entire world. - assert(false); - return sf::Vector2i(); -} +/* + * Generator.cpp + * + * Created on: 07.04.2013 + * Author: Felix + */ + +#include "Generator.h" + +#include +#include +#include +#include + +#include + +#include + +#include "../Pathfinder.h" +#include "../World.h" +#include "../sprites/Enemy.h" +#include "../util/Log.h" + +const int Generator::GENERATE_AREA_SIZE = 4; +const float Generator::GENERATE_AREA_RANGE = 4.0f; + +/** + * Generates new random seed. + */ +Generator::Generator(World& world, Pathfinder& pathfinder) : + mWorld(world), + mPathfinder(pathfinder) { +} + +/** + * Generates tiles near player position (maximum distance is determined by + * GENERATE_AREA_SIZE and GENERATE_AREA_RANGE). + */ +void +Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& playerPosition) { + auto compare = [](const sf::Vector2i& a, const sf::Vector2i& b) { + return a.x < b.x || (a.x == b.x && a.y < b.y); + }; + std::map open(compare); + std::set closed(compare); + + sf::Vector2i start((int) floor(playerPosition.x / Tile::TILE_SIZE.x), + (int) floor(playerPosition.y / Tile::TILE_SIZE.y)); + start /= GENERATE_AREA_SIZE; + auto makePair = [&start](const sf::Vector2i& point) { + return std::make_pair(point, thor::length(sf::Vector2f(point - start))); + }; + + open.insert(makePair(start)); + while (!open.empty()) { + auto intComp = [](const std::pair& left, + const std::pair& right) { + return left.second < right.second; + }; + sf::Vector2i current = + std::min_element(open.begin(), open.end(), intComp)->first; + float distance = open[current]; + open.erase(current); + closed.insert(current); + if (!mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) { + mGenerated[current.x][current.y] = true; + sf::IntRect area(current * GENERATE_AREA_SIZE - + sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2, + sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE)); + generateTiles(area); + for (const auto& enemyPosition : getEnemySpawns(area)) { + float distance = thor::length(enemyPosition - playerPosition); + if (distance > Character::VISION_DISTANCE) { + mWorld.insertCharacter(std::shared_ptr(new Enemy(mWorld, mPathfinder, enemyPosition))); + } + } + } + if (mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) { + if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x + 1, current.y))); + if (closed.find(sf::Vector2i(current.x, current.y + 1)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x, current.y + 1))); + if (closed.find(sf::Vector2i(current.x - 1, current.y)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x - 1, current.y))); + if (closed.find(sf::Vector2i(current.x, current.y - 1)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x, current.y - 1))); + } + } +} + +/** + * Generates a minimum spanning tree on mTileNoise, starting from start with + * a maximum total node weight of limit. + * + * FIXME: Some nodes are selected more than once. + */ +std::vector +Generator::createMinimalSpanningTree(const sf::Vector2i& start, + const float limit) { + std::vector open; + std::vector selected; + open.push_back(start); + float totalWeight = 0.0f; + + while (totalWeight < limit) { + sf::Vector2i current; + float minValue = std::numeric_limits::max(); + for (auto& o : open) { + if (mTileNoise.getNoise(o.x, o.y) + 1.0f < minValue) { + current = o; + minValue = mTileNoise.getNoise(o.x, o.y) + 1.0f; + } + } + std::remove(open.begin(), open.end(), current); + selected.push_back(current); + totalWeight += minValue; + + auto insertOnlyNew = [&open, &selected](const sf::Vector2i& v) { + if (std::find(open.begin(), open.end(), v) == open.end() + && std::find(selected.begin(), selected.end(), v) == selected.end()) + open.push_back(v); + }; + insertOnlyNew(sf::Vector2i(current.x + 1, current.y)); + insertOnlyNew(sf::Vector2i(current.x, current.y + 1)); + insertOnlyNew(sf::Vector2i(current.x - 1, current.y)); + insertOnlyNew(sf::Vector2i(current.x, current.y - 1)); + } + return selected; +} + +/** + * Fill world with procedurally generated tiles. + * + * This is done by generating random (simplex) noise, with a value mapped + * to every integer point in area, selecting the lowest value point as start, + * and building a minimum spanning tree from there. + * + * @param area Size and position of area to generate tiles for. Width and + * height must each be a power of two. + */ +void +Generator::generateTiles(const sf::IntRect& area) { + // Width and height must be a power of two. + assert(area.width && !(area.width & (area.width - 1))); + assert(area.height && !(area.height & (area.height - 1))); + + sf::Vector2i start; + float minValue = std::numeric_limits::max(); + + // Find lowest value for tree start. + for (int x = area.left; x < area.left + area.width; x++) + for (int y = area.top; y < area.top + area.height; y++) { + if (mTileNoise.getNoise(x, y) + 1.0f < minValue) { + start = sf::Vector2i(x, y); + minValue = mTileNoise.getNoise(x, y) + 1.0f; + } + } + + std::vector selected = createMinimalSpanningTree(start, 12.0f); + + // For rooms, take minimum bounding box of spanning tree. + + int left = start.x; + int right = start.x; + int down = start.y; + int up = start.y; + + for (auto& s : selected) { + if (s.x < left) left = s.x; + if (s.x > right) right = s.x; + if (s.y < down) down = s.y; + if (s.y > up) up = s.y; + } + + // Merge new map into stored map and create tile sprites. + for (int x = area.left; x < area.left + area.width; x++) + for (int y = area.top; y < area.top + area.height; y++) { + Tile::Type type = ((x >= left && x < right && y >= down && y < up) + || (mTiles[x][y] == Tile::Type::FLOOR)) + ? Tile::Type::FLOOR + : Tile::Type::WALL; + mTiles[x][y] = type; + mWorld.insert(std::shared_ptr(new Tile(type, x, y))); + } + generateAreas(area); + mPathfinder.generatePortals(); +} + +/** + * Returns coordinates where enemies should spawn. + * + * @param area Area for which enemy spawns should be returned. + */ +std::vector +Generator::getEnemySpawns(const sf::IntRect& area) { + auto compare = [](const sf::Vector2f& a, const sf::Vector2f& b) { + return a.x < b.x || (a.x == b.x && a.y < b.y); + }; + std::set ret(compare); + for (int x = area.left; x < area.left + area.width; x++) { + for (int y = area.top; y < area.top + area.height; y++) { + if (mCharacterNoise.getNoise(x, y) < -0.85f) { + sf::Vector2i tilePosition = findClosestFloor(sf::Vector2i(x, y)); + ret.insert(sf::Vector2f(tilePosition.x * Tile::TILE_SIZE.x, + tilePosition.y * Tile::TILE_SIZE.y)); + } + } + } + return std::vector(ret.begin(), ret.end()); +} + +/** + * Inserts floor tiles into path finder, using a quadtree approach to group + * tiles where possible. + * + * @param area The area to generate areas for. + */ +void +Generator::generateAreas(const sf::IntRect& area) { + assert(area.width > 0 && area.height > 0); + + int wallCount = 0; + for (int x = area.left; x < area.left + area.width; x++) + for (int y = area.top; y < area.top + area.height; y++) + wallCount += (int) (mTiles[x][y] == Tile::Type::WALL); + + if (wallCount == 0) + mPathfinder.insertArea(sf::FloatRect(area.left, area.top, area.width, area.height)); + else if (wallCount == area.width * area.height) + return; + else { + int halfWidth = area.width / 2; + int halfHeight = area.height / 2; + generateAreas(sf::IntRect(area.left, + area.top, halfWidth, halfHeight)); + generateAreas(sf::IntRect(area.left + halfWidth, + area.top, halfWidth, halfHeight)); + generateAreas(sf::IntRect(area.left, + area.top + halfHeight, halfWidth, halfHeight)); + generateAreas(sf::IntRect(area.left + halfWidth, + area.top + halfHeight, halfWidth, halfHeight)); + } +} + +/** + * Returns a valid position (floor) for the player to spawn at. + */ +sf::Vector2f +Generator::getPlayerSpawn() const { + sf::Vector2i spawn = findClosestFloor(sf::Vector2i(0, 0)); + return sf::Vector2f(spawn.x * Tile::TILE_SIZE.x, + spawn.y * Tile::TILE_SIZE.y); +} + +/** + * Finds the point array index closest to position which has a floor tile. + * + * @warn Will fail if no floor tile has been generated yet. + * @position Point to start search for a floor tile from. + */ +sf::Vector2i +Generator::findClosestFloor(const sf::Vector2i& position) const { + auto compare = [](const sf::Vector2i& a, const sf::Vector2i& b) { + return a.x < b.x || (a.x == b.x && a.y < b.y); + }; + std::map open(compare); + std::set closed(compare); + sf::Vector2i start = position; + auto makePair = [&start](const sf::Vector2i& point) { + return std::make_pair(point, thor::length(sf::Vector2f(point - start))); + }; + + open.insert(makePair(start)); + while (!open.empty()) { + auto intComp = [](const std::pair& left, + const std::pair& right) { + return left.second < right.second; + }; + sf::Vector2i current = std::min_element(open.begin(), open.end(), intComp)->first; + open.erase(current); + closed.insert(current); + if (mTiles.count(current.x) != 0 && + mTiles.at(current.x).count(current.y) != 0 && + mTiles.at(current.x).at(current.y) == Tile::Type::FLOOR) { + return current; + } + else { + if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x + 1, current.y))); + if (closed.find(sf::Vector2i(current.x, current.y + 1)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x, current.y + 1))); + if (closed.find(sf::Vector2i(current.x - 1, current.y)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x - 1, current.y))); + if (closed.find(sf::Vector2i(current.x, current.y - 1)) == closed.end()) + open.insert(makePair(sf::Vector2i(current.x, current.y - 1))); + } + } + // No floor tile found in the entire world. + assert(false); + return sf::Vector2i(); +} diff --git a/source/generator/Generator.h b/source/generator/Generator.h index 2774bb5..707c7fc 100644 --- a/source/generator/Generator.h +++ b/source/generator/Generator.h @@ -1,60 +1,55 @@ -/* - * Generator.h - * - * Created on: 07.04.2013 - * Author: Felix - */ - -#ifndef DG_GENERATOR_H_ -#define DG_GENERATOR_H_ - -#include - -#include "../sprites/Tile.h" -#include "SimplexNoise.h" - -class World; -class Pathfinder; - -/** - * Procedurally generates tiles, chooses player and enemy spawn positions. - */ -class Generator { -public: - explicit Generator(World& world, Pathfinder& pathfinder); - void generateCurrentAreaIfNeeded(const sf::Vector2f& position); - sf::Vector2f getPlayerSpawn() const; - std::vector getEnemySpawns(const sf::IntRect& area); - -private: - typedef Tile::Type type; - typedef std::map > array; - -private: - void generateAreas(const sf::IntRect& area); - void generateTiles(const sf::IntRect& area); - sf::Vector2i findClosestFloor(const sf::Vector2i& position) const; - - static void fill(array& tiles, const sf::IntRect& area, type value); - void filterWalls(array& tiles, int x, int y, int longside, - int shortside, int subtract); - int countWalls(const sf::IntRect& area); - static type getTileType(float value); - -private: - static const int GENERATE_AREA_SIZE; - static const float GENERATE_AREA_RANGE; - - World& mWorld; - Pathfinder& mPathfinder; - /// Contains values of all tiles that have yet been generated. - array mTiles; - /// Stores where tiles have already been generated. - std::map > mGenerated; - /// Perlin noise used for tile generation. - SimplexNoise mTileNoise; - /// Perlin noise used for character placement. - SimplexNoise mCharacterNoise; -}; - -#endif /* DG_GENERATOR_H_ */ +/* + * Generator.h + * + * Created on: 07.04.2013 + * Author: Felix + */ + +#ifndef DG_GENERATOR_H_ +#define DG_GENERATOR_H_ + +#include + +#include "../sprites/Tile.h" +#include "SimplexNoise.h" + +class World; +class Pathfinder; + +/** + * Procedurally generates tiles, chooses player and enemy spawn positions. + */ +class Generator { +public: + explicit Generator(World& world, Pathfinder& pathfinder); + void generateCurrentAreaIfNeeded(const sf::Vector2f& position); + sf::Vector2f getPlayerSpawn() const; + std::vector getEnemySpawns(const sf::IntRect& area); + +private: + typedef std::map > array; + +private: + void generateAreas(const sf::IntRect& area); + void generateTiles(const sf::IntRect& area); + sf::Vector2i findClosestFloor(const sf::Vector2i& position) const; + std::vector createMinimalSpanningTree( + const sf::Vector2i& start, const float limit); + +private: + static const int GENERATE_AREA_SIZE; + static const float GENERATE_AREA_RANGE; + + World& mWorld; + Pathfinder& mPathfinder; + /// Contains values of all tiles that have yet been generated. + array mTiles; + /// Stores where tiles have already been generated. + std::map > mGenerated; + /// Perlin noise used for tile generation. + SimplexNoise mTileNoise; + /// Perlin noise used for character placement. + SimplexNoise mCharacterNoise; +}; + +#endif /* DG_GENERATOR_H_ */ diff --git a/source/sprites/Tile.h b/source/sprites/Tile.h index 262641f..2088701 100644 --- a/source/sprites/Tile.h +++ b/source/sprites/Tile.h @@ -16,8 +16,8 @@ class Tile : public Rectangle { public: enum class Type : char { - FLOOR, - WALL + WALL, + FLOOR }; public: