First tile map properly working

This commit is contained in:
Maximilian Giller 2023-06-17 19:48:51 +02:00
parent 120fdb0a88
commit 27b6e1b324
35 changed files with 216 additions and 227 deletions

View file

@ -98,7 +98,7 @@ set(SOURCES
src/levels.hpp
src/sprites/tiling/tilemap.cpp
src/sprites/tiling/tilemap.hpp
src/sprites/tiling/tilemap_config.hpp src/tilemaps.hpp src/sprites/tiling/tileset_config.hpp src/sprites/tiling/tileset.cpp src/sprites/tiling/tileset.hpp)
src/sprites/tiling/tilemap_config.hpp src/sprites/tiling/tileset_config.hpp src/sprites/tiling/tileset.cpp src/sprites/tiling/tileset.hpp)
set(PHYSICS_00_SOURCES
src/prototypes/physics_00.cpp)

View file

@ -10,7 +10,7 @@ struct WorldCoordinates
WorldCoordinates(float x, float y, float z = 0) : x(x), y(y), z(z)
{}
WorldCoordinates(sf::Vector2f vector) : x(vector.x), y(vector.y), z(0)
explicit WorldCoordinates(sf::Vector2f vector) : x(vector.x), y(vector.y), z(0)
{}
float x;
@ -62,7 +62,7 @@ struct IsometricCoordinates
float y;
float depth; // Bigger means further back. Can be used for accurate rendering order.
sf::Vector2f toScreen() const
[[nodiscard]] sf::Vector2f toScreen() const
{
return {x, y};
}
@ -72,7 +72,7 @@ struct IsometricCoordinates
IsometricCoordinates(float x, float y, float depth = 0) : x(x), y(y), depth(depth)
{}
explicit IsometricCoordinates (sf::Vector2f vector) : x(vector.x), y(vector.y), depth(0)
explicit IsometricCoordinates(sf::Vector2f vector) : x(vector.x), y(vector.y), depth(0)
{}
};
@ -85,6 +85,9 @@ struct GridCoordinates
GridCoordinates(float x, float y) : x(x), y(y)
{}
GridCoordinates(int x, int y) : x(static_cast<float>(x)), y(static_cast<float>(y))
{}
};

View file

@ -23,15 +23,15 @@ GridCoordinates TranslatedCoordinates::grid() const {
return {referenceWordCoordinates.x - 0.5f, referenceWordCoordinates.y - 0.5f};
}
void TranslatedCoordinates::set(WorldCoordinates newWorldCoordinates) {
void TranslatedCoordinates::setWorld(WorldCoordinates newWorldCoordinates) {
this->worldCoordinates = newWorldCoordinates;
}
void TranslatedCoordinates::set(IsometricCoordinates newIsometricCoordinates) {
void TranslatedCoordinates::setIsometric(IsometricCoordinates newIsometricCoordinates) {
this->worldCoordinates = CoordinateTransformer::isometricToWorld(newIsometricCoordinates);
}
void TranslatedCoordinates::set(const TranslatedCoordinates& newCoordinates) {
void TranslatedCoordinates::setTranslated(const TranslatedCoordinates& newCoordinates) {
this->worldCoordinates = newCoordinates.world();
}
@ -54,7 +54,7 @@ void TranslatedCoordinates::setParent(std::shared_ptr<TranslatedCoordinates> par
this->worldCoordinates = offset;
}
void TranslatedCoordinates::set(GridCoordinates newGridCoordinates)
void TranslatedCoordinates::setGrid(GridCoordinates newGridCoordinates)
{
this->worldCoordinates = {newGridCoordinates.x + 0.5f, newGridCoordinates.y + 0.5f, 0};
}
@ -71,5 +71,5 @@ void TranslatedCoordinates::setScreenOffset(IsometricCoordinates offset)
TranslatedCoordinates::TranslatedCoordinates(GridCoordinates gridCoordinates)
{
set(gridCoordinates);
setGrid(gridCoordinates);
}

View file

@ -17,13 +17,13 @@ public:
[[nodiscard]] GridCoordinates grid() const;
void set(WorldCoordinates newWorldCoordinates);
void setWorld(WorldCoordinates newWorldCoordinates);
void set(const TranslatedCoordinates& newCoordinates);
void setTranslated(const TranslatedCoordinates& newCoordinates);
void set(IsometricCoordinates newIsometricCoordinates);
void setIsometric(IsometricCoordinates newIsometricCoordinates);
void set(GridCoordinates newGridCoordinates);
void setGrid(GridCoordinates newGridCoordinates);
void move(WorldCoordinates deltaWorldCoordinates);

View file

@ -98,7 +98,7 @@ void TrackingView::followTrackables()
auto trackingPoint = getTrackingArea().getCenter();
if (DEVELOPER_MODE)
{
marker->coordinates->set(IsometricCoordinates(trackingPoint));
marker->coordinates->setIsometric(IsometricCoordinates(trackingPoint));
}
// Calculate distance to target to check how to handle it

View file

@ -7,8 +7,8 @@
struct TrackingViewOptions
{
/**
* Value >1 to set pixel radius.
* Value between 0 and 1 to set relative radius based on smallest half-axis-size.
* Value >1 to setWorld pixel radius.
* Value between 0 and 1 to setWorld relative radius based on smallest half-axis-size.
*/
float freeMoveThreshold = DEF_TV_FREE_MOVE_THRESHOLD;
@ -22,24 +22,24 @@ struct TrackingViewOptions
float softResizeSpeed = DEF_TV_SOFT_RESIZE_SPEED;
/**
* If set to 0, view will not be limited.
* If setWorld to 0, view will not be limited.
*/
sf::Vector2f minViewSize = DEF_TV_MIN_VIEW_SIZE;
/**
* If set to 0, view will not be limited.
* If setWorld to 0, view will not be limited.
*/
sf::Vector2f maxViewSize = DEF_TV_MAX_VIEW_SIZE;
/**
* Will be added to tracked area size twice, as padding for each side.
* Value >1 to set pixel padding.
* Value between 0 and 1 to set relative padding.
* Value >1 to setWorld pixel padding.
* Value between 0 and 1 to setWorld relative 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.
* If setWorld to true, view will add all new players automatically and remove them accordingly, based on PlayerCollection.
*/
bool addPlayersDynamically = DEF_TV_ADD_PLAYERS_DYNAMICALLY;
};

View file

@ -5,7 +5,7 @@ std::shared_ptr<Collectable> CollectableFactory::createFromInLevelConfig(const C
auto collectableConfig = config.collectableConfig;
auto collectable = std::make_shared<Collectable>();
collectable->coordinates->set(config.position);
collectable->coordinates->setGrid(config.position);
collectable->setSprite(collectableConfig.spriteName);
return collectable;

View file

@ -8,28 +8,28 @@
#include "../collectables/collectable_in_level.hpp"
#include <vector>
#include "../../sprites/tiling/tilemap_config.hpp"
#include "../../sprites/sprite_factory.hpp"
struct LevelConfig
{
std::string name;
sf::Vector2f worldMapSize = {};
sf::Vector2i worldMapSize = {};
TileMapConfig tileMapConfig = {};
std::vector<GridCoordinates> playerSpawnPoints = {};
std::vector<CollectableInLevel> collectables = {};
LevelConfig(std::string name,
const std::string &tileMapName,
const std::vector<GridCoordinates> &playerSpawnPoints,
const std::vector<CollectableInLevel> &collectables = {})
const std::vector<CollectableInLevel> &collectables,
const TileMapConfig &tileMapConfig)
: name(std::move(name)),
worldMapSize(worldMapSize),
playerSpawnPoints(playerSpawnPoints)
playerSpawnPoints(playerSpawnPoints),
tileMapConfig(tileMapConfig)
{
tileMapConfig = TileMapConfig(tileMapName, {});
worldMapSize = tileMapConfig.getSize();
// Remove invalid collectables
for (auto &collectable : collectables)
for (auto &collectable: collectables)
{
if (collectable.isValid())
{

View file

@ -20,6 +20,8 @@ void LevelLoader::loadLevel(const LevelConfig &levelConfig)
PlayerCollection::getInstance()->clear();
// Add basic game objects
game->addGameObject(SpriteFactory::createTileMap(levelConfig.tileMapConfig));
if (DEVELOPER_MODE)
{
game->addGameObject(std::make_shared<GridDebugLayer>(0, 50, 0, 50));
@ -43,12 +45,6 @@ void LevelLoader::loadLevel(const LevelConfig &levelConfig)
// 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 << "'.";
}

View file

@ -20,7 +20,7 @@ void MapPlayer::updateSimulationPosition()
void MapPlayer::updatePlayerPosition() const
{
b2Vec2 playerPosition = body->GetPosition();
player->coordinates->set(sf::Vector2f(playerPosition.x, playerPosition.y));
player->coordinates->setWorld({playerPosition.x, playerPosition.y});
}
void MapPlayer::updateShape()
@ -28,7 +28,8 @@ void MapPlayer::updateShape()
shapeRadius = player->getWorldRadius();
b2Fixture *oldFixture = body->GetFixtureList();
if (oldFixture != nullptr) {
if (oldFixture != nullptr)
{
body->DestroyFixture(oldFixture);
}

View file

@ -33,7 +33,7 @@ void MapSimulation::physicsUpdate()
}
}
void MapSimulation::resetMap(sf::Vector2f worldMapSize)
void MapSimulation::resetMap(sf::Vector2<int> worldMapSize)
{
// Clear all players
for (auto &mapPlayer: mapPlayersById)

View file

@ -16,7 +16,7 @@ public:
void physicsUpdate() override;
void resetMap(sf::Vector2f worldMapSize);
void resetMap(sf::Vector2<int> worldMapSize);
static std::shared_ptr<MapSimulation> getInstance();

View file

@ -8,7 +8,7 @@ Player::Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &
: spawnPosition(initCoordinates)
{
playerId = playerCreationCounter++;
coordinates->set(spawnPosition);
coordinates->setTranslated(spawnPosition);
input = std::move(assignedInput);
@ -94,8 +94,3 @@ void Player::setWorldRadius(float newWorldRadius)
skinSprite->setSize(newSize);
skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f));
}
Player::~Player()
{
LOG(INFO) << "Player " << playerId << " destroyed.";
}

View file

@ -13,8 +13,6 @@ public:
Player(std::shared_ptr<InputIdentity> assignedInput, const std::string &skinRessourceName,
GridCoordinates initCoordinates);
~Player();
void update() override;
[[nodiscard]] sf::Vector2f getTrackablePosition() const override;

View file

@ -8,9 +8,19 @@
#define INITIAL_LEVEL "default"
std::map<std::string, LevelConfig> const all_levels = {
{"default", LevelConfig("Default", "grass", {{0, 0}}, {
CollectableInLevel("box", {5, 5})
})}
{"default", LevelConfig("Default", {{0, 0}}, {
CollectableInLevel("box", {5, 5})},
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, 0, 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}})
)}
};
#endif //HOLESOME_LEVELS_HPP

View file

@ -694,7 +694,7 @@ class ConfigurationTypeHelper : base::StaticClass {
/// This bool represent whether or not to exit iterating through configurations.
static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function<bool(void)>& fn);
};
/// @brief Flags used while writing logs. This flags are set by user
/// @brief Flags used while writing logs. This flags are setWorld by user
enum class LoggingFlag : base::type::EnumType {
/// @brief Makes sure we have new line for each container log entry
NewLineForContainer = 1,
@ -1701,7 +1701,7 @@ class Configuration : public Loggable {
}
/// @brief Set string based configuration value
/// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values
/// @param value Value to setWorld. Values have to be std::string; For boolean values use "true", "false", for any integral values
/// use them in quotes. They will be parsed when configuring
inline void setValue(const std::string& value) {
m_value = value;
@ -1735,9 +1735,9 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Default constructor with empty repository
Configurations(void);
/// @brief Constructor used to set configurations using configuration file.
/// @brief Constructor used to setWorld configurations using configuration file.
/// @param configurationFile Full path to configuration file
/// @param useDefaultsForRemaining Lets you set the remaining configurations to default.
/// @param useDefaultsForRemaining Lets you setWorld the remaining configurations to default.
/// @param base If provided, this configuration will be based off existing repository that this argument is pointing to.
/// @see parseFromFile(const std::string&, Configurations* base)
/// @see setRemainingToDefault()
@ -1750,7 +1750,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Parses configuration from file.
/// @param configurationFile Full path to configuration file
/// @param base Configurations to base new configuration repository off. This value is used when you want to use
/// existing Configurations to base all the values and then set rest of configuration via configuration file.
/// existing Configurations to base all the values and then setWorld rest of configuration via configuration file.
/// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
/// do not proceed without successful parse.
bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr);
@ -1760,7 +1760,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
/// new line characters are provided.
/// @param base Configurations to base new configuration repository off. This value is used when you want to use
/// existing Configurations to base all the values and then set rest of configuration via configuration text.
/// existing Configurations to base all the values and then setWorld rest of configuration via configuration text.
/// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
/// do not proceed without successful parse.
bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr);
@ -1783,9 +1783,9 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Sets value of configuration for specified level.
///
/// @detail Any existing configuration for specified level will be replaced. Also note that configuration types
/// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for
/// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not setWorld for
/// Level::Global because these configurations are not dependant on level.
/// @param level Level to set configuration for (el::Level).
/// @param level Level to setWorld configuration for (el::Level).
/// @param configurationType Type of configuration (el::ConfigurationType)
/// @param value A string based value. Regardless of what the data type of configuration is, it will always be string
/// from users' point of view. This is then parsed later to be used internally.
@ -1795,7 +1795,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
void set(Level level, ConfigurationType configurationType, const std::string& value);
/// @brief Sets single configuration based on other single configuration.
/// @see set(Level level, ConfigurationType configurationType, const std::string& value)
/// @see setWorld(Level level, ConfigurationType configurationType, const std::string& value)
void set(Configuration* conf);
inline Configuration* get(Level level, ConfigurationType configurationType) {
@ -1806,7 +1806,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Sets configuration for all levels.
/// @param configurationType Type of configuration
/// @param value String based value
/// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value)
/// @see Configurations::setWorld(Level level, ConfigurationType configurationType, const std::string& value)
inline void setGlobally(ConfigurationType configurationType, const std::string& value) {
setGlobally(configurationType, value, false);
}
@ -1819,7 +1819,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Gets configuration file used in parsing this configurations.
///
/// @detail If this repository was set manually or by text this returns empty string.
/// @detail If this repository was setWorld manually or by text this returns empty string.
inline const std::string& configurationFile(void) const {
return m_configurationFile;
}
@ -1827,11 +1827,11 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Sets configurations to "factory based" configurations.
void setToDefault(void);
/// @brief Lets you set the remaining configurations to default.
/// @brief Lets you setWorld the remaining configurations to default.
///
/// @detail By remaining, it means that the level/type a configuration does not exist for.
/// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets
/// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e,
/// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is setWorld to default i.e,
/// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor
/// and try to access a value, an error is thrown
void setRemainingToDefault(void);
@ -1846,7 +1846,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @param configurationFile Full path to configuration file
/// @param sender Sender configurations pointer. Usually 'this' is used from calling class
/// @param base Configurations to base new configuration repository off. This value is used when you want to use
/// existing Configurations to base all the values and then set rest of configuration via configuration file.
/// existing Configurations to base all the values and then setWorld rest of configuration via configuration file.
/// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
/// do not proceed without successful parse.
static bool parseFromFile(const std::string& configurationFile, Configurations* sender,
@ -1860,7 +1860,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @param configurationsString the configuration in plain text format
/// @param sender Sender configurations pointer. Usually 'this' is used from calling class
/// @param base Configurations to base new configuration repository off. This value is used when you want to use
/// existing Configurations to base all the values and then set rest of configuration via configuration text.
/// existing Configurations to base all the values and then setWorld rest of configuration via configuration text.
/// @return True if successfully parsed, false otherwise.
static bool parseFromText(const std::string& configurationsString, Configurations* sender,
Configurations* base = nullptr);
@ -1883,7 +1883,7 @@ class Configurations : public base::utils::RegistryWithPred<Configuration, Confi
/// @brief Unsafely sets configuration if does not already exist
void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value);
/// @brief Thread unsafe set
/// @brief Thread unsafe setWorld
void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value);
/// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true
@ -3839,7 +3839,7 @@ class Loggers : base::StaticClass {
static std::vector<std::string>* populateAllLoggerIds(std::vector<std::string>* targetList);
/// @brief Sets configurations from global configuration file.
static void configureFromGlobal(const char* globalConfigurationFilePath);
/// @brief Configures loggers using command line arg. Ensure you have already set command line args,
/// @brief Configures loggers using command line arg. Ensure you have already setWorld command line args,
/// @return False if invalid argument or argument with no value provided, true if attempted to configure logger.
/// If true is returned that does not mean it has been configured successfully, it only means that it
/// has attempted to configure logger using configuration file provided in argument

View file

@ -44,3 +44,8 @@ sf::Vector2f AnimatedSprite::getSize() const
auto textureSize = sprites[currentFrame].getTextureRect();
return {textureSize.width * scale.x, textureSize.height * scale.y};
}
sf::Sprite AnimatedSprite::getSprite() const
{
return sprites[currentFrame];
}

View file

@ -9,7 +9,7 @@
class AnimatedSprite : public GameObject, public Sprite
{
public:
AnimatedSprite(const std::vector<sf::Sprite>& sprites, const sf::Vector2f& size = sf::Vector2f(0, 0));
explicit AnimatedSprite(const std::vector<sf::Sprite>& sprites, const sf::Vector2f& size = sf::Vector2f(0, 0));
void update() override;
@ -19,7 +19,9 @@ public:
void setSize(const sf::Vector2f &size) override;
sf::Vector2f getSize() const override;
[[nodiscard]] sf::Vector2f getSize() const override;
sf::Sprite getSprite() const override;
private:
int currentFrame = 0;

View file

@ -37,3 +37,8 @@ sf::Vector2f SingleSprite::getSize() const
auto textureSize = sprite.getTextureRect();
return {textureSize.width * sprite.getScale().x, textureSize.height * sprite.getScale().y};
}
sf::Sprite SingleSprite::getSprite() const
{
return sprite;
}

View file

@ -19,6 +19,8 @@ public:
sf::Vector2f getSize() const override;
sf::Sprite getSprite() const override;
private:
sf::Sprite sprite;
};

View file

@ -3,16 +3,26 @@
#include <SFML/System/Vector2.hpp>
#include <vector>
#include <memory>
#include <SFML/Graphics/Sprite.hpp>
class Sprite
{
public:
virtual void setSize(const sf::Vector2f &size)
{}
{
throw std::runtime_error("Sprite::setSize() not implemented");
}
virtual sf::Vector2f getSize() const
{ return {0, 0}; }
[[nodiscard]] virtual sf::Vector2f getSize() const
{
throw std::runtime_error("Sprite::getSize() not implemented");
}
[[nodiscard]] virtual sf::Sprite getSprite() const
{
throw std::runtime_error("Sprite::getSprite() not implemented");
}
};
#endif //HOLESOME_SPRITE_HPP

View file

@ -2,7 +2,7 @@
#include "../texture_config.h"
#include "texture_manager.hpp"
std::shared_ptr<SingleSprite> SpriteFactory::createSingleSprite(const std::string& name, sf::Vector2f size)
std::shared_ptr<SingleSprite> SpriteFactory::createSingleSprite(const std::string &name, sf::Vector2f size)
{
// Get sprite config
auto sprite_config = all_sprites.find(name);
@ -44,7 +44,7 @@ std::shared_ptr<SingleSprite> SpriteFactory::createSingleSprite(const std::strin
return sprite;
}
std::shared_ptr<AnimatedSprite> SpriteFactory::createAnimatedSprite(const std::string& name, sf::Vector2f size)
std::shared_ptr<AnimatedSprite> SpriteFactory::createAnimatedSprite(const std::string &name, sf::Vector2f size)
{
// Get animation config
auto animation_config = all_animations.find(name);
@ -72,7 +72,7 @@ std::shared_ptr<AnimatedSprite> SpriteFactory::createAnimatedSprite(const std::s
return animation;
}
std::shared_ptr<SpriteSheet> SpriteFactory::createSheet(const std::string& name)
std::shared_ptr<SpriteSheet> SpriteFactory::createSheet(const std::string &name)
{
// Get config
auto sheet_config = all_sheets.find(name);
@ -96,32 +96,6 @@ std::shared_ptr<SpriteSheet> SpriteFactory::createSheet(const std::string& name)
return std::make_shared<SpriteSheet>(texture, config.columns, config.rows);
}
std::shared_ptr<TileMap> SpriteFactory::createTileMap(const std::string &name)
{
// Get config
auto tilemap_config = all_tilemaps.find(name);
if (tilemap_config == all_tilemaps.end())
{
LOG(ERROR) << "Tilemap " << name << " not found. Could not create tilemap.";
return nullptr;
}
// Construct tilemap
auto config = tilemap_config->second;
std::shared_ptr<TileSet> tileSet = createTileSet(config.tileSheet);
if (sheet == nullptr)
{
LOG(ERROR) << "Sheet " << config.sheetName << " not found. Could not create tilemap.";
return nullptr;
}
LOG(INFO) << "Creating tilemap " << name;
auto tilemap = std::make_shared<TileMap>(sheet, config.tileSize, config.tileCount);
tilemap->setTilemap(config.tilemap);
return tilemap;
}
std::shared_ptr<TileSet> SpriteFactory::createTileSet(const std::string &name)
{
// Get config
@ -145,3 +119,20 @@ std::shared_ptr<TileSet> SpriteFactory::createTileSet(const std::string &name)
LOG(INFO) << "Creating tileset " << name;
return std::make_shared<TileSet>(sheet, config.tileIndices);
}
std::shared_ptr<SingleSprite> SpriteFactory::copySingleSprite(const std::shared_ptr<SingleSprite>& sprite)
{
return std::make_shared<SingleSprite>(sprite->getSprite(), sprite->getSize());
}
std::shared_ptr<TileMap> SpriteFactory::createTileMap(TileMapConfig config)
{
auto tileSet = createTileSet(config.tileSet);
if (tileSet == nullptr)
{
LOG(ERROR) << "Tileset " << config.tileSet << " not found. Could not create tilemap.";
return nullptr;
}
return std::make_shared<TileMap>(tileSet, config.tiles);
}

View file

@ -10,6 +10,7 @@
#include "../logging/easylogging++.h"
#include "tiling/tilemap.hpp"
#include "tiling/tileset.hpp"
#include "tiling/tilemap_config.hpp"
class SpriteFactory
{
@ -17,8 +18,9 @@ public:
static std::shared_ptr<SingleSprite> createSingleSprite(const std::string& name, sf::Vector2f size = sf::Vector2f(0, 0));
static std::shared_ptr<AnimatedSprite> createAnimatedSprite(const std::string& name, sf::Vector2f size = sf::Vector2f(0, 0));
static std::shared_ptr<SpriteSheet> createSheet(const std::string& name);
static std::shared_ptr<TileMap> createTileMap(const std::string& name);
std::shared_ptr<TileSet> createTileSet(const std::string &name);
static std::shared_ptr<TileSet> createTileSet(const std::string &name);
static std::shared_ptr<SingleSprite> copySingleSprite(const std::shared_ptr<SingleSprite>& sprite);
static std::shared_ptr<TileMap> createTileMap(TileMapConfig config);
};

View file

@ -1 +0,0 @@
#include "tilemap.hpp"

View file

@ -1,13 +0,0 @@
#ifndef HOLESOME_TILEMAP_HPP
#define HOLESOME_TILEMAP_HPP
#include "../../game/game_object.h"
class Tilemap : public GameObject
{
};
#endif //HOLESOME_TILEMAP_HPP

View file

@ -1,12 +0,0 @@
#ifndef HOLESOME_TILEMAP_CONFIG_HPP
#define HOLESOME_TILEMAP_CONFIG_HPP
#include <vector>
#include <string>
struct TilemapConfig {
std::string tileSheetName;
std::vector<std::vector<int>> tiles;
};
#endif //HOLESOME_TILEMAP_CONFIG_HPP

View file

@ -1,57 +1,35 @@
#include "tilemap.hpp"
#include "../sprite_factory.hpp"
TileMap::TileMap(std::shared_ptr<TileSet> tileSet, std::vector<std::vector<int>> tiles)
TileMap::TileMap(const std::shared_ptr<TileSet> &tileSet, std::vector<std::vector<int>> tiles)
{
// resize the vertex array to fit the level size
vertices.setPrimitiveType(sf::Quads);
unsigned int size = tiles.size();
vertices.resize(size * size * 4);
// populate the vertex array, with one quad per tile
for (unsigned int y = 0; y < size; ++y)
for (unsigned int x = 0; x < size; ++x)
{
// get the current tile number
int tileNumber = tiles[size - 1 - y][x];
// TODO
// Follow: https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php#example-tile-map
// find its position in the tileset texture
int tu = tileNumber % (tileset.getSize().y / tileSize.y);
int tv = tileNumber / (tileset.getSize().y / tileSize.y);
// get a pointer to the current tile's quad
sf::Vertex *quad = &vertices[(y + x * width) * 4];
// define its 4 corners
quad[0].position = sf::Vector2f(y * tileSize.y, x * tileSize.y);
quad[1].position = sf::Vector2f((y + 1) * tileSize.y, x * tileSize.y);
quad[2].position = sf::Vector2f((y + 1) * tileSize.y, (x + 1) * tileSize.y);
quad[3].position = sf::Vector2f(y * tileSize.y, (x + 1) * tileSize.y);
// define its 4 texture coordinates
quad[0].texCoords = sf::Vector2f(tu * tileSize.y, tv * tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.y, tv * tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.y, (tv + 1) * tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * tileSize.y, (tv + 1) * tileSize.y);
for (int i = 2 * (size - 1); i >= 0 ; i--)
{
int x, y;
if (i < size) {
x = i;
y = 0;
} else {
x = size - 1;
y = i - size + 1;
}
for (; x >= 0 && y < size; x--, y++)
{
auto tileId = tiles[size - 1 - y][x];
auto sprite = tileSet->getTile(tileId);
createTileAtGridPosition(sprite, {x, y});
}
}
}
void TileMap::draw(sf::RenderWindow *window)
void TileMap::createTileAtGridPosition(const std::shared_ptr<SingleSprite> &sprite, GridCoordinates coordinates)
{
window->draw(*this);
}
void TileMap::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
// apply the transform
// TODO? NEEDED?
// states.transform *= getTransform();
// apply the tileset texture
states.texture = &tileMapTexture;
// draw the vertex array
target.draw(vertices, states);
auto tile = SpriteFactory::copySingleSprite(sprite);
// Move to tile diagonal top left, since center of that tile is correct position for sprite corner
coordinates.y += 1;
addChildScreenOffset(tile, TranslatedCoordinates(coordinates).isometric());
}

View file

@ -8,18 +8,12 @@
#include "../../game/game_object.h"
#include "tileset.hpp"
class TileMap : public GameObject, public sf::Drawable
class TileMap : public GameObject
{
public:
TileMap(std::shared_ptr<TileSet> tileSet, std::vector<std::vector<int>> tiles);
TileMap(const std::shared_ptr<TileSet>& tileSet, std::vector<std::vector<int>> tiles);
void draw(sf::RenderWindow *window) override;
void draw(sf::RenderTarget &target, sf::RenderStates states) const override;
private:
sf::VertexArray vertices;
sf::Texture tileMapTexture;
void createTileAtGridPosition(const std::shared_ptr<SingleSprite>& sprite, GridCoordinates coordinates);
};

View file

@ -9,22 +9,18 @@
struct TileMapConfig
{
std::string tileSheet;
std::vector<int> backgroundTileSelection = {};
std::string tileSet;
std::vector<std::vector<int>> tiles = {};
TileMapConfig(std::string tileSheet, std::vector<std::vector<int>> tiles,
std::vector<int> backgroundTileSelection = {})
TileMapConfig(std::string tileSheet, const std::vector<std::vector<int>> &tiles)
{
this->tileSheet = std::move(tileSheet);
this->backgroundTileSelection = std::move(backgroundTileSelection);
this->tiles = std::move(tiles);
this->tileSet = std::move(tileSheet);
this->tiles = tiles;
// Make sure all rows are the same length and that the map is square
int size = tiles.size();
for (auto &row : tiles)
unsigned int size = tiles.size();
for (auto &row: tiles)
{
if (row.size() != size)
{
@ -35,10 +31,10 @@ struct TileMapConfig
TileMapConfig() = default;
sf::Vector2f getSize() const
[[nodiscard]] sf::Vector2<int> getSize() const
{
int size = tiles.size();
return {static_cast<float>(size), static_cast<float>(size)};
return {size, size};
}
};

View file

@ -1,6 +1,26 @@
#include "tileset.hpp"
TileSet::TileSet(const std::shared_ptr<SpriteSheet>& sheet, const std::vector<int>& tileIndices)
TileSet::TileSet(const std::shared_ptr<SpriteSheet> &sheet, const std::vector<int> &tileIndices)
{
float tileWidth = TranslatedCoordinates(WorldCoordinates{1, 0}).isometric().x -
TranslatedCoordinates(WorldCoordinates{0, 1}).isometric().x;
sf::Vector2f tileSize = sf::Vector2f(1, 1) * tileWidth;
// Load desired tiles from sheet
for (auto index: tileIndices)
{
auto sprite = sheet->getSprite(index);
sprite->setSize(tileSize);
tiles.push_back(sprite);
}
}
std::shared_ptr<SingleSprite> TileSet::getTile(int index) const
{
if (index < 0 || index >= tiles.size())
{
throw std::runtime_error("Tile index out of range");
}
return tiles[index];
}

View file

@ -3,11 +3,17 @@
#include "../sprite_sheet.hpp"
#include "../versatile_sprite.hpp"
class TileSet
{
public:
TileSet(const std::shared_ptr<SpriteSheet>& sheet, const std::vector<int>& tileIndices);
[[nodiscard]] std::shared_ptr<SingleSprite> getTile(int index) const;
private:
std::vector<std::shared_ptr<SingleSprite>> tiles;
};

View file

@ -47,3 +47,17 @@ sf::Vector2f VersatileSprite::getSize() const
return Sprite::getSize();
}
}
sf::Sprite VersatileSprite::getSprite() const
{
if (singleSprite != nullptr)
{
return singleSprite->getSprite();
} else if (animatedSprite != nullptr)
{
return animatedSprite->getSprite();
} else
{
return {};
}
}

View file

@ -12,11 +12,13 @@
class VersatileSprite : public GameObject, public Sprite
{
public:
VersatileSprite(const std::string& name, sf::Vector2f size = sf::Vector2f(0, 0));
explicit VersatileSprite(const std::string& name, sf::Vector2f size = sf::Vector2f(0, 0));
void setSize(const sf::Vector2f &size) override;
sf::Vector2f getSize() const override;
[[nodiscard]] sf::Vector2f getSize() const override;
sf::Sprite getSprite() const override;
private:
std::shared_ptr<SingleSprite> singleSprite = nullptr;

View file

@ -20,7 +20,8 @@ std::map<std::string, std::string> const all_textures = {
{"edge", "assets/edge.png"},
{"ring", "assets/ring.png"},
{"grasses", "assets/grass_plus.png"},
{"hole", "assets/hole.png"}
{"hole", "assets/hole.png"},
{"iso-tiles", "assets/isometric-tiles.png"}
};
/**
@ -28,8 +29,9 @@ std::map<std::string, std::string> const all_textures = {
* The key is the name of the sheet, the value is the sheet config.
*/
std::map<std::string, SheetConfig> const all_sheets = {
{"numbers", SheetConfig("numbers", 4, 2)},
{"grasses", SheetConfig("grasses", 25, 14)}
{"numbers", SheetConfig("numbers", 4, 2)},
{"grasses", SheetConfig("grasses", 25, 14)},
{"iso-tiles", SheetConfig("iso-tiles", 6, 2)}
};
/**
@ -45,14 +47,18 @@ std::map<std::string, AnimationConfig> const all_animations = {
* The key is the name of the singleSprite, the value is the singleSprite config.
*/
std::map<std::string, SpriteConfig> const all_sprites = {
{"64", SpriteConfig("64")},
{"64", SpriteConfig("64")},
{"edge", SpriteConfig("edge")},
{"ring", SpriteConfig("ring")},
{"hole", SpriteConfig("hole")}
};
/**
* All tilesets used in the game.
* The key is the name of the tileset, the value is the tileset config.
*/
std::map<std::string, TileSetConfig> const all_tilesets = {
{"grass", TileSetConfig("grasses", {58})}
{"iso-tiles", TileSetConfig("iso-tiles", {0, 1, 2, 3, 4, 5})}
};
#endif //HOLESOME_TEXTURE_CONFIG_H

View file

@ -1,21 +0,0 @@
#ifndef HOLESOME_TILEMAPS_HPP
#define HOLESOME_TILEMAPS_HPP
#include <map>
#include <string>
#include "sprites/tiling/tilemap_config.hpp"
std::map<std::string, TileMapConfig> const all_tilemaps = {
{"grass", TileMapConfig("grass", {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},})}
};
#endif //HOLESOME_TILEMAPS_HPP