Implemented procedural world generation
This commit is contained in:
parent
f50a346e22
commit
851e591c3c
11 changed files with 223 additions and 7 deletions
|
@ -138,7 +138,7 @@ set(SOURCES
|
||||||
src/typography/font_manager.cpp
|
src/typography/font_manager.cpp
|
||||||
src/typography/font_manager.hpp
|
src/typography/font_manager.hpp
|
||||||
src/screens/winner_screen.cpp
|
src/screens/winner_screen.cpp
|
||||||
src/screens/winner_screen.hpp src/screens/screen.cpp src/screens/screen.hpp src/screens/join_screen.cpp src/screens/join_screen.hpp)
|
src/screens/winner_screen.hpp src/screens/screen.cpp src/screens/screen.hpp src/screens/join_screen.cpp src/screens/join_screen.hpp src/game/level/level_generator.cpp src/game/level/level_generator.hpp src/screens/loading_screen.cpp src/screens/loading_screen.hpp)
|
||||||
|
|
||||||
set(PHYSICS_00_SOURCES
|
set(PHYSICS_00_SOURCES
|
||||||
src/prototypes/physics_00.cpp)
|
src/prototypes/physics_00.cpp)
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
// World
|
// World
|
||||||
#define WORLD_GRAVITY b2Vec2(0.f, -9.8f)
|
#define WORLD_GRAVITY b2Vec2(0.f, -9.8f)
|
||||||
#define SKY_HEIGHT_SCALE 2.f
|
#define SKY_HEIGHT_SCALE 5.f
|
||||||
#define CONSIDER_COLLECTABLE_DEPTH_MOVEMENT false // Might cost perfomance and is currently not in use
|
#define CONSIDER_COLLECTABLE_DEPTH_MOVEMENT false // Might cost perfomance and is currently not in use
|
||||||
|
|
||||||
// FPS
|
// FPS
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
#define DEF_TV_MIN_VIEW_SIZE sf::Vector2f(6, 6) * WORLD_TO_ISO_SCALE
|
#define DEF_TV_MIN_VIEW_SIZE sf::Vector2f(6, 6) * WORLD_TO_ISO_SCALE
|
||||||
#define DEF_TV_MAX_VIEW_SIZE sf::Vector2f(0, 0)
|
#define DEF_TV_MAX_VIEW_SIZE sf::Vector2f(0, 0)
|
||||||
#define DEF_TV_IS_ABSOLUTE_VIEW_SIZE_PADDING false
|
#define DEF_TV_IS_ABSOLUTE_VIEW_SIZE_PADDING false
|
||||||
#define DEF_TV_VIEW_SIZE_PADDING sf::Vector2f(3.5f, 3.5f)
|
#define DEF_TV_VIEW_SIZE_PADDING sf::Vector2f(2.f, 2.f)
|
||||||
#define MP_VIEW_ADD_NEW_PLAYERS true
|
#define MP_VIEW_ADD_NEW_PLAYERS true
|
||||||
#define MP_VIEW_REMOVE_DISCONNECTED_PLAYERS true
|
#define MP_VIEW_REMOVE_DISCONNECTED_PLAYERS true
|
||||||
#define MP_VIEW_BORDER_COLOR sf::Color::Black
|
#define MP_VIEW_BORDER_COLOR sf::Color::Black
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "player/player_collection.hpp"
|
#include "player/player_collection.hpp"
|
||||||
#include "../screens/winner_screen.hpp"
|
#include "../screens/winner_screen.hpp"
|
||||||
#include "../screens/join_screen.hpp"
|
#include "../screens/join_screen.hpp"
|
||||||
|
#include "level/level_generator.hpp"
|
||||||
|
#include "../screens/loading_screen.hpp"
|
||||||
|
|
||||||
Game::Game(std::shared_ptr<sf::RenderWindow> window) : window(std::move(window))
|
Game::Game(std::shared_ptr<sf::RenderWindow> window) : window(std::move(window))
|
||||||
{
|
{
|
||||||
|
@ -223,3 +225,26 @@ void Game::showJoinScreen()
|
||||||
addGameObject(GlobalLayer::getInstance());
|
addGameObject(GlobalLayer::getInstance());
|
||||||
addGameObject(PlayerCollection::getInstance());
|
addGameObject(PlayerCollection::getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::generateNewLevel()
|
||||||
|
{
|
||||||
|
showLoadingScreen("Generating new level ...");
|
||||||
|
|
||||||
|
LevelConfig newLevel = LevelGenerator::generateLevel("Procedural Level");
|
||||||
|
LevelLoader::loadLevel(newLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::showLoadingScreen(const std::string &message)
|
||||||
|
{
|
||||||
|
GlobalLayer::getInstance()->clear();
|
||||||
|
clearGameObjects();
|
||||||
|
|
||||||
|
auto loadingScreen = std::make_shared<LoadingScreen>(message);
|
||||||
|
GlobalLayer::getInstance()->add(loadingScreen);
|
||||||
|
|
||||||
|
addGameObject(GlobalLayer::getInstance());
|
||||||
|
|
||||||
|
// Mini loop
|
||||||
|
update();
|
||||||
|
drawFrame();
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
|
|
||||||
void showJoinScreen();
|
void showJoinScreen();
|
||||||
|
|
||||||
|
void generateNewLevel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline std::shared_ptr<Game> singletonInstance = nullptr;
|
static inline std::shared_ptr<Game> singletonInstance = nullptr;
|
||||||
std::vector<std::shared_ptr<GameObject>> gameObjects = {};
|
std::vector<std::shared_ptr<GameObject>> gameObjects = {};
|
||||||
|
@ -58,6 +60,8 @@ private:
|
||||||
std::shared_ptr<Player> checkForWinner();
|
std::shared_ptr<Player> checkForWinner();
|
||||||
|
|
||||||
void handleWinning();
|
void handleWinning();
|
||||||
|
|
||||||
|
void showLoadingScreen(const std::string &message = "Loading...");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
134
src/game/level/level_generator.cpp
Normal file
134
src/game/level/level_generator.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include "level_generator.hpp"
|
||||||
|
|
||||||
|
LevelConfig LevelGenerator::generateLevel(const std::string &name)
|
||||||
|
{
|
||||||
|
int levelSize = 50;
|
||||||
|
|
||||||
|
TileMapConfig map = generateRandomMap(levelSize, levelSize);
|
||||||
|
std::vector<CollectableInLevel> collectables = generateRandomCollectables(levelSize, levelSize);
|
||||||
|
|
||||||
|
return LevelConfig(name,
|
||||||
|
120,
|
||||||
|
{
|
||||||
|
{1, 2},
|
||||||
|
{2, 1},
|
||||||
|
{0, 3},
|
||||||
|
{3, 0}
|
||||||
|
},
|
||||||
|
collectables,
|
||||||
|
{
|
||||||
|
// Blues
|
||||||
|
sf::Color(2, 100, 234),
|
||||||
|
sf::Color(2, 100, 234),
|
||||||
|
sf::Color(2, 100, 234),
|
||||||
|
sf::Color(2, 195, 234),
|
||||||
|
|
||||||
|
// Neutral
|
||||||
|
sf::Color::White,
|
||||||
|
|
||||||
|
// Browns
|
||||||
|
sf::Color(163, 128, 68),
|
||||||
|
sf::Color(100, 80, 40),
|
||||||
|
sf::Color(20, 18, 11),
|
||||||
|
sf::Color::Black
|
||||||
|
},
|
||||||
|
map
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TileMapConfig LevelGenerator::generateRandomMap(int width, int height)
|
||||||
|
{
|
||||||
|
int tileVariants = 6 * 2;
|
||||||
|
std::vector<std::vector<int>> tiles;
|
||||||
|
for (int h = 0; h < height; h++)
|
||||||
|
{
|
||||||
|
std::vector<int> row;
|
||||||
|
for (int w = 0; w < width; w++)
|
||||||
|
{
|
||||||
|
row.push_back(rand() % tileVariants);
|
||||||
|
}
|
||||||
|
tiles.push_back(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TileMapConfig("iso-tiles", tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CollectableInLevel> LevelGenerator::generateRandomCollectables(int width, int height)
|
||||||
|
{
|
||||||
|
std::vector<CollectableInLevel> collectables;
|
||||||
|
|
||||||
|
// Add rose fields
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
// Random coordinates for center of rose field with enough distance from edges
|
||||||
|
int x = rand() % int(width - 2 * roseFieldRadius) + roseFieldRadius;
|
||||||
|
int y = rand() % int(height - 2 * roseFieldRadius) + roseFieldRadius;
|
||||||
|
|
||||||
|
GridCoordinates fieldCenter = GridCoordinates(x, y);
|
||||||
|
|
||||||
|
// Add rose field by creating a dense field of roses around the center
|
||||||
|
int roseCount = rand() % 15 + 5;
|
||||||
|
for (int j = 0; j < roseCount; j++)
|
||||||
|
{
|
||||||
|
// Use cosine distribution to get a more dense field around the center
|
||||||
|
float angle = rand() % 360;
|
||||||
|
float radius = rand() % 1000 / 1000.f;
|
||||||
|
|
||||||
|
// Skew radius to avoid too dense at center
|
||||||
|
radius = pow(radius, 0.3f) * roseFieldRadius;
|
||||||
|
|
||||||
|
float xOffset = radius * cos(angle);
|
||||||
|
float yOffset = radius * sin(angle);
|
||||||
|
|
||||||
|
GridCoordinates roseCoordinates = GridCoordinates(fieldCenter.x + xOffset, fieldCenter.y + yOffset);
|
||||||
|
collectables.push_back(CollectableInLevel("rose", roseCoordinates));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place rows of lanterns
|
||||||
|
int rowCount = rand() % 3 + 2;
|
||||||
|
int heightDelta = height / (rowCount + 1);
|
||||||
|
int stepSize = 7;
|
||||||
|
for (int i = 0; i < rowCount; i++)
|
||||||
|
{
|
||||||
|
int y = (i + 1) * heightDelta;
|
||||||
|
for (int j = stepSize; j < width; j += stepSize)
|
||||||
|
{
|
||||||
|
collectables.push_back(CollectableInLevel("lantern", GridCoordinates(j, y)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place random bikes
|
||||||
|
int bikeCount = rand() % 5 + 5;
|
||||||
|
for (int i = 0; i < bikeCount; i++)
|
||||||
|
{
|
||||||
|
int x = rand() % width;
|
||||||
|
int y = rand() % height;
|
||||||
|
collectables.push_back(CollectableInLevel("bike", GridCoordinates(x, y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place random rose bushes
|
||||||
|
int roseBushCount = rand() % 40 + 40;
|
||||||
|
for (int i = 0; i < roseBushCount; i++)
|
||||||
|
{
|
||||||
|
int x = rand() % width;
|
||||||
|
int y = rand() % height;
|
||||||
|
collectables.push_back(CollectableInLevel("rose-bush", GridCoordinates(x, y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place random stones
|
||||||
|
int stoneCount = rand() % 20 + 20;
|
||||||
|
for (int i = 0; i < stoneCount; i++)
|
||||||
|
{
|
||||||
|
int x = rand() % width;
|
||||||
|
int y = rand() % height;
|
||||||
|
collectables.push_back(CollectableInLevel("stone", GridCoordinates(x, y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place a single tree
|
||||||
|
int x = rand() % width;
|
||||||
|
int y = rand() % height;
|
||||||
|
collectables.push_back(CollectableInLevel("small-tree", GridCoordinates(x, y)));
|
||||||
|
|
||||||
|
return collectables;
|
||||||
|
}
|
21
src/game/level/level_generator.hpp
Normal file
21
src/game/level/level_generator.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef HOLESOME_LEVEL_GENERATOR_HPP
|
||||||
|
#define HOLESOME_LEVEL_GENERATOR_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include "level_config.hpp"
|
||||||
|
|
||||||
|
class LevelGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static LevelConfig generateLevel(const std::string& name);
|
||||||
|
|
||||||
|
static TileMapConfig generateRandomMap(int width, int height);
|
||||||
|
|
||||||
|
static std::vector<CollectableInLevel> generateRandomCollectables(int width, int height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const inline float roseFieldRadius = 3.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HOLESOME_LEVEL_GENERATOR_HPP
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
std::map<std::string, LevelConfig> const all_levels = {
|
std::map<std::string, LevelConfig> const all_levels = {
|
||||||
{"default", LevelConfig("Default",
|
{"default", LevelConfig("Default",
|
||||||
5,
|
120,
|
||||||
{
|
{
|
||||||
{0, 0},
|
{0, 0},
|
||||||
{18, 18},
|
{18, 18},
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../game/player/player_collection.hpp"
|
#include "../game/player/player_collection.hpp"
|
||||||
#include "../levels.hpp"
|
#include "../levels.hpp"
|
||||||
#include "../game/level/level_loader.hpp"
|
#include "../game/level/level_loader.hpp"
|
||||||
|
#include "../game/game.h"
|
||||||
|
|
||||||
JoinScreen::JoinScreen()
|
JoinScreen::JoinScreen()
|
||||||
{
|
{
|
||||||
|
@ -39,7 +40,7 @@ void JoinScreen::update()
|
||||||
if (input->isPerformingAction(GameAction::CONFIRM))
|
if (input->isPerformingAction(GameAction::CONFIRM))
|
||||||
{
|
{
|
||||||
// Start game
|
// Start game
|
||||||
LevelLoader::loadLevel(INITIAL_LEVEL);
|
Game::getInstance()->generateNewLevel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/screens/loading_screen.cpp
Normal file
17
src/screens/loading_screen.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <SFML/Graphics/Text.hpp>
|
||||||
|
#include "loading_screen.hpp"
|
||||||
|
#include "../typography/font_manager.hpp"
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
|
LoadingScreen::LoadingScreen(const std::string &message)
|
||||||
|
{
|
||||||
|
auto text = std::make_shared<sf::Text>();
|
||||||
|
text->setString(message);
|
||||||
|
text->setFont(*FontManager::getInstance()->getDefaultFont());
|
||||||
|
text->setCharacterSize(24);
|
||||||
|
text->setStyle(sf::Text::Italic);
|
||||||
|
text->setFillColor(sf::Color::White);
|
||||||
|
text->setPosition(REFERENCE_SIZE.x / 2.f - text->getGlobalBounds().width / 2.f,
|
||||||
|
REFERENCE_SIZE.y / 2.f - text->getGlobalBounds().height / 2.f);
|
||||||
|
add(text);
|
||||||
|
}
|
14
src/screens/loading_screen.hpp
Normal file
14
src/screens/loading_screen.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef HOLESOME_LOADING_SCREEN_HPP
|
||||||
|
#define HOLESOME_LOADING_SCREEN_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include "screen.hpp"
|
||||||
|
|
||||||
|
class LoadingScreen : public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LoadingScreen(const std::string &message = "Loading...");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HOLESOME_LOADING_SCREEN_HPP
|
|
@ -9,7 +9,7 @@
|
||||||
#include "sprites/tiling/tileset_config.hpp"
|
#include "sprites/tiling/tileset_config.hpp"
|
||||||
#include "sprites/configs/masked_sprite_config.hpp"
|
#include "sprites/configs/masked_sprite_config.hpp"
|
||||||
|
|
||||||
#define PLAYER_SKINS std::vector<std::string> { "player-0", "player-1", "player-2", "player-3" }
|
#define PLAYER_SKINS std::vector<std::string> { "player", "player-1", "player-2", "player-3" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All textures used in the game.
|
* All textures used in the game.
|
||||||
|
@ -91,7 +91,7 @@ std::map<std::string, MaskedSpriteConfig> const all_masked_sprites = {
|
||||||
* The key is the name of the tileset, the value is the tileset config.
|
* The key is the name of the tileset, the value is the tileset config.
|
||||||
*/
|
*/
|
||||||
std::map<std::string, TileSetConfig> const all_tilesets = {
|
std::map<std::string, TileSetConfig> const all_tilesets = {
|
||||||
{"iso-tiles", TileSetConfig("custom-grass-tiles", {0, 1, 2, 3, 4, 5})}
|
{"iso-tiles", TileSetConfig("custom-grass-tiles", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //HOLESOME_TEXTURE_CONFIG_H
|
#endif //HOLESOME_TEXTURE_CONFIG_H
|
||||||
|
|
Loading…
Reference in a new issue