Added consumption and countdown
This commit is contained in:
parent
b0a83a90ef
commit
241d8119ce
39 changed files with 538 additions and 81 deletions
|
@ -129,7 +129,14 @@ set(SOURCES
|
||||||
src/game/physics/body_adapter.hpp
|
src/game/physics/body_adapter.hpp
|
||||||
src/sprites/masked_sprite.cpp
|
src/sprites/masked_sprite.cpp
|
||||||
src/sprites/masked_sprite.hpp
|
src/sprites/masked_sprite.hpp
|
||||||
src/sprites/configs/masked_sprite_config.hpp src/sprites/masked_sprite_hole.hpp)
|
src/sprites/configs/masked_sprite_config.hpp
|
||||||
|
src/sprites/masked_sprite_hole.hpp
|
||||||
|
src/game/time/countdown.cpp
|
||||||
|
src/game/time/countdown.hpp
|
||||||
|
src/game/layer/global_layer.cpp
|
||||||
|
src/game/layer/global_layer.hpp
|
||||||
|
src/typography/font_manager.cpp
|
||||||
|
src/typography/font_manager.hpp)
|
||||||
|
|
||||||
set(PHYSICS_00_SOURCES
|
set(PHYSICS_00_SOURCES
|
||||||
src/prototypes/physics_00.cpp)
|
src/prototypes/physics_00.cpp)
|
||||||
|
|
BIN
assets/fonts/pixel.ttf
Normal file
BIN
assets/fonts/pixel.ttf
Normal file
Binary file not shown.
|
@ -6,7 +6,12 @@
|
||||||
#include "game/collectables/collectable_config.hpp"
|
#include "game/collectables/collectable_config.hpp"
|
||||||
|
|
||||||
std::map<std::string, CollectableConfig> const all_collectables = {
|
std::map<std::string, CollectableConfig> const all_collectables = {
|
||||||
{"box", CollectableConfig("rosebush")}
|
{"rose", CollectableConfig("rose", 1)},
|
||||||
|
{"rosebush", CollectableConfig("rosebush", 3)},
|
||||||
|
{"stone", CollectableConfig("stone", 5)},
|
||||||
|
{"bike", CollectableConfig("bike", 10)},
|
||||||
|
{"small-tree", CollectableConfig("small-tree", 20)},
|
||||||
|
{"tram", CollectableConfig("tram", 50)}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //HOLESOME_COLLECTABLES_HPP
|
#endif //HOLESOME_COLLECTABLES_HPP
|
||||||
|
|
11
src/config.h
11
src/config.h
|
@ -34,6 +34,7 @@
|
||||||
#define MASKED_HOLE_BORDER_TRANSITION_SIZE 0.2f
|
#define MASKED_HOLE_BORDER_TRANSITION_SIZE 0.2f
|
||||||
#define MASKED_HOLE_DARKNESS_LIMIT 0.5f
|
#define MASKED_HOLE_DARKNESS_LIMIT 0.5f
|
||||||
#define COLLECTABLE_SCALE 5.f
|
#define COLLECTABLE_SCALE 5.f
|
||||||
|
#define MASKED_SPRITE_LOWER_BOUND -3.f
|
||||||
|
|
||||||
// Tracking view defaults
|
// Tracking view defaults
|
||||||
#define DEF_TV_IS_ABSOLUTE_FREE_MOVE_THRESHOLD false
|
#define DEF_TV_IS_ABSOLUTE_FREE_MOVE_THRESHOLD false
|
||||||
|
@ -70,4 +71,14 @@
|
||||||
#define DB_WORLD_GRID_RENDER false
|
#define DB_WORLD_GRID_RENDER false
|
||||||
#define DB_TRACKING_VIEW_CENTER false
|
#define DB_TRACKING_VIEW_CENTER false
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
#define FONT_BASE_PATH "assets/fonts/"
|
||||||
|
#define DEFAULT_FONT "pixel"
|
||||||
|
#define COUNTDOWN_FONT_SIZE 50
|
||||||
|
|
||||||
|
// Name => Path
|
||||||
|
const std::map<std::string, std::string> all_fonts = {
|
||||||
|
{"pixel", "pixel.ttf"}
|
||||||
|
};
|
||||||
|
|
||||||
#endif //HOLESOME_CONFIG_H
|
#endif //HOLESOME_CONFIG_H
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
#include "../player/player_collection.hpp"
|
#include "../player/player_collection.hpp"
|
||||||
|
|
||||||
TrackingView::TrackingView(TrackingViewOptions options) : options(options),
|
TrackingView::TrackingView(TrackingViewOptions options) : options(options),
|
||||||
view(new sf::View()),
|
view(new sf::View(options.initialCenter,
|
||||||
|
options.minViewSize)),
|
||||||
trackables({})
|
trackables({})
|
||||||
{
|
{
|
||||||
marker = new CircleObject(DB_CIRCLE_RADIUS, sf::Color::Yellow);
|
marker = new CircleObject(DB_CIRCLE_RADIUS, sf::Color::Yellow);
|
||||||
|
@ -22,8 +23,8 @@ void TrackingView::lateUpdate()
|
||||||
if (!trackables.empty())
|
if (!trackables.empty())
|
||||||
{
|
{
|
||||||
followTrackables();
|
followTrackables();
|
||||||
adjustSizeToTrackables();
|
|
||||||
}
|
}
|
||||||
|
adjustSizeToTrackables();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackingView::setSize(sf::Vector2f newSize)
|
void TrackingView::setSize(sf::Vector2f newSize)
|
||||||
|
@ -143,6 +144,11 @@ void TrackingView::processTrackableStates()
|
||||||
|
|
||||||
TrackingArea TrackingView::getTrackingArea() const
|
TrackingArea TrackingView::getTrackingArea() const
|
||||||
{
|
{
|
||||||
|
if (trackables.empty())
|
||||||
|
{
|
||||||
|
return TrackingArea();
|
||||||
|
}
|
||||||
|
|
||||||
auto initialTrackable = trackables[0];
|
auto initialTrackable = trackables[0];
|
||||||
TrackingArea area = {
|
TrackingArea area = {
|
||||||
initialTrackable->getTrackablePosition() - initialTrackable->getTrackableSize() / 2.f,
|
initialTrackable->getTrackablePosition() - initialTrackable->getTrackableSize() / 2.f,
|
||||||
|
|
|
@ -21,18 +21,20 @@ struct TrackingViewOptions
|
||||||
float softResizeSpeed = DEF_TV_SOFT_RESIZE_SPEED;
|
float softResizeSpeed = DEF_TV_SOFT_RESIZE_SPEED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If setWorld to 0, view will not be limited.
|
* If set to 0, view will not be limited.
|
||||||
*/
|
*/
|
||||||
sf::Vector2f minViewSize = DEF_TV_MIN_VIEW_SIZE;
|
sf::Vector2f minViewSize = DEF_TV_MIN_VIEW_SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If setWorld to 0, view will not be limited.
|
* If set to 0, view will not be limited.
|
||||||
*/
|
*/
|
||||||
sf::Vector2f maxViewSize = DEF_TV_MAX_VIEW_SIZE;
|
sf::Vector2f maxViewSize = DEF_TV_MAX_VIEW_SIZE;
|
||||||
|
|
||||||
|
sf::Vector2f initialCenter = {0, 0};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be added to tracked area size twice, as padding for each side.
|
* Will be added to tracked area size twice, as padding for each side.
|
||||||
* If isAbsoluteViewSizePadding is setWorld to true, padding will be added to view size, is multiplied with tracking size and added.
|
* If isAbsoluteViewSizePadding is set to true, padding will be added to view size, is multiplied with tracking size and added.
|
||||||
*/
|
*/
|
||||||
sf::Vector2f viewSizePadding = DEF_TV_VIEW_SIZE_PADDING;
|
sf::Vector2f viewSizePadding = DEF_TV_VIEW_SIZE_PADDING;
|
||||||
bool isAbsoluteViewSizePadding = DEF_TV_IS_ABSOLUTE_VIEW_SIZE_PADDING;
|
bool isAbsoluteViewSizePadding = DEF_TV_IS_ABSOLUTE_VIEW_SIZE_PADDING;
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
#include "../../sprites/versatile_sprite.hpp"
|
#include "../../sprites/versatile_sprite.hpp"
|
||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
#include "../input/input_mapper.h"
|
#include "../input/input_mapper.h"
|
||||||
|
#include "../physics/holes/holes_simulation.hpp"
|
||||||
|
#include "collection/collectables_collection.hpp"
|
||||||
|
#include "../player/player_collection.hpp"
|
||||||
|
|
||||||
Collectable::Collectable()
|
Collectable::Collectable(int points)
|
||||||
|
: points(points)
|
||||||
{
|
{
|
||||||
collectableId = collectableCount;
|
collectableId = collectableCount;
|
||||||
collectableCount++;
|
collectableCount++;
|
||||||
|
@ -24,10 +28,12 @@ float Collectable::getDepth() const
|
||||||
void Collectable::setSprite(const std::string &spriteName)
|
void Collectable::setSprite(const std::string &spriteName)
|
||||||
{
|
{
|
||||||
// Create versatile sprite
|
// Create versatile sprite
|
||||||
auto sprite = std::make_shared<VersatileSprite>(spriteName);
|
auto spriteObject = std::make_shared<VersatileSprite>(spriteName);
|
||||||
size = sprite->getSize() * COLLECTABLE_SCALE;
|
size = spriteObject->getSize() * COLLECTABLE_SCALE;
|
||||||
sprite->setSize(size);
|
spriteObject->setSize(size);
|
||||||
addChildScreenOffset(sprite, IsometricCoordinates(-size / 2.f));
|
addChildScreenOffset(spriteObject, IsometricCoordinates(-size / 2.f));
|
||||||
|
|
||||||
|
sprite = spriteObject;
|
||||||
|
|
||||||
// Set half size offset of coordinates
|
// Set half size offset of coordinates
|
||||||
coordinates->move(IsometricCoordinates(0, -size.x / 2.f, 0));
|
coordinates->move(IsometricCoordinates(0, -size.x / 2.f, 0));
|
||||||
|
@ -37,3 +43,16 @@ sf::Vector2f Collectable::getSize() const
|
||||||
{
|
{
|
||||||
return size / WORLD_TO_ISO_SCALE;
|
return size / WORLD_TO_ISO_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Collectable::preRenderUpdate()
|
||||||
|
{
|
||||||
|
if (!sprite->isVisible())
|
||||||
|
{
|
||||||
|
auto closestPlayer = PlayerCollection::getInstance()->getClosestPlayer(*coordinates);
|
||||||
|
closestPlayer->consume(points);
|
||||||
|
setActive(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameObject::preRenderUpdate();
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
|
|
||||||
#include "../game_object.h"
|
#include "../game_object.h"
|
||||||
#include "../player/player.hpp"
|
#include "../player/player.hpp"
|
||||||
|
#include "../../sprites/masked_sprite.hpp"
|
||||||
|
|
||||||
class Collectable : public GameObject
|
class Collectable : public GameObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Collectable();
|
Collectable(int points);
|
||||||
|
|
||||||
void setSprite(const std::string &spriteName);
|
void setSprite(const std::string &spriteName);
|
||||||
|
|
||||||
|
@ -23,11 +24,15 @@ public:
|
||||||
return collectableId;
|
return collectableId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void preRenderUpdate() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int collectableId = 0;
|
int collectableId = 0;
|
||||||
static inline int collectableCount = 0;
|
static inline int collectableCount = 0;
|
||||||
|
std::shared_ptr<Sprite> sprite;
|
||||||
|
|
||||||
sf::Vector2f size;
|
sf::Vector2f size;
|
||||||
|
int points = 0;
|
||||||
|
|
||||||
std::shared_ptr<Player> consumedBy = nullptr;
|
std::shared_ptr<Player> consumedBy = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
struct CollectableConfig
|
struct CollectableConfig
|
||||||
{
|
{
|
||||||
std::string spriteName;
|
std::string spriteName;
|
||||||
|
int points = 0;
|
||||||
|
|
||||||
explicit CollectableConfig(std::string spriteName)
|
explicit CollectableConfig(std::string spriteName, int points)
|
||||||
: spriteName(std::move(spriteName))
|
: spriteName(std::move(spriteName)), points(points)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CollectableConfig() = default;
|
CollectableConfig() = default;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
std::shared_ptr<Collectable> CollectableFactory::createFromInLevelConfig(const CollectableInLevel &config)
|
std::shared_ptr<Collectable> CollectableFactory::createFromInLevelConfig(const CollectableInLevel &config)
|
||||||
{
|
{
|
||||||
auto collectableConfig = config.collectableConfig;
|
auto collectableConfig = config.collectableConfig;
|
||||||
auto collectable = std::make_shared<Collectable>();
|
auto collectable = std::make_shared<Collectable>(config.collectableConfig.points);
|
||||||
|
|
||||||
collectable->coordinates->setGrid(config.position);
|
collectable->coordinates->setGrid(config.position);
|
||||||
collectable->setSprite(collectableConfig.spriteName);
|
collectable->setSprite(collectableConfig.spriteName);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "collectables_depth_collection.hpp"
|
#include "collectables_depth_collection.hpp"
|
||||||
#include "../../../logging/easylogging++.h"
|
#include "../../../logging/easylogging++.h"
|
||||||
#include "../../../config.h"
|
#include "../../../config.h"
|
||||||
|
#include "../../physics/holes/holes_simulation.hpp"
|
||||||
|
|
||||||
std::shared_ptr<CollectablesCollection> CollectablesCollection::getInstance()
|
std::shared_ptr<CollectablesCollection> CollectablesCollection::getInstance()
|
||||||
{
|
{
|
||||||
|
@ -28,8 +29,26 @@ void CollectablesCollection::createEmpty(int maxDepth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectablesCollection::remove(const std::shared_ptr<Collectable> &collectable)
|
void CollectablesCollection::remove(int collectableId)
|
||||||
{
|
{
|
||||||
|
HolesSimulation::getInstance()->removeCollectable(collectableId);
|
||||||
|
|
||||||
|
std::shared_ptr<Collectable> collectable = nullptr;
|
||||||
|
for (auto &child: getChildren())
|
||||||
|
{
|
||||||
|
collectable = std::dynamic_pointer_cast<Collectable>(child);
|
||||||
|
if (collectable->getId() == collectableId)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectable == nullptr)
|
||||||
|
{
|
||||||
|
LOG(ERROR) << "No collectables left to remove.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
depthCollections[collectable->getDepth()]->remove(collectable);
|
depthCollections[collectable->getDepth()]->remove(collectable);
|
||||||
removeChild(collectable);
|
removeChild(collectable);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +63,21 @@ void CollectablesCollection::update()
|
||||||
{
|
{
|
||||||
GameObject::update();
|
GameObject::update();
|
||||||
|
|
||||||
if (!CONSIDER_COLLECTABLE_DEPTH_MOVEMENT) {
|
// Remove inactive collectables
|
||||||
|
auto collectables = getChildren();
|
||||||
|
for (auto &child: collectables)
|
||||||
|
{
|
||||||
|
auto collectable = std::dynamic_pointer_cast<Collectable>(child);
|
||||||
|
if (collectable->getActive())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(collectable->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CONSIDER_COLLECTABLE_DEPTH_MOVEMENT)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
void draw(sf::RenderWindow *window) override;
|
void draw(sf::RenderWindow *window) override;
|
||||||
|
|
||||||
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(int collectableId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline std::shared_ptr<CollectablesCollection> singletonInstance = nullptr;
|
static inline std::shared_ptr<CollectablesCollection> singletonInstance = nullptr;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#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"
|
#include "../logging/easylogging++.h"
|
||||||
|
#include "layer/global_layer.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))
|
||||||
{
|
{
|
||||||
|
@ -145,3 +146,9 @@ bool Game::isLevelLoaded() const
|
||||||
{
|
{
|
||||||
return loadedLevelConfig.isValid();
|
return loadedLevelConfig.isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::startCountdown(int durationInSeconds)
|
||||||
|
{
|
||||||
|
countdown = std::make_shared<Countdown>(durationInSeconds);
|
||||||
|
GlobalLayer::getInstance()->add(countdown);
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "camera/tracking_view.h"
|
#include "camera/tracking_view.h"
|
||||||
#include "level/level_config.hpp"
|
#include "level/level_config.hpp"
|
||||||
#include "frame_counter.hpp"
|
#include "frame_counter.hpp"
|
||||||
|
#include "time/countdown.hpp"
|
||||||
|
|
||||||
class TrackingView;
|
class TrackingView;
|
||||||
|
|
||||||
|
@ -16,8 +17,10 @@ class TrackingView;
|
||||||
class Game
|
class Game
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Game> constructInstance(const std::shared_ptr<sf::RenderWindow>& window);
|
static std::shared_ptr<Game> constructInstance(const std::shared_ptr<sf::RenderWindow> &window);
|
||||||
|
|
||||||
static std::shared_ptr<Game> getInstance();
|
static std::shared_ptr<Game> getInstance();
|
||||||
|
|
||||||
explicit Game(std::shared_ptr<sf::RenderWindow> window);
|
explicit Game(std::shared_ptr<sf::RenderWindow> window);
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
@ -28,9 +31,11 @@ public:
|
||||||
|
|
||||||
void setLevel(LevelConfig levelConfig);
|
void setLevel(LevelConfig levelConfig);
|
||||||
|
|
||||||
|
void startCountdown(int durationInSeconds);
|
||||||
|
|
||||||
[[nodiscard]] bool isLevelLoaded() const;
|
[[nodiscard]] bool isLevelLoaded() const;
|
||||||
|
|
||||||
void addGameObject(const std::shared_ptr<GameObject>& gameObject);
|
void addGameObject(const std::shared_ptr<GameObject> &gameObject);
|
||||||
|
|
||||||
std::shared_ptr<sf::RenderWindow> window;
|
std::shared_ptr<sf::RenderWindow> window;
|
||||||
private:
|
private:
|
||||||
|
@ -41,6 +46,7 @@ private:
|
||||||
LevelConfig loadedLevelConfig = {};
|
LevelConfig loadedLevelConfig = {};
|
||||||
|
|
||||||
std::shared_ptr<FrameCounter> frameCounter = std::make_shared<FrameCounter>();
|
std::shared_ptr<FrameCounter> frameCounter = std::make_shared<FrameCounter>();
|
||||||
|
std::shared_ptr<Countdown> countdown = std::make_shared<Countdown>();
|
||||||
|
|
||||||
void drawFrame();
|
void drawFrame();
|
||||||
|
|
||||||
|
|
39
src/game/layer/global_layer.cpp
Normal file
39
src/game/layer/global_layer.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "global_layer.hpp"
|
||||||
|
|
||||||
|
void GlobalLayer::clear()
|
||||||
|
{
|
||||||
|
clearChildren();
|
||||||
|
addDetachedChild(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<GlobalLayer> GlobalLayer::getInstance()
|
||||||
|
{
|
||||||
|
if (singletonInstance == nullptr)
|
||||||
|
{
|
||||||
|
singletonInstance = std::make_shared<GlobalLayer>();
|
||||||
|
}
|
||||||
|
return singletonInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalLayer::draw(sf::RenderWindow *window)
|
||||||
|
{
|
||||||
|
view->setViewForWindow();
|
||||||
|
GameObject::draw(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalLayer::GlobalLayer()
|
||||||
|
{
|
||||||
|
// Reference screen size of 1920x1080
|
||||||
|
TrackingViewOptions options = {
|
||||||
|
.minViewSize = sf::Vector2f{10, 1080},
|
||||||
|
.initialCenter = sf::Vector2f{1920, 1080} / 2.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
view = std::make_shared<TrackingView>(options);
|
||||||
|
addDetachedChild(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalLayer::add(const std::shared_ptr<GameObject>& gameObject)
|
||||||
|
{
|
||||||
|
addDetachedChild(gameObject);
|
||||||
|
}
|
27
src/game/layer/global_layer.hpp
Normal file
27
src/game/layer/global_layer.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef HOLESOME_GLOBAL_LAYER_HPP
|
||||||
|
#define HOLESOME_GLOBAL_LAYER_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include "../game_object.h"
|
||||||
|
#include "../camera/tracking_view.h"
|
||||||
|
|
||||||
|
class GlobalLayer : public GameObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GlobalLayer();
|
||||||
|
|
||||||
|
static std::shared_ptr<GlobalLayer> getInstance();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void draw(sf::RenderWindow *window) override;
|
||||||
|
|
||||||
|
void add(const std::shared_ptr<GameObject>& gameObject);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline std::shared_ptr<GlobalLayer> singletonInstance = nullptr;
|
||||||
|
std::shared_ptr<TrackingView> view;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HOLESOME_GLOBAL_LAYER_HPP
|
|
@ -13,6 +13,7 @@
|
||||||
struct LevelConfig
|
struct LevelConfig
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
|
int durationInSeconds = 0;
|
||||||
sf::Vector2i worldMapSize = {};
|
sf::Vector2i worldMapSize = {};
|
||||||
TileMapConfig tileMapConfig = {};
|
TileMapConfig tileMapConfig = {};
|
||||||
std::vector<GridCoordinates> playerSpawnPoints = {};
|
std::vector<GridCoordinates> playerSpawnPoints = {};
|
||||||
|
@ -20,11 +21,13 @@ struct LevelConfig
|
||||||
std::vector<sf::Color> skyColors = {};
|
std::vector<sf::Color> skyColors = {};
|
||||||
|
|
||||||
LevelConfig(std::string name,
|
LevelConfig(std::string name,
|
||||||
|
int durationInSeconds,
|
||||||
const std::vector<GridCoordinates> &playerSpawnPoints,
|
const std::vector<GridCoordinates> &playerSpawnPoints,
|
||||||
const std::vector<CollectableInLevel> &collectables,
|
const std::vector<CollectableInLevel> &collectables,
|
||||||
std::vector<sf::Color> skyColors,
|
std::vector<sf::Color> skyColors,
|
||||||
const TileMapConfig &tileMapConfig)
|
const TileMapConfig &tileMapConfig)
|
||||||
: name(std::move(name)),
|
: name(std::move(name)),
|
||||||
|
durationInSeconds(durationInSeconds),
|
||||||
playerSpawnPoints(playerSpawnPoints),
|
playerSpawnPoints(playerSpawnPoints),
|
||||||
tileMapConfig(tileMapConfig),
|
tileMapConfig(tileMapConfig),
|
||||||
skyColors(std::move(skyColors))
|
skyColors(std::move(skyColors))
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "../camera/multiplayer_view.hpp"
|
#include "../camera/multiplayer_view.hpp"
|
||||||
#include "../physics/holes/holes_simulation.hpp"
|
#include "../physics/holes/holes_simulation.hpp"
|
||||||
#include "../physics/holes/layouts/hole_layout.hpp"
|
#include "../physics/holes/layouts/hole_layout.hpp"
|
||||||
|
#include "../layer/global_layer.hpp"
|
||||||
|
|
||||||
void LevelLoader::loadLevel(const LevelConfig &levelConfig)
|
void LevelLoader::loadLevel(const LevelConfig &levelConfig)
|
||||||
{
|
{
|
||||||
|
@ -23,6 +24,7 @@ void LevelLoader::loadLevel(const LevelConfig &levelConfig)
|
||||||
MapSimulation::getInstance()->resetMap(levelConfig.worldMapSize);
|
MapSimulation::getInstance()->resetMap(levelConfig.worldMapSize);
|
||||||
HolesSimulation::getInstance()->clear();
|
HolesSimulation::getInstance()->clear();
|
||||||
PlayerCollection::getInstance()->clear();
|
PlayerCollection::getInstance()->clear();
|
||||||
|
GlobalLayer::getInstance()->clear();
|
||||||
HoleLayout::getInstance()->clear();
|
HoleLayout::getInstance()->clear();
|
||||||
|
|
||||||
// Add views
|
// Add views
|
||||||
|
@ -60,6 +62,10 @@ void LevelLoader::loadLevel(const LevelConfig &levelConfig)
|
||||||
spawnCollectable(collectableInfo);
|
spawnCollectable(collectableInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game->startCountdown(levelConfig.durationInSeconds);
|
||||||
|
|
||||||
|
// Must be last
|
||||||
|
game->addGameObject(GlobalLayer::getInstance());
|
||||||
|
|
||||||
LOG(INFO) << "Finished loading level '" << levelConfig.name << "'.";
|
LOG(INFO) << "Finished loading level '" << levelConfig.name << "'.";
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
std::shared_ptr<HolesSimulation> HolesSimulation::getInstance()
|
std::shared_ptr<HolesSimulation> HolesSimulation::getInstance()
|
||||||
{
|
{
|
||||||
if (singletonInstance == nullptr) {
|
if (singletonInstance == nullptr)
|
||||||
|
{
|
||||||
singletonInstance = std::make_shared<HolesSimulation>();
|
singletonInstance = std::make_shared<HolesSimulation>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +14,8 @@ std::vector<std::shared_ptr<CollectableSimulation>> HolesSimulation::getCollecta
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<CollectableSimulation>> collectableSimulations{};
|
std::vector<std::shared_ptr<CollectableSimulation>> collectableSimulations{};
|
||||||
|
|
||||||
for (auto &child : getChildren()) {
|
for (auto &child: getChildren())
|
||||||
|
{
|
||||||
auto sim = std::dynamic_pointer_cast<CollectableSimulation>(child);
|
auto sim = std::dynamic_pointer_cast<CollectableSimulation>(child);
|
||||||
collectableSimulations.push_back(sim);
|
collectableSimulations.push_back(sim);
|
||||||
}
|
}
|
||||||
|
@ -35,8 +37,10 @@ void HolesSimulation::addCollectable(const std::shared_ptr<Collectable> &collect
|
||||||
void HolesSimulation::lateUpdate()
|
void HolesSimulation::lateUpdate()
|
||||||
{
|
{
|
||||||
// Remove disabled collectables
|
// Remove disabled collectables
|
||||||
for (const auto& sim : getCollectableSimulations()) {
|
for (const auto &sim: getCollectableSimulations())
|
||||||
if (sim->getCollectable()->getActive()) {
|
{
|
||||||
|
if (sim->getCollectable()->getActive())
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,3 +49,15 @@ void HolesSimulation::lateUpdate()
|
||||||
|
|
||||||
GameObject::lateUpdate();
|
GameObject::lateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HolesSimulation::removeCollectable(int collectableId)
|
||||||
|
{
|
||||||
|
for (const auto &sim: getCollectableSimulations())
|
||||||
|
{
|
||||||
|
if (sim->getCollectable()->getId() == collectableId)
|
||||||
|
{
|
||||||
|
removeChild(sim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ public:
|
||||||
|
|
||||||
void addCollectable(const std::shared_ptr<Collectable> &collectable);
|
void addCollectable(const std::shared_ptr<Collectable> &collectable);
|
||||||
|
|
||||||
|
void removeCollectable(int collectableId);
|
||||||
|
|
||||||
void lateUpdate() override;
|
void lateUpdate() override;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -14,7 +14,7 @@ Player::Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &
|
||||||
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));
|
||||||
|
|
||||||
updateRadiusBasedOnLevel();
|
updateRadiusBasedOnPoints();
|
||||||
|
|
||||||
LOG(INFO) << "Player " << playerId << " created.";
|
LOG(INFO) << "Player " << playerId << " created.";
|
||||||
}
|
}
|
||||||
|
@ -41,19 +41,6 @@ void Player::update()
|
||||||
auto moveDelta = moveDirection * speed * FRAME_TIME.asSeconds();
|
auto moveDelta = moveDirection * speed * FRAME_TIME.asSeconds();
|
||||||
coordinates->move(moveDelta);
|
coordinates->move(moveDelta);
|
||||||
|
|
||||||
if (input->isPerformingAction(GameAction::GROW))
|
|
||||||
{
|
|
||||||
points = (points + 1) * (1 + 1 * FRAME_TIME.asSeconds());
|
|
||||||
} else if (input->isPerformingAction(GameAction::SHRINK))
|
|
||||||
{
|
|
||||||
points *= 1 - 1 * FRAME_TIME.asSeconds();
|
|
||||||
if (points < 0) {
|
|
||||||
points = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRadiusBasedOnLevel();
|
|
||||||
|
|
||||||
GameObject::update();
|
GameObject::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +88,18 @@ long Player::getPoints() const
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::updateRadiusBasedOnLevel()
|
void Player::updateRadiusBasedOnPoints()
|
||||||
{
|
{
|
||||||
long points = getPoints();
|
long points = getPoints();
|
||||||
float newWorldRadius = PLAYER_MIN_RADIUS + PLAYER_RADIUS_PER_LEVEL * pow(points / 100.f, 2);
|
float newWorldRadius = PLAYER_MIN_RADIUS + PLAYER_RADIUS_PER_LEVEL * points / 10.f;
|
||||||
|
|
||||||
setWorldRadius(newWorldRadius);
|
setWorldRadius(newWorldRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::consume(int points)
|
||||||
|
{
|
||||||
|
this->points += points;
|
||||||
|
LOG(INFO) << "Player " << playerId << " consumed " << points << " points. Total: " << this->points;
|
||||||
|
|
||||||
|
updateRadiusBasedOnPoints();
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] long getPoints() const;
|
[[nodiscard]] long getPoints() const;
|
||||||
|
|
||||||
|
void consume(int points);
|
||||||
|
|
||||||
TranslatedCoordinates spawnPosition;
|
TranslatedCoordinates spawnPosition;
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<InputIdentity> input;
|
std::shared_ptr<InputIdentity> input;
|
||||||
|
@ -44,7 +46,7 @@ private:
|
||||||
|
|
||||||
void setWorldRadius(float newWorldRadius);
|
void setWorldRadius(float newWorldRadius);
|
||||||
|
|
||||||
void updateRadiusBasedOnLevel();
|
void updateRadiusBasedOnPoints();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -144,3 +144,22 @@ void PlayerCollection::updateInputIdentityAllowance() const
|
||||||
{
|
{
|
||||||
InputMapper::getInstance()->allowNewInputIdentities = getPlayers().size() < maxPlayerCount;
|
InputMapper::getInstance()->allowNewInputIdentities = getPlayers().size() < maxPlayerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Player> PlayerCollection::getClosestPlayer(const TranslatedCoordinates& point) const
|
||||||
|
{
|
||||||
|
std::shared_ptr<Player> closestPlayer = nullptr;
|
||||||
|
float closestDistance = INFINITY;
|
||||||
|
for (auto &player: getPlayers())
|
||||||
|
{
|
||||||
|
auto playerCenterGround = player->coordinates->world().toGroundCoordinates();
|
||||||
|
auto pointCenterGround = point.world().toGroundCoordinates();
|
||||||
|
// Normalize distance by player radius to get a value below 1 for something inside the player
|
||||||
|
float distance = length(playerCenterGround - pointCenterGround) / player->getWorldRadius();
|
||||||
|
if (distance < closestDistance)
|
||||||
|
{
|
||||||
|
closestPlayer = player;
|
||||||
|
closestDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closestPlayer;
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ public:
|
||||||
|
|
||||||
void removePlayer(const std::shared_ptr<Player>& player);
|
void removePlayer(const std::shared_ptr<Player>& player);
|
||||||
|
|
||||||
|
std::shared_ptr<Player> getClosestPlayer(const TranslatedCoordinates& point) const;
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::shared_ptr<Player>> getPlayers() const;
|
[[nodiscard]] std::vector<std::shared_ptr<Player>> getPlayers() const;
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<Player> getPlayerById(int playerId) const;
|
[[nodiscard]] std::shared_ptr<Player> getPlayerById(int playerId) const;
|
||||||
|
|
70
src/game/time/countdown.cpp
Normal file
70
src/game/time/countdown.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include <SFML/Graphics/Text.hpp>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "countdown.hpp"
|
||||||
|
#include "../../typography/font_manager.hpp"
|
||||||
|
#include "../../config.h"
|
||||||
|
|
||||||
|
void Countdown::restart(int durationInSeconds)
|
||||||
|
{
|
||||||
|
this->durationInSeconds = durationInSeconds;
|
||||||
|
timeElapsed = sf::Time::Zero;
|
||||||
|
clock.restart();
|
||||||
|
stopped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Countdown::Countdown(int durationInSeconds)
|
||||||
|
{
|
||||||
|
restart(durationInSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Countdown::stop()
|
||||||
|
{
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Countdown::isFinished() const
|
||||||
|
{
|
||||||
|
return timeElapsed.asSeconds() >= durationInSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Countdown::update()
|
||||||
|
{
|
||||||
|
GameObject::update();
|
||||||
|
|
||||||
|
if (stopped)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeElapsed += clock.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Countdown::draw(sf::RenderWindow *window)
|
||||||
|
{
|
||||||
|
GameObject::draw(window);
|
||||||
|
|
||||||
|
// Draw the countdown
|
||||||
|
int timeLeft = durationInSeconds - timeElapsed.asSeconds();
|
||||||
|
if (timeLeft <= 0)
|
||||||
|
{
|
||||||
|
timeLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minutes = timeLeft / 60;
|
||||||
|
int seconds = timeLeft % 60;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::setfill('0') << std::setw(2) << minutes << ":" << std::setw(2) << seconds;
|
||||||
|
auto timeLeftString = ss.str();
|
||||||
|
|
||||||
|
|
||||||
|
auto font = FontManager::getInstance()->getDefaultFont();
|
||||||
|
auto text = sf::Text(timeLeftString, *font, COUNTDOWN_FONT_SIZE);
|
||||||
|
text.setFillColor(sf::Color::White);
|
||||||
|
text.setPosition(1920 / 2.f, 5);
|
||||||
|
|
||||||
|
// Align top center
|
||||||
|
sf::FloatRect textRect = text.getLocalBounds();
|
||||||
|
text.setOrigin(textRect.left + textRect.width / 2.0f,
|
||||||
|
textRect.top);
|
||||||
|
window->draw(text);
|
||||||
|
}
|
31
src/game/time/countdown.hpp
Normal file
31
src/game/time/countdown.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef HOLESOME_COUNTDOWN_HPP
|
||||||
|
#define HOLESOME_COUNTDOWN_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <SFML/System/Clock.hpp>
|
||||||
|
#include "../game_object.h"
|
||||||
|
|
||||||
|
class Countdown : public GameObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Countdown(int durationInSeconds = 0);
|
||||||
|
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
void restart(int durationInSeconds);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
[[nodiscard]] bool isFinished() const;
|
||||||
|
|
||||||
|
void draw(sf::RenderWindow *window) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sf::Clock clock;
|
||||||
|
int durationInSeconds = 0;
|
||||||
|
sf::Time timeElapsed = sf::Time::Zero;
|
||||||
|
bool stopped = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HOLESOME_COUNTDOWN_HPP
|
|
@ -8,21 +8,25 @@
|
||||||
#define INITIAL_LEVEL "default"
|
#define INITIAL_LEVEL "default"
|
||||||
|
|
||||||
std::map<std::string, LevelConfig> const all_levels = {
|
std::map<std::string, LevelConfig> const all_levels = {
|
||||||
{"default", LevelConfig("Default", {{0, 0},
|
{"default", LevelConfig("Default",
|
||||||
{18, 18},
|
30,
|
||||||
{0, 18},
|
{
|
||||||
{18, 0}}, {
|
{0, 0},
|
||||||
CollectableInLevel("box", {3, 5}),
|
{18, 18},
|
||||||
CollectableInLevel("box", {4, 5}),
|
{0, 18},
|
||||||
CollectableInLevel("box", {10, 6}),
|
{18, 0}
|
||||||
CollectableInLevel("box", {2, 8}),
|
}, {
|
||||||
CollectableInLevel("box", {1, 2}),
|
CollectableInLevel("rose", {3, 5}),
|
||||||
CollectableInLevel("box", {4, 3}),
|
CollectableInLevel("rosebush", {4, 5}),
|
||||||
CollectableInLevel("box", {8, 3}),
|
CollectableInLevel("stone", {10, 6}),
|
||||||
CollectableInLevel("box", {6, 7}),
|
CollectableInLevel("bike", {2, 8}),
|
||||||
CollectableInLevel("box", {5, 5}),
|
CollectableInLevel("rose", {1, 2}),
|
||||||
CollectableInLevel("box", {9, 5}),
|
CollectableInLevel("small-tree", {4, 3}),
|
||||||
CollectableInLevel("box", {0, 1})
|
CollectableInLevel("rose", {8, 3}),
|
||||||
|
CollectableInLevel("rose", {6, 7}),
|
||||||
|
CollectableInLevel("rose", {5, 5}),
|
||||||
|
CollectableInLevel("tram", {9, 5}),
|
||||||
|
CollectableInLevel("rose", {0, 1})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Blues
|
// Blues
|
||||||
|
@ -40,25 +44,27 @@ std::map<std::string, LevelConfig> const all_levels = {
|
||||||
sf::Color(20, 18, 11),
|
sf::Color(20, 18, 11),
|
||||||
sf::Color::Black
|
sf::Color::Black
|
||||||
},
|
},
|
||||||
TileMapConfig("iso-tiles", {{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
TileMapConfig("iso-tiles", {
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}})
|
{4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
|
||||||
|
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
|
||||||
|
})
|
||||||
)}
|
)}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
14
src/main.cpp
14
src/main.cpp
|
@ -4,11 +4,14 @@
|
||||||
#include "texture_config.h"
|
#include "texture_config.h"
|
||||||
#include "game/level/level_loader.hpp"
|
#include "game/level/level_loader.hpp"
|
||||||
#include "levels.hpp"
|
#include "levels.hpp"
|
||||||
|
#include "typography/font_manager.hpp"
|
||||||
|
|
||||||
void loadAllTextures();
|
void loadAllTextures();
|
||||||
|
|
||||||
void runGame();
|
void runGame();
|
||||||
|
|
||||||
|
void loadAllFonts();
|
||||||
|
|
||||||
INITIALIZE_EASYLOGGINGPP
|
INITIALIZE_EASYLOGGINGPP
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -16,9 +19,20 @@ int main(int argc, char *argv[])
|
||||||
START_EASYLOGGINGPP(argc, argv);
|
START_EASYLOGGINGPP(argc, argv);
|
||||||
|
|
||||||
loadAllTextures();
|
loadAllTextures();
|
||||||
|
loadAllFonts();
|
||||||
runGame();
|
runGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadAllFonts()
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Loading fonts...";
|
||||||
|
for (auto const &[key, path]: all_fonts)
|
||||||
|
{
|
||||||
|
FontManager::getInstance()->loadFont(key, path);
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Finished loading fonts.";
|
||||||
|
}
|
||||||
|
|
||||||
void runGame()
|
void runGame()
|
||||||
{
|
{
|
||||||
LOG(INFO) << "Starting game ...";
|
LOG(INFO) << "Starting game ...";
|
||||||
|
|
|
@ -77,3 +77,8 @@ void AnimatedSprite::preRenderUpdate()
|
||||||
|
|
||||||
renderPosition = calculateRotatedCornerPosition(position, angle);
|
renderPosition = calculateRotatedCornerPosition(position, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AnimatedSprite::isVisible() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ public:
|
||||||
|
|
||||||
void preRenderUpdate() override;
|
void preRenderUpdate() override;
|
||||||
|
|
||||||
|
bool isVisible() const override;
|
||||||
|
|
||||||
void setRotation(float angle) override;
|
void setRotation(float angle) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -24,7 +24,15 @@ void MaskedSprite::preRenderUpdate()
|
||||||
{
|
{
|
||||||
GameObject::preRenderUpdate();
|
GameObject::preRenderUpdate();
|
||||||
|
|
||||||
// TODO: Did anything change? Is update of masked sprite necessary?
|
if (isHidden)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousAngle == angle && previousRenderPosition == renderPosition)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (angle == 0)
|
if (angle == 0)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +46,14 @@ void MaskedSprite::preRenderUpdate()
|
||||||
sprite->setRotation(angle);
|
sprite->setRotation(angle);
|
||||||
|
|
||||||
updateFreshMaskedSprite();
|
updateFreshMaskedSprite();
|
||||||
|
|
||||||
|
previousAngle = angle;
|
||||||
|
previousRenderPosition = renderPosition;
|
||||||
|
|
||||||
|
if (isHidden)
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Masked sprite has been permanently hidden";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaskedSprite::draw(sf::RenderWindow *window)
|
void MaskedSprite::draw(sf::RenderWindow *window)
|
||||||
|
@ -49,14 +65,12 @@ void MaskedSprite::draw(sf::RenderWindow *window)
|
||||||
|
|
||||||
void MaskedSprite::updateFreshMaskedSprite()
|
void MaskedSprite::updateFreshMaskedSprite()
|
||||||
{
|
{
|
||||||
// TODO: Calculate depth per pixel
|
|
||||||
auto maskedImage = std::make_shared<sf::Image>();
|
auto maskedImage = std::make_shared<sf::Image>();
|
||||||
maskedImage->create(textureRect.width, textureRect.height, sf::Color::Transparent);
|
maskedImage->create(textureRect.width, textureRect.height, sf::Color::Transparent);
|
||||||
|
|
||||||
// todo: or use sf::RenderTexture?
|
|
||||||
|
|
||||||
maskedImage->copy(*image, 0, 0);
|
maskedImage->copy(*image, 0, 0);
|
||||||
|
|
||||||
|
isHidden = true;
|
||||||
|
|
||||||
// Calculate world coordinates for each pixel
|
// Calculate world coordinates for each pixel
|
||||||
auto coordinatesTopLeftCorner = TranslatedCoordinates(
|
auto coordinatesTopLeftCorner = TranslatedCoordinates(
|
||||||
IsometricCoordinates(renderPosition.x, renderPosition.y, coordinates->isometric().depth));
|
IsometricCoordinates(renderPosition.x, renderPosition.y, coordinates->isometric().depth));
|
||||||
|
@ -77,6 +91,7 @@ void MaskedSprite::updateFreshMaskedSprite()
|
||||||
topLeftCorner + xAxis * (xOffset * xFactorPerPixel) + yAxis * (yOffset * yFactorPerPixel);
|
topLeftCorner + xAxis * (xOffset * xFactorPerPixel) + yAxis * (yOffset * yFactorPerPixel);
|
||||||
if (pixelPosition.y >= 0)
|
if (pixelPosition.y >= 0)
|
||||||
{
|
{
|
||||||
|
isHidden = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +139,7 @@ sf::Color MaskedSprite::calculateNewPixelColor(sf::Color currentColor, sf::Vecto
|
||||||
if (position.y >= 0)
|
if (position.y >= 0)
|
||||||
{
|
{
|
||||||
// Pixel is above ground
|
// Pixel is above ground
|
||||||
|
isHidden = false;
|
||||||
return currentColor;
|
return currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +154,7 @@ sf::Color MaskedSprite::calculateNewPixelColor(sf::Color currentColor, sf::Vecto
|
||||||
auto players = PlayerCollection::getInstance()->getPlayers();
|
auto players = PlayerCollection::getInstance()->getPlayers();
|
||||||
if (players.empty())
|
if (players.empty())
|
||||||
{
|
{
|
||||||
|
isHidden = false;
|
||||||
return currentColor;
|
return currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +170,16 @@ sf::Color MaskedSprite::calculateNewPixelColor(sf::Color currentColor, sf::Vecto
|
||||||
}
|
}
|
||||||
|
|
||||||
float biggestHoleAlphaFactor = *std::max_element(holeAlphaFactors.begin(), holeAlphaFactors.end());
|
float biggestHoleAlphaFactor = *std::max_element(holeAlphaFactors.begin(), holeAlphaFactors.end());
|
||||||
|
if (biggestHoleAlphaFactor > 0)
|
||||||
|
{
|
||||||
|
isHidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
currentColor.a *= biggestHoleAlphaFactor;
|
currentColor.a *= biggestHoleAlphaFactor;
|
||||||
return currentColor;
|
return currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MaskedSprite::isVisible() const
|
||||||
|
{
|
||||||
|
return !isHidden;
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ public:
|
||||||
|
|
||||||
void setRotation(float angle) override;
|
void setRotation(float angle) override;
|
||||||
|
|
||||||
|
bool isVisible() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<sf::Sprite> sprite;
|
std::shared_ptr<sf::Sprite> sprite;
|
||||||
std::shared_ptr<sf::Texture> maskedTexture;
|
std::shared_ptr<sf::Texture> maskedTexture;
|
||||||
|
@ -34,7 +36,11 @@ private:
|
||||||
std::shared_ptr<sf::Image> image;
|
std::shared_ptr<sf::Image> image;
|
||||||
sf::IntRect textureRect;
|
sf::IntRect textureRect;
|
||||||
float angle = 0;
|
float angle = 0;
|
||||||
|
float previousAngle = -10;
|
||||||
sf::Vector2f renderPosition;
|
sf::Vector2f renderPosition;
|
||||||
|
sf::Vector2f previousRenderPosition = sf::Vector2f(-10, 0);
|
||||||
|
|
||||||
|
bool isHidden = false;
|
||||||
|
|
||||||
void updateFreshMaskedSprite();
|
void updateFreshMaskedSprite();
|
||||||
|
|
||||||
|
|
|
@ -61,3 +61,8 @@ void SingleSprite::preRenderUpdate()
|
||||||
|
|
||||||
renderPosition = calculateRotatedCornerPosition(position, angle);
|
renderPosition = calculateRotatedCornerPosition(position, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SingleSprite::isVisible() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ public:
|
||||||
|
|
||||||
void preRenderUpdate() override;
|
void preRenderUpdate() override;
|
||||||
|
|
||||||
|
bool isVisible() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::Sprite sprite;
|
sf::Sprite sprite;
|
||||||
float angle = 0;
|
float angle = 0;
|
||||||
|
|
|
@ -25,6 +25,11 @@ public:
|
||||||
throw std::runtime_error("Sprite::getSprite() not implemented");
|
throw std::runtime_error("Sprite::getSprite() not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool isVisible() const
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Sprite::isVisible() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates a sprite around its center.
|
* Rotates a sprite around its center.
|
||||||
* @param angle [0, 360]
|
* @param angle [0, 360]
|
||||||
|
|
|
@ -46,3 +46,8 @@ void VersatileSprite::setRotation(float angle)
|
||||||
{
|
{
|
||||||
sprite->setRotation(angle);
|
sprite->setRotation(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VersatileSprite::isVisible() const
|
||||||
|
{
|
||||||
|
return sprite->isVisible();
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ public:
|
||||||
|
|
||||||
void setRotation(float angle) override;
|
void setRotation(float angle) override;
|
||||||
|
|
||||||
|
bool isVisible() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Sprite> sprite = nullptr;
|
std::shared_ptr<Sprite> sprite = nullptr;
|
||||||
};
|
};
|
||||||
|
|
37
src/typography/font_manager.cpp
Normal file
37
src/typography/font_manager.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "font_manager.hpp"
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
|
std::shared_ptr<FontManager> FontManager::getInstance()
|
||||||
|
{
|
||||||
|
if (singletonInstance == nullptr)
|
||||||
|
{
|
||||||
|
singletonInstance = std::make_shared<FontManager>();
|
||||||
|
}
|
||||||
|
return singletonInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::loadFont(const std::string &name, const std::string &fontPath)
|
||||||
|
{
|
||||||
|
auto font = std::make_shared<sf::Font>();
|
||||||
|
auto fullPath = FONT_BASE_PATH + fontPath;
|
||||||
|
if (!font->loadFromFile(fullPath))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to load font: " + fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
fonts[name] = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<sf::Font> FontManager::getFont(const std::string &name)
|
||||||
|
{
|
||||||
|
if (fonts.find(name) == fonts.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Font not found: " + name);
|
||||||
|
}
|
||||||
|
return fonts[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<sf::Font> FontManager::getDefaultFont()
|
||||||
|
{
|
||||||
|
return getFont(DEFAULT_FONT);
|
||||||
|
}
|
27
src/typography/font_manager.hpp
Normal file
27
src/typography/font_manager.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef HOLESOME_FONT_MANAGER_HPP
|
||||||
|
#define HOLESOME_FONT_MANAGER_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <SFML/Graphics/Font.hpp>
|
||||||
|
|
||||||
|
class FontManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<FontManager> getInstance();
|
||||||
|
|
||||||
|
void loadFont(const std::string &name, const std::string &fontPath);
|
||||||
|
|
||||||
|
std::shared_ptr<sf::Font> getFont(const std::string &name);
|
||||||
|
|
||||||
|
std::shared_ptr<sf::Font> getDefaultFont();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline std::shared_ptr<FontManager> singletonInstance = nullptr;
|
||||||
|
|
||||||
|
std::map<std::string, std::shared_ptr<sf::Font>> fonts;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //HOLESOME_FONT_MANAGER_HPP
|
Loading…
Reference in a new issue