Improved map wallout, fixed spawned player in wall glitch and now actually rendering collectables. Player handling has also been reworked

This commit is contained in:
Maximilian Giller 2023-06-13 21:59:50 +02:00
parent d3e6e35c9b
commit 414f3b79fc
27 changed files with 345 additions and 111 deletions

View file

@ -52,8 +52,6 @@ set(SOURCES
src/game/camera/ITrackable.h src/game/camera/ITrackable.h
src/game/input/input_identity.h src/game/input/input_identity.h
src/utilities/magic_enum.hpp src/utilities/magic_enum.hpp
src/game/player/player_spawner.cpp
src/game/player/player_spawner.hpp
src/game/camera/tracking_area.h src/game/camera/tracking_area.h
src/game/camera/tracking_view_options.hpp src/game/camera/tracking_view_options.hpp
src/game/collectables/collectable.cpp src/game/collectables/collectable.cpp
@ -96,7 +94,7 @@ set(SOURCES
src/game/collectables/collection/collectables_collection.cpp src/game/collectables/collection/collectables_collection.cpp
src/game/collectables/collection/collectables_collection.hpp src/game/collectables/collection/collectables_collection.hpp
src/game/collectables/collection/collectables_depth_collection.cpp src/game/collectables/collection/collectables_depth_collection.cpp
src/game/collectables/collection/collectables_depth_collection.hpp src/game/collectables/collectable_in_level.hpp src/game/collectables/collectable_factory.cpp src/game/collectables/collectable_factory.hpp) src/game/collectables/collection/collectables_depth_collection.hpp src/game/collectables/collectable_in_level.hpp src/game/collectables/collectable_factory.cpp src/game/collectables/collectable_factory.hpp src/game/player/player_collection.cpp src/game/player/player_collection.hpp)
set(PHYSICS_00_SOURCES set(PHYSICS_00_SOURCES
src/prototypes/physics_00.cpp) src/prototypes/physics_00.cpp)

View file

@ -34,8 +34,10 @@
#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_VIEW_SIZE_PADDING sf::Vector2f(0.5f, 0.5f) #define DEF_TV_VIEW_SIZE_PADDING sf::Vector2f(0.5f, 0.5f)
#define DEF_TV_ADD_PLAYERS_DYNAMICALLY true
// Simulations // Simulations
#define MAPSIM_WALL_THICKNESS 3.f
#define MAPSIM_VELOCITY_ITERATIONS 6 #define MAPSIM_VELOCITY_ITERATIONS 6
#define MAPSIM_POSITION_ITERATIONS 2 #define MAPSIM_POSITION_ITERATIONS 2
#define HOLESIM_VELOCITY_ITERATIONS 8 #define HOLESIM_VELOCITY_ITERATIONS 8

View file

@ -68,3 +68,8 @@ void TranslatedCoordinates::setScreenOffset(IsometricCoordinates offset)
{ {
setWorldOffset(CoordinateTransformer::isometricToWorld(offset)); setWorldOffset(CoordinateTransformer::isometricToWorld(offset));
} }
TranslatedCoordinates::TranslatedCoordinates(GridCoordinates gridCoordinates)
{
set(gridCoordinates);
}

View file

@ -9,12 +9,13 @@ class TranslatedCoordinates
{ {
public: public:
explicit TranslatedCoordinates(WorldCoordinates worldCoordinates); explicit TranslatedCoordinates(WorldCoordinates worldCoordinates);
explicit TranslatedCoordinates(GridCoordinates gridCoordinates);
WorldCoordinates world() const; [[nodiscard]] WorldCoordinates world() const;
IsometricCoordinates isometric() const; [[nodiscard]] IsometricCoordinates isometric() const;
GridCoordinates grid() const; [[nodiscard]] GridCoordinates grid() const;
void set(WorldCoordinates newWorldCoordinates); void set(WorldCoordinates newWorldCoordinates);
@ -35,7 +36,7 @@ public:
void setScreenOffset(IsometricCoordinates offset); void setScreenOffset(IsometricCoordinates offset);
private: private:
WorldCoordinates worldCoordinates; WorldCoordinates worldCoordinates{};
std::shared_ptr<TranslatedCoordinates> parent = nullptr; std::shared_ptr<TranslatedCoordinates> parent = nullptr;
}; };

View file

@ -1,11 +1,13 @@
#include "tracking_view.h" #include "tracking_view.h"
#include "../../utilities/vector_utils.hpp" #include "../../utilities/vector_utils.hpp"
#include "../player/player_collection.hpp"
TrackingView::TrackingView(TrackingViewOptions options) : options(options), TrackingView::TrackingView(TrackingViewOptions options) : options(options),
view(nullptr), view(nullptr),
hasViewChanged(false), hasViewChanged(false),
trackables({}) trackables({})
{; {
;
marker = new CircleObject(DB_CIRCLE_RADIUS, sf::Color::Yellow); marker = new CircleObject(DB_CIRCLE_RADIUS, sf::Color::Yellow);
Game::getInstance()->registerView(this); Game::getInstance()->registerView(this);
} }
@ -65,7 +67,8 @@ void TrackingView::setSize(sf::Vector2f newSize)
didAspectRationChange = true; didAspectRationChange = true;
} }
if (options.softResizeSpeed != 0 && !didAspectRationChange) { if (options.softResizeSpeed != 0 && !didAspectRationChange)
{
// Smooth out transition to new size // Smooth out transition to new size
newSize = size + (newSize - size) * options.softResizeSpeed * FRAME_TIME.asSeconds(); newSize = size + (newSize - size) * options.softResizeSpeed * FRAME_TIME.asSeconds();
} }
@ -142,7 +145,7 @@ void TrackingView::draw(sf::RenderWindow *window)
marker->draw(window); marker->draw(window);
} }
void TrackingView::addTrackable(const std::shared_ptr<ITrackable>& trackable) void TrackingView::addTrackable(const std::shared_ptr<ITrackable> &trackable)
{ {
trackables.push_back(trackable); trackables.push_back(trackable);
} }
@ -271,3 +274,39 @@ float TrackingView::getRadius(float threshold) const
// Only half of the side, since we are calculating radius // Only half of the side, since we are calculating radius
return smallestSide / 2.f * threshold; return smallestSide / 2.f * threshold;
} }
void TrackingView::update()
{
if (options.addPlayersDynamically)
{
addPlayersDynamically();
}
}
void TrackingView::addPlayersDynamically()
{
// Update based on PlayerCollection
// Add new
for (const auto &player: PlayerCollection::getInstance()->getNewPlayers())
{
if (player->getTrackableState() == TrackableState::TRACKING)
{
addTrackable(player);
}
}
// Remove old
for (const auto &player: PlayerCollection::getInstance()->getRemovedPlayers())
{
removeTrackable(player);
}
}
void TrackingView::removeTrackable(const std::shared_ptr<ITrackable> &trackable)
{
trackables.erase(
std::remove_if(trackables.begin(), trackables.end(), [&trackable](const std::shared_ptr<ITrackable> &t)
{
return t == trackable;
}), trackables.end());
}

View file

@ -17,6 +17,7 @@ public:
~TrackingView(); ~TrackingView();
void update() override;
void draw(sf::RenderWindow *window) override; void draw(sf::RenderWindow *window) override;
@ -24,6 +25,8 @@ public:
void addTrackable(const std::shared_ptr<ITrackable>& trackable); void addTrackable(const std::shared_ptr<ITrackable>& trackable);
void removeTrackable(const std::shared_ptr<ITrackable> &trackable);
sf::Vector2f getSize() const; sf::Vector2f getSize() const;
sf::Vector2f getCenter() const; sf::Vector2f getCenter() const;
@ -57,6 +60,8 @@ private:
float getRadius(float threshold) const; float getRadius(float threshold) const;
sf::Vector2f getWindowSize() const; sf::Vector2f getWindowSize() const;
void addPlayersDynamically();
}; };

View file

@ -37,6 +37,11 @@ struct TrackingViewOptions
* Value between 0 and 1 to set relative padding. * Value between 0 and 1 to set relative padding.
*/ */
sf::Vector2f viewSizePadding = DEF_TV_VIEW_SIZE_PADDING; sf::Vector2f viewSizePadding = DEF_TV_VIEW_SIZE_PADDING;
/**
* If set to true, view will add all new players automatically and remove them accordingly, based on PlayerCollection.
*/
bool addPlayersDynamically = DEF_TV_ADD_PLAYERS_DYNAMICALLY;
}; };
#endif //HOLESOME_TRACKING_VIEW_OPTIONS_HPP #endif //HOLESOME_TRACKING_VIEW_OPTIONS_HPP

View file

@ -8,11 +8,6 @@ Collectable::Collectable()
collectableCount++; collectableCount++;
} }
void Collectable::draw(sf::RenderWindow *window)
{
}
void Collectable::setRotation(float angle) void Collectable::setRotation(float angle)
{ {

View file

@ -9,8 +9,6 @@ class Collectable : public GameObject
public: public:
Collectable(); Collectable();
void draw(sf::RenderWindow *window) override;
void setSprite(const std::string &spriteName); void setSprite(const std::string &spriteName);
void setRotation(float angle); void setRotation(float angle);

View file

@ -66,7 +66,7 @@ void CollectablesCollection::update()
void CollectablesCollection::draw(sf::RenderWindow *window) void CollectablesCollection::draw(sf::RenderWindow *window)
{ {
// Render collectables in reverse order of depth // Render collectables in reverse order of depth
int maxDepth = depthCollections.size(); int maxDepth = (int) depthCollections.size();
for (int depth = maxDepth - 1; depth >= 0; depth--) for (int depth = maxDepth - 1; depth >= 0; depth--)
{ {
auto depthCollection = depthCollections.at(depth); auto depthCollection = depthCollections.at(depth);
@ -87,3 +87,14 @@ void CollectablesCollection::updateCollectables()
} }
} }
} }
std::shared_ptr<CollectablesDepthCollection> CollectablesCollection::getDepthCollection(int depth)
{
if (depthCollections.find(depth) == depthCollections.end())
{
LOG(ERROR) << "Depth collection for depth " << depth << " does not exist! Returning empty collection ...";
return std::make_shared<CollectablesDepthCollection>(depth);
}
return depthCollections[depth];
}

View file

@ -23,6 +23,8 @@ public:
void add(const std::shared_ptr<Collectable>& collectable); void add(const std::shared_ptr<Collectable>& collectable);
void remove(const std::shared_ptr<Collectable>& collectable); void remove(const std::shared_ptr<Collectable>& collectable);
std::shared_ptr<CollectablesDepthCollection> getDepthCollection(int depth);
private: private:
static inline std::shared_ptr<CollectablesCollection> singletonInstance = nullptr; static inline std::shared_ptr<CollectablesCollection> singletonInstance = nullptr;

View file

@ -5,6 +5,7 @@
#include "game.h" #include "game.h"
#include "level/level_loader.hpp" #include "level/level_loader.hpp"
#include "physics/map/map_simulation.hpp" #include "physics/map/map_simulation.hpp"
#include "../logging/easylogging++.h"
Game::Game(std::shared_ptr<sf::RenderWindow> window) : window(std::move(window)) Game::Game(std::shared_ptr<sf::RenderWindow> window) : window(std::move(window))
{ {
@ -15,6 +16,7 @@ void Game::run()
sf::Clock clock; sf::Clock clock;
sf::Time TimeSinceLastUpdate = sf::seconds(0); sf::Time TimeSinceLastUpdate = sf::seconds(0);
LOG(INFO) << "Game loop started ...";
while (window->isOpen()) while (window->isOpen())
{ {
@ -29,6 +31,8 @@ void Game::run()
} }
drawFrame(); drawFrame();
} }
LOG(INFO) << "Game closing ...";
} }
void Game::exit() void Game::exit()
@ -83,12 +87,16 @@ void Game::update()
} }
} }
InputMapper::getInstance()->updateIdentities(); // Physics updates
for (const auto &gameObject: gameObjects)
if (isLevelLoaded())
{ {
MapSimulation::getInstance()->updateSimulation(); if (gameObject->getActive())
{
gameObject->physicsUpdate();
}
} }
InputMapper::getInstance()->updateIdentities();
} }
std::shared_ptr<Game> Game::getInstance() std::shared_ptr<Game> Game::getInstance()

View file

@ -57,3 +57,25 @@ void GameObject::addChild(const std::shared_ptr<GameObject> &child)
{ {
addChildWorldOffset(child, {0, 0}); addChildWorldOffset(child, {0, 0});
} }
void GameObject::removeChild(const std::shared_ptr<GameObject> &child)
{
auto it = std::find(children.begin(), children.end(), child);
if (it != children.end())
{
children.erase(it);
}
}
void GameObject::clearChildren()
{
children.clear();
}
void GameObject::physicsUpdate()
{
for (auto &child: children)
{
child->physicsUpdate();
}
}

View file

@ -18,12 +18,16 @@ public:
virtual void lateUpdate(); virtual void lateUpdate();
virtual void physicsUpdate();
void setActive(bool active); void setActive(bool active);
bool getActive() const { return isActive; } bool getActive() const { return isActive; }
void addChildScreenOffset(const std::shared_ptr<GameObject> &child, IsometricCoordinates offset = {0, 0}); void addChildScreenOffset(const std::shared_ptr<GameObject> &child, IsometricCoordinates offset = {0, 0});
void addChildWorldOffset(const std::shared_ptr<GameObject> &child, WorldCoordinates offset); void addChildWorldOffset(const std::shared_ptr<GameObject> &child, WorldCoordinates offset);
void addChild(const std::shared_ptr<GameObject> &child); void addChild(const std::shared_ptr<GameObject> &child);
void removeChild(const std::shared_ptr<GameObject> &child);
void clearChildren();
[[nodiscard]] std::vector<std::shared_ptr<GameObject>> getChildren() const { return children; } [[nodiscard]] std::vector<std::shared_ptr<GameObject>> getChildren() const { return children; }
std::shared_ptr<TranslatedCoordinates> coordinates; std::shared_ptr<TranslatedCoordinates> coordinates;

View file

@ -2,12 +2,13 @@
#include "../game.h" #include "../game.h"
#include "../physics/map/map_simulation.hpp" #include "../physics/map/map_simulation.hpp"
#include "../../debug/grid_debug_layer.h" #include "../../debug/grid_debug_layer.h"
#include "../player/player_spawner.hpp"
#include "../../levels.hpp" #include "../../levels.hpp"
#include "../collectables/collection/collectables_collection.hpp" #include "../collectables/collection/collectables_collection.hpp"
#include "../collectables/collectable_factory.hpp" #include "../collectables/collectable_factory.hpp"
#include "../player/player_collection.hpp"
#include "../physics/hole/hole_depth_simulation.hpp"
void LevelLoader::loadLevel(const LevelConfig& levelConfig) void LevelLoader::loadLevel(const LevelConfig &levelConfig)
{ {
auto game = Game::getInstance(); auto game = Game::getInstance();
game->clearGameObjects(); game->clearGameObjects();
@ -16,6 +17,7 @@ void LevelLoader::loadLevel(const LevelConfig& levelConfig)
game->setLevel(levelConfig); game->setLevel(levelConfig);
MapSimulation::getInstance()->resetMap(levelConfig.worldMapSize); MapSimulation::getInstance()->resetMap(levelConfig.worldMapSize);
PlayerCollection::getInstance()->clear();
// Add basic game objects // Add basic game objects
if (DEVELOPER_MODE) if (DEVELOPER_MODE)
@ -24,12 +26,14 @@ void LevelLoader::loadLevel(const LevelConfig& levelConfig)
} }
game->addGameObject(std::make_shared<TrackingView>()); game->addGameObject(std::make_shared<TrackingView>());
game->addGameObject(std::make_shared<PlayerSpawner>(levelConfig.playerSpawnPoints)); game->addGameObject(PlayerCollection::getInstance());
PlayerCollection::getInstance()->setSpawnPoints(levelConfig.playerSpawnPoints);
// Prepare collectables framework // Prepare collectables framework
auto maxDepth = levelConfig.worldMapSize.x * 2; auto maxDepth = (int) levelConfig.worldMapSize.x * 2;
CollectablesCollection::getInstance()->createEmpty(maxDepth); auto collectablesCollection = CollectablesCollection::getInstance();
game->addGameObject(CollectablesCollection::getInstance()); collectablesCollection->createEmpty(maxDepth);
game->addGameObject(collectablesCollection);
// Spawn collectibles // Spawn collectibles
for (auto const &collectableInfo: levelConfig.collectables) for (auto const &collectableInfo: levelConfig.collectables)
@ -37,6 +41,15 @@ void LevelLoader::loadLevel(const LevelConfig& levelConfig)
spawnCollectable(collectableInfo); spawnCollectable(collectableInfo);
} }
// Add physics simulations
game->addGameObject(MapSimulation::getInstance());
// For every depth, add a hole depth simulation
for (int depth = 0; depth < maxDepth; depth++)
{
auto depthCollection = collectablesCollection->getDepthCollection(depth);
game->addGameObject(std::make_shared<HoleDepthSimulation>(depthCollection));
}
LOG(INFO) << "Finished loading level '" << levelConfig.name << "'."; LOG(INFO) << "Finished loading level '" << levelConfig.name << "'.";
} }

View file

@ -7,7 +7,7 @@ HoleDepthSimulation::HoleDepthSimulation(std::shared_ptr<CollectablesDepthCollec
simWorld = std::make_shared<b2World>(WORLD_GRAVITY); simWorld = std::make_shared<b2World>(WORLD_GRAVITY);
} }
void HoleDepthSimulation::updateSimulation() void HoleDepthSimulation::physicsUpdate()
{ {
updateBodiesFromCollectionHistory(); updateBodiesFromCollectionHistory();

View file

@ -10,12 +10,12 @@
/** /**
* @brief Simulates the hole(s) for the specific depth * @brief Simulates the hole(s) for the specific depth
*/ */
class HoleDepthSimulation class HoleDepthSimulation : public GameObject
{ {
public: public:
HoleDepthSimulation(std::shared_ptr<CollectablesDepthCollection> collectables); explicit HoleDepthSimulation(std::shared_ptr<CollectablesDepthCollection> collectables);
void updateSimulation(); void physicsUpdate() override;
private: private:
std::shared_ptr<CollectablesDepthCollection> collectables; std::shared_ptr<CollectablesDepthCollection> collectables;

View file

@ -1,5 +1,6 @@
#include "map_simulation.hpp" #include "map_simulation.hpp"
#include "../../../config.h" #include "../../../config.h"
#include "../../player/player_collection.hpp"
MapSimulation::MapSimulation() MapSimulation::MapSimulation()
{ {
@ -15,7 +16,7 @@ std::shared_ptr<MapSimulation> MapSimulation::getInstance()
return singletonInstance; return singletonInstance;
} }
void MapSimulation::updateSimulation() void MapSimulation::physicsUpdate()
{ {
// Update simulation positions // Update simulation positions
for (auto &mapPlayer: mapPlayersById) for (auto &mapPlayer: mapPlayersById)
@ -34,15 +35,20 @@ void MapSimulation::updateSimulation()
void MapSimulation::resetMap(sf::Vector2f worldMapSize) void MapSimulation::resetMap(sf::Vector2f worldMapSize)
{ {
// Clear all players
for (auto &mapPlayer: mapPlayersById)
{
removePlayer(mapPlayer.second->player);
}
// No gravity, since this a top-down view of the map // No gravity, since this a top-down view of the map
world = std::make_shared<b2World>(b2Vec2(0.0f, 0.0f)); world = std::make_shared<b2World>(b2Vec2(0.0f, 0.0f));
mapPlayersById.clear();
// Create map borders // Create map borders
constructSquareObstacle(-1, 0, 0, worldMapSize.y); constructSquareObstacle(-MAPSIM_WALL_THICKNESS, -MAPSIM_WALL_THICKNESS, 0, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Bottom left
constructSquareObstacle(0, -1, worldMapSize.x, 0); constructSquareObstacle(0, -MAPSIM_WALL_THICKNESS, worldMapSize.x, 0); // Bottom right
constructSquareObstacle(worldMapSize.x, 0, worldMapSize.x + 1, worldMapSize.y); constructSquareObstacle(worldMapSize.x, -MAPSIM_WALL_THICKNESS, worldMapSize.x + MAPSIM_WALL_THICKNESS, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Top right
constructSquareObstacle(0, worldMapSize.y, worldMapSize.x, worldMapSize.y + 1); constructSquareObstacle(0, worldMapSize.y, worldMapSize.x, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Top left
} }
void MapSimulation::constructSquareObstacle(float minX, float minY, float maxX, float maxY) void MapSimulation::constructSquareObstacle(float minX, float minY, float maxX, float maxY)
@ -62,11 +68,34 @@ void MapSimulation::constructSquareObstacle(float minX, float minY, float maxX,
body->CreateFixture(&fixtureDef); body->CreateFixture(&fixtureDef);
} }
void MapSimulation::addPlayer(const std::shared_ptr<Player>& player) void MapSimulation::addPlayer(const std::shared_ptr<Player> &player)
{ {
b2BodyDef bodyDef; b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody; bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(player->coordinates->world().x, player->coordinates->world().y); bodyDef.position.Set(player->spawnPosition.world().x, player->spawnPosition.world().y);
b2Body *body = world->CreateBody(&bodyDef); b2Body *body = world->CreateBody(&bodyDef);
mapPlayersById[player->getPlayerId()] = std::make_shared<MapPlayer>(player, body); mapPlayersById[player->getPlayerId()] = std::make_shared<MapPlayer>(player, body);
} }
void MapSimulation::update()
{
// Update players from player collection
// New player
for (auto &player: PlayerCollection::getInstance()->getNewPlayers())
{
addPlayer(player);
}
// Removed players
for (auto &player: PlayerCollection::getInstance()->getRemovedPlayers())
{
removePlayer(player);
}
}
void MapSimulation::removePlayer(std::shared_ptr<Player> &player)
{
// Remove body from simulation
int playerId = player->getPlayerId();
world->DestroyBody(mapPlayersById[playerId]->body);
mapPlayersById.erase(playerId);
}

View file

@ -7,12 +7,14 @@
#include "../../player/player.hpp" #include "../../player/player.hpp"
#include "map_player.hpp" #include "map_player.hpp"
class MapSimulation class MapSimulation : public GameObject
{ {
public: public:
MapSimulation(); MapSimulation();
void updateSimulation(); void update() override;
void physicsUpdate() override;
void resetMap(sf::Vector2f worldMapSize); void resetMap(sf::Vector2f worldMapSize);
@ -29,6 +31,7 @@ private:
void constructSquareObstacle(float minX, float minY, float maxX, float maxY); void constructSquareObstacle(float minX, float minY, float maxX, float maxY);
void removePlayer(std::shared_ptr<Player> &player);
}; };

View file

@ -1,19 +1,21 @@
#include "player.hpp" #include "player.hpp"
#include "../../config.h" #include "../../logging/easylogging++.h"
#include <utility> #include <utility>
Player::Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &skinRessourceName, Player::Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &skinRessourceName,
GridCoordinates initCoordinates) GridCoordinates initCoordinates)
: spawnPosition(initCoordinates)
{ {
playerId = playerCreationCounter++; playerId = playerCreationCounter++;
this->spawnPosition = initCoordinates; coordinates->set(spawnPosition);
coordinates->set(initCoordinates);
input = std::move(assignedInput); input = std::move(assignedInput);
skinSprite = std::make_shared<VersatileSprite>(skinRessourceName, getIsoSize()); skinSprite = std::make_shared<VersatileSprite>(skinRessourceName, getIsoSize());
addChildScreenOffset(skinSprite, IsometricCoordinates(-getIsoSize() / 2.f)); addChildScreenOffset(skinSprite, IsometricCoordinates(-getIsoSize() / 2.f));
LOG(INFO) << "Player " << playerId << " created.";
} }
sf::Vector2f Player::getTrackablePosition() const sf::Vector2f Player::getTrackablePosition() const
@ -92,3 +94,8 @@ void Player::setWorldRadius(float newWorldRadius)
skinSprite->setSize(newSize); skinSprite->setSize(newSize);
skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f)); skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f));
} }
Player::~Player()
{
LOG(INFO) << "Player " << playerId << " destroyed.";
}

View file

@ -13,6 +13,8 @@ public:
Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &skinRessourceName, Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &skinRessourceName,
GridCoordinates initCoordinates); GridCoordinates initCoordinates);
~Player();
void update() override; void update() override;
[[nodiscard]] sf::Vector2f getTrackablePosition() const override; [[nodiscard]] sf::Vector2f getTrackablePosition() const override;
@ -29,13 +31,12 @@ public:
[[nodiscard]] float getWorldRadius() const; [[nodiscard]] float getWorldRadius() const;
TranslatedCoordinates spawnPosition;
private: private:
std::shared_ptr<InputIdentity> input; std::shared_ptr<InputIdentity> input;
float radiusInWorld = DEFAULT_PLAYER_RADIUS; float radiusInWorld = DEFAULT_PLAYER_RADIUS;
std::shared_ptr<VersatileSprite> skinSprite; std::shared_ptr<VersatileSprite> skinSprite;
GridCoordinates spawnPosition;
int playerId; int playerId;
static inline int playerCreationCounter = 0; static inline int playerCreationCounter = 0;

View file

@ -0,0 +1,106 @@
#include "player_collection.hpp"
#include <utility>
#include "../input/input_mapper.h"
#include "../../texture_config.h"
PlayerCollection::PlayerCollection()
{
// Set default spawn point
setSpawnPoints({{0, 0}});
// Create player for existing input identities
for (auto &inputIdentity: InputMapper::getInstance()->getInputIdentities())
{
spawnPlayer(inputIdentity);
}
}
std::shared_ptr<PlayerCollection> PlayerCollection::getInstance()
{
if (singletonInstance == nullptr)
{
singletonInstance = std::make_shared<PlayerCollection>();
}
return singletonInstance;
}
void PlayerCollection::addPlayer(const std::shared_ptr<Player> &player)
{
newPlayerBuffer.push_back(player);
addChild(player);
}
void PlayerCollection::clear()
{
newPlayerBuffer.clear();
removedPlayerBuffer.clear();
// Fill in removed players
for (auto &child: getChildren())
{
auto player = std::dynamic_pointer_cast<Player>(child);
if (player != nullptr)
{
removedPlayerBuffer.push_back(player);
}
}
clearChildren();
}
void PlayerCollection::lateUpdate()
{
GameObject::lateUpdate();
newPlayerBuffer.clear();
removedPlayerBuffer.clear();
// Create player for new input identities
for (auto &inputIdentity: InputMapper::getInstance()->newInputIdentities)
{
spawnPlayer(inputIdentity);
}
// Remove players, that are not active anymore
for (auto &child: getChildren())
{
if (child != nullptr && !child->getActive())
{
removedPlayerBuffer.push_back(std::dynamic_pointer_cast<Player>(child));
removeChild(child);
}
}
}
void PlayerCollection::removePlayer(const std::shared_ptr<Player> &player)
{
removedPlayerBuffer.push_back(player);
removeChild(player);
}
std::vector<std::shared_ptr<Player>> PlayerCollection::getNewPlayers() const
{
return newPlayerBuffer;
}
std::vector<std::shared_ptr<Player>> PlayerCollection::getRemovedPlayers() const
{
return removedPlayerBuffer;
}
void PlayerCollection::setSpawnPoints(std::vector<GridCoordinates> newSpawnPoints)
{
this->spawnPoints = std::move(newSpawnPoints);
nextSpawnPointIndex = 0;
}
void PlayerCollection::spawnPlayer(const std::shared_ptr<InputIdentity> &inputIdentity)
{
// Get proper Spawn point, if available
auto spawn = spawnPoints[nextSpawnPointIndex];
nextSpawnPointIndex = static_cast<int>((nextSpawnPointIndex + 1) % spawnPoints.size());
auto player = std::make_shared<Player>(inputIdentity, PLAYER_SKIN, spawn);
PlayerCollection::getInstance()->addPlayer(player);
}

View file

@ -0,0 +1,42 @@
#ifndef HOLESOME_PLAYER_COLLECTION_HPP
#define HOLESOME_PLAYER_COLLECTION_HPP
#include "../game_object.h"
#include "player.hpp"
class PlayerCollection : public GameObject
{
public:
PlayerCollection();
static std::shared_ptr<PlayerCollection> getInstance();
void setSpawnPoints(std::vector<GridCoordinates> newSpawnPoints);
void addPlayer(const std::shared_ptr<Player>& player);
void removePlayer(const std::shared_ptr<Player>& player);
std::vector<std::shared_ptr<Player>> getNewPlayers() const;
std::vector<std::shared_ptr<Player>> getRemovedPlayers() const;
void lateUpdate() override;
void clear();
private:
static inline std::shared_ptr<PlayerCollection> singletonInstance = nullptr;
std::vector<std::shared_ptr<Player>> newPlayerBuffer = {};
std::vector<std::shared_ptr<Player>> removedPlayerBuffer = {};
std::vector<GridCoordinates> spawnPoints;
int nextSpawnPointIndex = 0;
void spawnPlayer(const std::shared_ptr<InputIdentity> &inputIdentity);
};
#endif //HOLESOME_PLAYER_COLLECTION_HPP

View file

@ -1,39 +0,0 @@
#include "player_spawner.hpp"
#include "player.hpp"
#include "../../texture_config.h"
#include "../physics/map/map_simulation.hpp"
PlayerSpawner::PlayerSpawner(std::vector<GridCoordinates> 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)
{
spawnPlayer(inputIdentity);
}
}
void PlayerSpawner::spawnPlayer(const std::shared_ptr<InputIdentity> &inputIdentity)
{
// Get proper Spawn point, if available
auto spawn = spawnPoints[nextSpawnPointIndex];
nextSpawnPointIndex = static_cast<int>((nextSpawnPointIndex + 1) % spawnPoints.size());
auto player = std::make_shared<Player>(inputIdentity, PLAYER_SKIN, spawn);
MapSimulation::getInstance()->addPlayer(player);
Game::getInstance()->addGameObject(player);
// TODO: Better view handling
Game::getInstance()->views[0]->addTrackable(player);
}

View file

@ -1,23 +0,0 @@
#ifndef HOLESOME_PLAYER_SPAWNER_HPP
#define HOLESOME_PLAYER_SPAWNER_HPP
#include "../game_object.h"
#include "../game.h"
class PlayerSpawner : public GameObject
{
public:
PlayerSpawner(std::vector<GridCoordinates> spawnPoints);
void update() override;
void spawnPlayer(const std::shared_ptr<InputIdentity> &inputIdentity);
private:
std::vector<GridCoordinates> spawnPoints;
int nextSpawnPointIndex = 0;
};
#endif //HOLESOME_PLAYER_SPAWNER_HPP

View file

@ -3870,7 +3870,7 @@ class Loggers : base::StaticClass {
private: private:
LoggingFlag m_flag; LoggingFlag m_flag;
}; };
/// @brief Removes flag and add it when scope goes out /// @brief Removes flag and addPlayer it when scope goes out
class ScopedRemoveFlag { class ScopedRemoveFlag {
public: public:
ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) {

View file

@ -7,7 +7,7 @@
#include "sprites/configs/sheet_config.hpp" #include "sprites/configs/sheet_config.hpp"
#include "sprites/configs/sprite_config.hpp" #include "sprites/configs/sprite_config.hpp"
#define PLAYER_SKIN "hole" #define PLAYER_SKIN "ring"
/** /**
* All textures used in the game. * All textures used in the game.