From 916050153a0080386b0ea12e7cdf2ba3d876214b Mon Sep 17 00:00:00 2001 From: Maximilian Giller Date: Sat, 10 Jun 2023 14:48:16 +0200 Subject: [PATCH] Implemented Level concept and scaffolding for map simulation --- CMakeLists.txt | 36 +++++++++++- src/config.h | 5 ++ src/game/game.cpp | 31 +++++++++- src/game/game.h | 9 +++ src/game/level/level_config.hpp | 28 +++++++++ src/game/level/level_loader.cpp | 39 +++++++++++++ src/game/level/level_loader.hpp | 17 ++++++ src/game/physics/map_player.cpp | 1 + src/game/physics/map_player.hpp | 17 ++++++ src/game/physics/map_simulation.cpp | 91 +++++++++++++++++++++++++++++ src/game/physics/map_simulation.hpp | 35 +++++++++++ src/game/player/player.cpp | 11 +++- src/game/player/player.hpp | 10 +++- src/game/player/player_spawner.cpp | 28 ++++++++- src/game/player/player_spawner.hpp | 8 +++ src/levels.hpp | 14 +++++ src/main.cpp | 7 ++- 17 files changed, 375 insertions(+), 12 deletions(-) create mode 100644 src/game/level/level_config.hpp create mode 100644 src/game/level/level_loader.cpp create mode 100644 src/game/level/level_loader.hpp create mode 100644 src/game/physics/map_player.cpp create mode 100644 src/game/physics/map_player.hpp create mode 100644 src/game/physics/map_simulation.cpp create mode 100644 src/game/physics/map_simulation.hpp create mode 100644 src/levels.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 456e4ff..deb6c15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,10 +57,42 @@ set(SOURCES src/game/camera/tracking_area.h src/game/camera/tracking_view_options.hpp src/game/collectables/environment_collectable.cpp - src/game/collectables/environment_collectable.hpp src/sprites/texture_manager.cpp src/sprites/texture_manager.hpp src/sprites/sprite_sheet.cpp src/sprites/sprite_sheet.hpp src/sprites/animated_sprite.cpp src/sprites/animated_sprite.hpp src/sprites/single_sprite.cpp src/sprites/single_sprite.hpp src/texture_config.h src/sprites/configs/sprite_config.hpp src/sprites/configs/sheet_config.hpp src/sprites/configs/animation_config.hpp src/sprites/versatile_sprite.cpp src/sprites/versatile_sprite.hpp src/sprites/sprite.hpp src/sprites/sprite_factory.cpp src/sprites/sprite_factory.hpp src/input_config.h src/game/input/button_config.hpp src/game/input/game_action.hpp src/game/input/button_config_factory.cpp src/game/input/button_config_factory.hpp src/game/input/game_action_config.hpp src/game/input/gamepad_buttons.hpp) + src/game/collectables/environment_collectable.hpp + src/sprites/texture_manager.cpp + src/sprites/texture_manager.hpp + src/sprites/sprite_sheet.cpp + src/sprites/sprite_sheet.hpp + src/sprites/animated_sprite.cpp + src/sprites/animated_sprite.hpp + src/sprites/single_sprite.cpp + src/sprites/single_sprite.hpp + src/texture_config.h + src/sprites/configs/sprite_config.hpp + src/sprites/configs/sheet_config.hpp + src/sprites/configs/animation_config.hpp + src/sprites/versatile_sprite.cpp + src/sprites/versatile_sprite.hpp + src/sprites/sprite.hpp + src/sprites/sprite_factory.cpp + src/sprites/sprite_factory.hpp + src/input_config.h + src/game/input/button_config.hpp + src/game/input/game_action.hpp + src/game/input/button_config_factory.cpp + src/game/input/button_config_factory.hpp + src/game/input/game_action_config.hpp + src/game/input/gamepad_buttons.hpp + src/game/physics/map_simulation.cpp + src/game/physics/map_simulation.hpp + src/game/physics/map_player.cpp + src/game/physics/map_player.hpp + src/game/level/level_config.hpp + src/game/level/level_loader.cpp + src/game/level/level_loader.hpp + src/levels.hpp) set(PHYSICS_00_SOURCES - src/prototypes/physics_00.cpp) + src/prototypes/physics_00.cpp) set(MATH_00_SOURCES src/prototypes/math_00.cpp) diff --git a/src/config.h b/src/config.h index 637008e..d9025dd 100644 --- a/src/config.h +++ b/src/config.h @@ -27,6 +27,11 @@ #define DEF_TV_MAX_VIEW_SIZE sf::Vector2f(0, 0) #define DEF_TV_VIEW_SIZE_PADDING sf::Vector2f(0.5f, 0.5f) +// Simulations +#define MAPSIM_PLAYER_RADIUS 2.f +#define MAPSIM_VELOCITY_ITERATIONS 6 +#define MAPSIM_POSITION_ITERATIONS 2 + // Directions #define DIRECTION_HARD_ACTIVATION_THRESHOLD 0.1f diff --git a/src/game/game.cpp b/src/game/game.cpp index 59e782d..720392b 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -3,10 +3,15 @@ #include #include "game.h" +#include "level/level_loader.hpp" +#include "physics/map_simulation.hpp" +#include "../debug/grid_debug_layer.h" +#include "player/player_spawner.hpp" Game::Game(std::shared_ptr window) : window(std::move(window)), gameObjects(), - views() + views(), + loadedLevelConfig() { } @@ -85,6 +90,11 @@ void Game::update() } InputMapper::getInstance()->updateIdentities(); + + if (isLevelLoaded()) + { + MapSimulation::getInstance()->updateSimulation(); + } } std::shared_ptr Game::getInstance() @@ -113,3 +123,22 @@ void Game::registerView(TrackingView *view) { views.push_back(view); } + +void Game::clearGameObjects() +{ + for (auto &gameObject: gameObjects) + { + delete gameObject; + } + gameObjects.clear(); +} + +void Game::setLevel(LevelConfig levelConfig) +{ + loadedLevelConfig = std::move(levelConfig); +} + +bool Game::isLevelLoaded() const +{ + return loadedLevelConfig.isValid(); +} diff --git a/src/game/game.h b/src/game/game.h index 616abab..e4cb97f 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -7,6 +7,7 @@ #include "game_object.h" #include "input/input_mapper.h" #include "camera/tracking_view.h" +#include "level/level_config.hpp" class TrackingView; @@ -24,6 +25,12 @@ public: void exit(); + void clearGameObjects(); + + void setLevel(LevelConfig levelConfig); + + bool isLevelLoaded() const; + void addGameObject(GameObject *gameObject); void registerView(TrackingView *view); @@ -34,6 +41,8 @@ private: static inline std::shared_ptr singletonInstance = nullptr; std::vector gameObjects; + LevelConfig loadedLevelConfig; + void drawFrame(); void update(); diff --git a/src/game/level/level_config.hpp b/src/game/level/level_config.hpp new file mode 100644 index 0000000..4d4d0c8 --- /dev/null +++ b/src/game/level/level_config.hpp @@ -0,0 +1,28 @@ +#ifndef HOLESOME_LEVEL_CONFIG_HPP +#define HOLESOME_LEVEL_CONFIG_HPP + + +#include +#include +#include + +struct LevelConfig +{ + std::string name; + sf::Vector2f worldMapSize = {}; + std::vector playerSpawnPoints = {}; + + LevelConfig(std::string name, const sf::Vector2f &worldMapSize, + const std::vector &playerSpawnPoints) + : name(std::move(name)), worldMapSize(worldMapSize), playerSpawnPoints(playerSpawnPoints) + { } + + LevelConfig() = default; + + bool isValid() const { + return !name.empty(); + } +}; + + +#endif //HOLESOME_LEVEL_CONFIG_HPP diff --git a/src/game/level/level_loader.cpp b/src/game/level/level_loader.cpp new file mode 100644 index 0000000..e81b2bf --- /dev/null +++ b/src/game/level/level_loader.cpp @@ -0,0 +1,39 @@ +#include "level_loader.hpp" +#include "../game.h" +#include "../physics/map_simulation.hpp" +#include "../../debug/grid_debug_layer.h" +#include "../player/player_spawner.hpp" +#include "../../levels.hpp" + +void LevelLoader::loadLevel(LevelConfig levelConfig) +{ + Game::getInstance()->clearGameObjects(); + + LOG(INFO) << "Loading level '" << levelConfig.name << "' ..."; + + Game::getInstance()->setLevel(levelConfig); + MapSimulation::getInstance()->resetMap(levelConfig.worldMapSize); + + // Add basic game objects + if (DEVELOPER_MODE) + { + Game::getInstance()->addGameObject(new GridDebugLayer(0, 50, 0, 50)); + } + + Game::getInstance()->addGameObject(new TrackingView()); + Game::getInstance()->addGameObject(new PlayerSpawner(levelConfig.playerSpawnPoints)); + + LOG(INFO) << "Finished loading level '" << levelConfig.name << "'."; +} + +void LevelLoader::loadLevel(const std::string &levelName) +{ + // Does level exist? + if (!LEVELS.contains(levelName)) + { + LOG(ERROR) << "Level '" << levelName << "' not found. Could not load it."; + throw std::invalid_argument("Could not load level."); + } + + LevelLoader::loadLevel(LEVELS.at(levelName)); +} diff --git a/src/game/level/level_loader.hpp b/src/game/level/level_loader.hpp new file mode 100644 index 0000000..8a62374 --- /dev/null +++ b/src/game/level/level_loader.hpp @@ -0,0 +1,17 @@ +#ifndef HOLESOME_LEVEL_LOADER_HPP +#define HOLESOME_LEVEL_LOADER_HPP + + +#include +#include "level_config.hpp" + +class LevelLoader +{ +public: + static void loadLevel(LevelConfig levelConfig); + + static void loadLevel(const std::string &levelName); +}; + + +#endif //HOLESOME_LEVEL_LOADER_HPP diff --git a/src/game/physics/map_player.cpp b/src/game/physics/map_player.cpp new file mode 100644 index 0000000..38876c7 --- /dev/null +++ b/src/game/physics/map_player.cpp @@ -0,0 +1 @@ +#include "map_player.hpp" diff --git a/src/game/physics/map_player.hpp b/src/game/physics/map_player.hpp new file mode 100644 index 0000000..15c7fce --- /dev/null +++ b/src/game/physics/map_player.hpp @@ -0,0 +1,17 @@ +#ifndef HOLESOME_MAP_PLAYER_HPP +#define HOLESOME_MAP_PLAYER_HPP + + +#include +#include "../player/player.hpp" + +struct MapPlayer +{ + Player *player; + b2Body *body; + + MapPlayer(Player *player, b2Body *body) : player(player), body(body) {} +}; + + +#endif //HOLESOME_MAP_PLAYER_HPP diff --git a/src/game/physics/map_simulation.cpp b/src/game/physics/map_simulation.cpp new file mode 100644 index 0000000..cfd0173 --- /dev/null +++ b/src/game/physics/map_simulation.cpp @@ -0,0 +1,91 @@ +#include "map_simulation.hpp" +#include "../../config.h" + +MapSimulation::MapSimulation() +{ + mapPlayersById = std::map>(); +} + +std::shared_ptr MapSimulation::getInstance() +{ + if (singletonInstance == nullptr) + { + singletonInstance = std::make_shared(); + } + return singletonInstance; +} + +void MapSimulation::updateSimulation() +{ + // Get player positions + for (auto &mapPlayer: mapPlayersById) + { + auto player = mapPlayer.second->player; + auto body = mapPlayer.second->body; + + auto coordinates = player->coordinates->world(); + b2Vec2 playerPosition = b2Vec2(coordinates.x, coordinates.y); + body->SetTransform(playerPosition, 0); + } + + world->Step(FRAME_TIME.asSeconds(), MAPSIM_VELOCITY_ITERATIONS, MAPSIM_POSITION_ITERATIONS); + + // Update player positions + for (auto &mapPlayer: mapPlayersById) + { + auto player = mapPlayer.second->player; + auto body = mapPlayer.second->body; + + b2Vec2 playerPosition = body->GetPosition(); + player->coordinates->set(sf::Vector2f(playerPosition.x, playerPosition.y)); + } +} + +void MapSimulation::resetMap(sf::Vector2f worldMapSize) +{ + // No gravity, since this a top-down view of the map + world = std::make_shared(b2Vec2(0.0f, 0.0f)); + mapPlayersById.clear(); + + // Create map borders + constructSquareObstacle(-1, 0, 0, worldMapSize.y); + constructSquareObstacle(0, -1, worldMapSize.x, 0); + constructSquareObstacle(worldMapSize.x, 0, worldMapSize.x + 1, worldMapSize.y); + constructSquareObstacle(0, worldMapSize.y, worldMapSize.x, worldMapSize.y + 1); +} + +void MapSimulation::constructSquareObstacle(float minX, float minY, float maxX, float maxY) +{ + b2BodyDef bodyDef; + bodyDef.type = b2_staticBody; + bodyDef.position.Set((maxX - minX) / 2.f, (maxY - minY) / 2.f); + b2Body *body = world->CreateBody(&bodyDef); + + b2PolygonShape shape; + shape.SetAsBox(maxX - minX, maxY - minY); + + b2FixtureDef fixtureDef; + fixtureDef.shape = &shape; + fixtureDef.density = 1.0f; + + body->CreateFixture(&fixtureDef); +} + +void MapSimulation::addPlayer(Player *player) +{ + b2BodyDef bodyDef; + bodyDef.type = b2_kinematicBody; + bodyDef.position.Set(player->getTrackablePosition().x, player->getTrackablePosition().y); + b2Body *body = world->CreateBody(&bodyDef); + + b2CircleShape shape; + shape.m_radius = MAPSIM_PLAYER_RADIUS; + shape.m_p.Set(0, 0); + + b2FixtureDef fixtureDef; + fixtureDef.shape = &shape; + fixtureDef.density = 1.0f; + + body->CreateFixture(&fixtureDef); + mapPlayersById[player->getPlayerId()] = std::make_shared(player, body); +} diff --git a/src/game/physics/map_simulation.hpp b/src/game/physics/map_simulation.hpp new file mode 100644 index 0000000..19bb26e --- /dev/null +++ b/src/game/physics/map_simulation.hpp @@ -0,0 +1,35 @@ +#ifndef HOLESOME_MAP_SIMULATION_HPP +#define HOLESOME_MAP_SIMULATION_HPP + +#include +#include +#include +#include "../player/player.hpp" +#include "map_player.hpp" + +class MapSimulation +{ +public: + MapSimulation(); + + void updateSimulation(); + + void resetMap(sf::Vector2f worldMapSize); + + static std::shared_ptr getInstance(); + + void addPlayer(Player *player); + + +private: + static inline std::shared_ptr singletonInstance = nullptr; + + std::shared_ptr world; + std::map> mapPlayersById; + + void constructSquareObstacle(float minX, float minY, float maxX, float maxY); + +}; + + +#endif //HOLESOME_MAP_SIMULATION_HPP diff --git a/src/game/player/player.cpp b/src/game/player/player.cpp index 6986dc6..ab7684e 100644 --- a/src/game/player/player.cpp +++ b/src/game/player/player.cpp @@ -4,9 +4,11 @@ #include Player::Player(std::shared_ptr assignedInput, const std::string &skinRessourceName, - WorldCoordinates initCoordinates) + sf::Vector2f spawnPosition) { - coordinates->set(initCoordinates); + playerId = playerCreationCounter++; + this->spawnPosition = spawnPosition; + coordinates->set(spawnPosition); input = std::move(assignedInput); @@ -54,3 +56,8 @@ TrackableState Player::getTrackableState() const return TrackableState::END_TRACKING; } } + +int Player::getPlayerId() const +{ + return playerId; +} diff --git a/src/game/player/player.hpp b/src/game/player/player.hpp index d48014e..1b11fa2 100644 --- a/src/game/player/player.hpp +++ b/src/game/player/player.hpp @@ -9,7 +9,8 @@ class Player : public GameObject, public ITrackable { public: - Player(std::shared_ptr assignedInput, const std::string& skinRessourceName, WorldCoordinates initCoordinates); + Player(std::shared_ptr assignedInput, const std::string &skinRessourceName, + sf::Vector2f initCoordinates); ~Player(); @@ -23,9 +24,16 @@ public: float speed = 30.0f; + int getPlayerId() const; + private: std::shared_ptr input; float width = 50; + + sf::Vector2f spawnPosition; + + int playerId; + static inline int playerCreationCounter = 0; }; diff --git a/src/game/player/player_spawner.cpp b/src/game/player/player_spawner.cpp index 8503730..52b26f7 100644 --- a/src/game/player/player_spawner.cpp +++ b/src/game/player/player_spawner.cpp @@ -2,13 +2,35 @@ #include "player.hpp" #include "../../texture_config.h" +PlayerSpawner::PlayerSpawner(const std::vector &spawnPoints) +{ + this->spawnPoints = spawnPoints; + + // Create player for existing input identities + for (auto &inputIdentity: InputMapper::getInstance()->getInputIdentities()) + { + spawnPlayer(inputIdentity); + } +} + void PlayerSpawner::update() { // Create player for new input identities for (auto &inputIdentity: InputMapper::getInstance()->newInputIdentities) { - auto player = new Player(inputIdentity, PLAYER_SKIN, {0, 0}); - Game::getInstance()->addGameObject(player); - Game::getInstance()->views[0]->addTrackable(player); + spawnPlayer(inputIdentity); } } + +void PlayerSpawner::spawnPlayer(const std::shared_ptr &inputIdentity) +{ + // Get proper Spawn point, if available + sf::Vector2f spawn = spawnPoints[nextSpawnPointIndex]; + nextSpawnPointIndex = static_cast((nextSpawnPointIndex + 1) % spawnPoints.size()); + + auto player = new Player(inputIdentity, PLAYER_SKIN, spawn); + + Game::getInstance()->addGameObject(player); + // TODO: Better view handling + Game::getInstance()->views[0]->addTrackable(player); +} diff --git a/src/game/player/player_spawner.hpp b/src/game/player/player_spawner.hpp index 9bcea14..9a95f9c 100644 --- a/src/game/player/player_spawner.hpp +++ b/src/game/player/player_spawner.hpp @@ -8,7 +8,15 @@ class PlayerSpawner : public GameObject { public: + PlayerSpawner(const std::vector& spawnPoints); + void update() override; + + void spawnPlayer(const std::shared_ptr &inputIdentity); + +private: + std::vector spawnPoints; + int nextSpawnPointIndex = 0; }; diff --git a/src/levels.hpp b/src/levels.hpp new file mode 100644 index 0000000..8e7e25e --- /dev/null +++ b/src/levels.hpp @@ -0,0 +1,14 @@ +#ifndef HOLESOME_LEVELS_HPP +#define HOLESOME_LEVELS_HPP + +#include +#include +#include "game/level/level_config.hpp" + +#define INITIAL_LEVEL "default" + +std::map const LEVELS = { + {"default", LevelConfig("Default", {25, 25}, {{1, 1}})} +}; + +#endif //HOLESOME_LEVELS_HPP diff --git a/src/main.cpp b/src/main.cpp index 1ae5e1a..99b8eaf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,8 @@ #include "game/player/player_spawner.hpp" #include "sprites/texture_manager.hpp" #include "texture_config.h" +#include "game/level/level_loader.hpp" +#include "levels.hpp" void loadAllTextures(); @@ -26,9 +28,8 @@ void runGame() LOG(INFO) << "Starting game ..."; auto game = GameFactory::createWindowed("Holesome"); - game->addGameObject(new GridDebugLayer(0, 50, 0, 50)); - game->addGameObject(new TrackingView()); - game->addGameObject(new PlayerSpawner()); + // Load initial level + LevelLoader::loadLevel(INITIAL_LEVEL); game->run();