File BiomeGenerator.cpp
File List > source > Worlds > BiomeGenerator.cpp
Go to the documentation of this file
#include "BiomeGenerator.hpp"
#include "Agents/AgentLibary.hpp"
#include <cmath>
#include <tuple>
#include <queue>
using namespace group6;
using namespace cse491;
using std::vector;
BiomeGenerator::BiomeGenerator(BiomeType biome, unsigned int width, unsigned int height, unsigned int seed) : biome(biome), width(width), height(height), seed(seed) {
if (biome == BiomeType::Maze) {
setTiles(floor_id, wall_id);
} else if (biome == BiomeType::Grasslands) {
setTiles(grass_id, dirt_id);
}
else if (biome == BiomeType::Ocean) {
setTiles(water_id, sand_id);
}
perlinNoise = PerlinNoise(seed);
grid.Resize(width, height);
}
void BiomeGenerator::setWorld(WorldBase *world) {
worldPtr = world;
}
void BiomeGenerator::generate() {
size_t tile1 = tiles[0];
size_t tile2 = tiles[1];
for (unsigned int y = 0; y < height; y++) {
for (unsigned int x = 0; x < width; x++) {
// Give 5x5 clear space in top left corner
// TODO: Replace with putting player in valid room instead of 0,0
if (x > 4 || y > 4) {
const double val = perlinNoise.noise2D(x * frequency / width, y * frequency / height);
grid.At(x, y) = val < 0 ? tile1 : tile2;
}
}
}
if (biome == BiomeType::Maze) {
placeSpecialTiles(tile1, spike_id, 0.05); // Placing spike tiles
placeSpecialTiles(tile1, tar_id, 0.08); // Placing tar tiles
placeTileRandom(key_id, floor_id); // placing key tile
vector<GridPosition> path = clearPath();
applyPathToGrid(path);
placeDoorTile(door_id); // placing door tile
grid.At(keyLocation) = key_id;
}
if (biome == BiomeType::Grasslands) {
placeTileRandom(hole_id, grass_id); // placing hole tile
}
if (biome == BiomeType::Ocean) {
oceanHandler();
placeTileRandom(hole_id, sand_id);
}
}
void BiomeGenerator::placeTileRandom(const size_t &tile, const size_t &spawnTile) {
bool counter = false;
while (!counter) {
int random_x = (int)worldPtr->GetRandom(width / 2.0, width - 1);
int random_y = (int)worldPtr->GetRandom(height / 2.0, height - 1);
if (grid.At(random_x, random_y) == spawnTile) {
grid.At(random_x, random_y) = tile;
if (tile == key_id) {
keyLocation = GridPosition(random_x, random_y);
}
counter = true;
}
}
}
void BiomeGenerator::placeDoorTile(const size_t &doorTile) {
grid.At(2, 2) = doorTile;
}
void BiomeGenerator::placeSpecialTiles(const size_t &genericTile, const size_t &specialTile, double percentage) {
std::vector<std::pair<int, int>> floorPositions;
for (unsigned int x = 0; x < width; ++x) {
for (unsigned int y = 0; y < height; ++y) {
if (grid.At(x, y) == genericTile) {
floorPositions.emplace_back(x, y);
}
}
}
int numSpikes = (int)round((int)floorPositions.size() * percentage);
// Convert some generic floor tiles to special tiles
for (int i = 0; i < numSpikes; ++i) {
int pos = (int)round(worldPtr->GetRandom((int)floorPositions.size() - 1));
grid.At(floorPositions [pos].first, floorPositions[pos].second) = specialTile;
floorPositions.erase(floorPositions.begin() + pos);
}
}
vector<GridPosition> BiomeGenerator::clearPath() const {
vector<GridPosition> path;
GridPosition current(0, 0); // Starting point
path.push_back(current);
// Continue until we reach the KeyLocation
while (current != keyLocation) {
std::vector<GridPosition> possibleMoves;
// Always add right movement if not aligned horizontally
if (current.GetX() < keyLocation.GetX()) {
possibleMoves.push_back(current.ToRight());
}
// Add down movement if above the target and within grid bounds
if (current.GetY() < keyLocation.GetY() && current.GetY() < height - 1) {
possibleMoves.push_back(current.Below());
}
// Add up movement if below the target and within grid bounds
if (current.GetY() > keyLocation.GetY() && current.GetY() > 0) {
possibleMoves.push_back(current.Above());
}
// Randomly choose one of the possible moves
if (!possibleMoves.empty()) {
GridPosition next = possibleMoves[int(worldPtr->GetRandom(0, 2)) % possibleMoves.size()];
// Check if we have made a valid move, if so, update the path and current position
if (next != current) {
path.push_back(next);
current = next;
}
}
}
return path;
}
void BiomeGenerator::applyPathToGrid(const vector<GridPosition> &path) {
for (const GridPosition &p: path) {
grid.At(p) = floor_id;
}
}
void BiomeGenerator::saveToFile(const std::string &filename) const {
type_options_t types = type_options_t();
types.push_back(CellType{"floor", "Floor that you can easily walk over.", ' '});
types.push_back(CellType{"wall", "Impenetrable wall that you must find a way around.", '#'});
types.push_back(CellType{"spike", "Dangerous spike that resets the game.", 'X'});
types.push_back(CellType{"tar", "Slow tile that makes you take two steps to get through it", 'O'});
types.push_back(CellType{"key", "item that can be picked up to unlock door and escape maze", 'K'});
types.push_back(CellType{"door", "Door that can be walked through only with possession of key to leave maze", 'D'});
types.push_back(CellType{"grass", "Grass you can walk on.", 'M'});
types.push_back(CellType{"dirt", "Dirt you can walk on.", '~'});
types.push_back(CellType{"tree", "A tree that blocks the way.", 't'});
types.push_back(CellType{"hole", "A hole that you can fall into the maze from.", '8'});
types.push_back(CellType{"water","Water that you may be able to swim on.", 'W'});
types.push_back(CellType{"sand", "Sand you can walk on.", '-'});
grid.Write(filename, types);
}
void BiomeGenerator::setTiles(const size_t &firstTile, const size_t &secondTile) {
tiles.clear();
tiles.push_back(firstTile);
tiles.push_back(secondTile);
}
void BiomeGenerator::placeTrees() {
// Iterates through each tile in the grid with a margin of 1 tile to prevent out of bounds access
for (unsigned int y = 1; y < height - 1; ++y) {
for (unsigned int x = 1; x < width - 1; ++x) {
// Only place trees on grass tiles and ensure we have space for a 3x3 tree
if (grid.At(x, y) == grass_id &&
grid.At(x-1, y) == grass_id && grid.At(x+1, y) == grass_id &&
grid.At(x, y-1) == grass_id && grid.At(x, y+1) == grass_id &&
grid.At(x-1, y-1) == grass_id && grid.At(x+1, y-1) == grass_id &&
grid.At(x-1, y+1) == grass_id && grid.At(x+1, y+1) == grass_id) {
// Use a random chance to place a tree
if (worldPtr->GetRandom( 100) < 10) { // 10% chance to place a tree
// Place a 3x3 block of tree tile characters for the tree
for (int i = -1; i <= 1; ++i) {
for (int j = -1; j <= 1; ++j) {
grid.At(x + i, y + j) = tree_id;
}
}
}
}
}
}
}
void BiomeGenerator::oceanHandler(){
for (unsigned int y = 1; y < height - 1; ++y) {
for (unsigned int x = 1; x < width - 1; ++x) {
if (grid.At(x, y) == water_id) {
if (worldPtr->GetRandom(100) < 15) {
for (int i = -1; i <= 1; ++i) {
for (int j = -1; j <= 1; ++j) {
if (x + i > 0 && x + i < width - 1 && y + j > 0 && y + j < height - 1) {
grid.At(x + i, y + j) = sand_id;
}
}
}
}
}
}
}
}