Areas are now generated on the fly based on player position
This commit is contained in:
parent
07826336c5
commit
12048ffc8c
3 changed files with 74 additions and 9 deletions
|
@ -27,8 +27,7 @@ Game::Game(sf::RenderWindow& window) :
|
||||||
mWindow.setFramerateLimit(FPS_GOAL);
|
mWindow.setFramerateLimit(FPS_GOAL);
|
||||||
mWindow.setKeyRepeatEnabled(false);
|
mWindow.setKeyRepeatEnabled(false);
|
||||||
|
|
||||||
sf::IntRect area(-32, -32, 64, 64);
|
mGenerator.generateCurrentAreaIfNeeded(sf::Vector2f());
|
||||||
mGenerator.generateTiles(area);
|
|
||||||
mPlayer = std::shared_ptr<Player>(new Player(mWorld, mPathfinder,
|
mPlayer = std::shared_ptr<Player>(new Player(mWorld, mPathfinder,
|
||||||
mGenerator.getPlayerSpawn()));
|
mGenerator.getPlayerSpawn()));
|
||||||
mWorld.insertCharacter(mPlayer);
|
mWorld.insertCharacter(mPlayer);
|
||||||
|
@ -63,7 +62,10 @@ Game::loop() {
|
||||||
mWorld.think(elapsed);
|
mWorld.think(elapsed);
|
||||||
|
|
||||||
mWorld.step(elapsed);
|
mWorld.step(elapsed);
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
|
||||||
|
mGenerator.generateCurrentAreaIfNeeded(mPlayer->getPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "Generator.h"
|
#include "Generator.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -22,6 +23,9 @@
|
||||||
/// Seed for usage with simplexnoise.h
|
/// Seed for usage with simplexnoise.h
|
||||||
uint8_t perm[512];
|
uint8_t perm[512];
|
||||||
|
|
||||||
|
const int Generator::GENERATE_AREA_SIZE = 4;
|
||||||
|
const float Generator::GENERATE_AREA_RANGE = 4.0f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Amount of tiles extra to generate, to get consistent walls
|
* Amount of tiles extra to generate, to get consistent walls
|
||||||
* across multiple generateTiles calls for bordering areas.
|
* across multiple generateTiles calls for bordering areas.
|
||||||
|
@ -45,6 +49,55 @@ Generator::Generator(World& world, Pathfinder& pathfinder) :
|
||||||
perm[i] = distribution(mersenne);
|
perm[i] = distribution(mersenne);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates tiles near position (maximum distance is determined by
|
||||||
|
* GENERATE_AREA_SIZE and GENERATE_AREA_RANGE).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& position) {
|
||||||
|
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<sf::Vector2i, float, decltype(compare)> open(compare);
|
||||||
|
std::set<sf::Vector2i, decltype(compare)> closed(compare);
|
||||||
|
|
||||||
|
sf::Vector2i start((int) floor(position.x / Tile::TILE_SIZE.x),
|
||||||
|
(int) floor(position.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<sf::Vector2i, float>& left,
|
||||||
|
const std::pair<sf::Vector2i, float>& 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;
|
||||||
|
generateTiles(sf::IntRect(current * GENERATE_AREA_SIZE -
|
||||||
|
sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2,
|
||||||
|
sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE)));
|
||||||
|
}
|
||||||
|
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.
|
* Fill world with procedurally generated tiles.
|
||||||
*
|
*
|
||||||
|
@ -87,7 +140,7 @@ Generator::generateTiles(const sf::IntRect& area) {
|
||||||
}
|
}
|
||||||
generateAreas(filtered, area, sf::Vector2f(area.left, area.top));
|
generateAreas(filtered, area, sf::Vector2f(area.left, area.top));
|
||||||
mPathfinder.generatePortals();
|
mPathfinder.generatePortals();
|
||||||
mGenerated = filtered;
|
mTiles = filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<sf::Vector2f>
|
std::vector<sf::Vector2f>
|
||||||
|
@ -228,12 +281,16 @@ Generator::findClosestFloor(const sf::Vector2i& position) const {
|
||||||
|
|
||||||
open.insert(makePair(start));
|
open.insert(makePair(start));
|
||||||
while (!open.empty()) {
|
while (!open.empty()) {
|
||||||
const sf::Vector2i& current = open.begin()->first;
|
auto intComp = [](const std::pair<sf::Vector2i, float>& left,
|
||||||
|
const std::pair<sf::Vector2i, float>& right) {
|
||||||
|
return left.second < right.second;
|
||||||
|
};
|
||||||
|
sf::Vector2i current = std::min_element(open.begin(), open.end(), intComp)->first;
|
||||||
open.erase(current);
|
open.erase(current);
|
||||||
closed.insert(current);
|
closed.insert(current);
|
||||||
if (mGenerated.count(current.x) != 0 &&
|
if (mTiles.count(current.x) != 0 &&
|
||||||
mGenerated.at(current.x).count(current.y) != 0 &&
|
mTiles.at(current.x).count(current.y) != 0 &&
|
||||||
mGenerated.at(current.x).at(current.y) == Tile::Type::FLOOR)
|
mTiles.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())
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Pathfinder;
|
||||||
class Generator {
|
class Generator {
|
||||||
public:
|
public:
|
||||||
explicit Generator(World& world, Pathfinder& pathfinder);
|
explicit Generator(World& world, Pathfinder& pathfinder);
|
||||||
void generateTiles(const sf::IntRect& area);
|
void generateCurrentAreaIfNeeded(const sf::Vector2f& position);
|
||||||
sf::Vector2f getPlayerSpawn() const;
|
sf::Vector2f getPlayerSpawn() const;
|
||||||
std::vector<sf::Vector2f> getEnemySpawns(const sf::IntRect& area) const;
|
std::vector<sf::Vector2f> getEnemySpawns(const sf::IntRect& area) const;
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ private:
|
||||||
typedef std::map<int, std::map<int, type> > array;
|
typedef std::map<int, std::map<int, type> > array;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void generateTiles(const sf::IntRect& area);
|
||||||
sf::Vector2i findClosestFloor(const sf::Vector2i& position) const;
|
sf::Vector2i findClosestFloor(const sf::Vector2i& position) const;
|
||||||
static void fill(array& in, const sf::IntRect& area, type value);
|
static void fill(array& in, const sf::IntRect& area, type value);
|
||||||
static void filterWalls(const array& in, array& out, int x, int y,
|
static void filterWalls(const array& in, array& out, int x, int y,
|
||||||
|
@ -36,13 +37,18 @@ private:
|
||||||
const sf::Vector2f& offset) const;
|
const sf::Vector2f& offset) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int GENERATE_AREA_SIZE;
|
||||||
|
static const float GENERATE_AREA_RANGE;
|
||||||
static const int MARGIN;
|
static const int MARGIN;
|
||||||
static const float LAYER_TILES;
|
static const float LAYER_TILES;
|
||||||
static const float LAYER_ENEMIES;
|
static const float LAYER_ENEMIES;
|
||||||
|
|
||||||
World& mWorld;
|
World& mWorld;
|
||||||
Pathfinder& mPathfinder;
|
Pathfinder& mPathfinder;
|
||||||
array mGenerated;
|
/// Contains values of all tiles that have yet been generated.
|
||||||
|
array mTiles;
|
||||||
|
/// Stores where tiles have already been generated.
|
||||||
|
std::map<int, std::map<int, bool> > mGenerated;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DG_GENERATOR_H_ */
|
#endif /* DG_GENERATOR_H_ */
|
||||||
|
|
Reference in a new issue