Skip to content

Commit

Permalink
Merge pull request #157 from mward25/dev/feature/position_sfml_maps
Browse files Browse the repository at this point in the history
Allow offsets for tilemap in sfml demo
  • Loading branch information
fallahn committed May 19, 2024
2 parents 3633ea5 + c15167a commit ba50823
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 43 deletions.
111 changes: 73 additions & 38 deletions SFMLExample/src/SFMLOrthogonalLayer.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*********************************************************************
(c) Matt Marchant & contributors 2016 - 2019
(c) Matt Marchant & contributors 2016 - 2024
http://trederia.blogspot.com
tmxlite - Zlib license.
Expand Down Expand Up @@ -45,6 +45,7 @@ are implemented.
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/Transformable.hpp>
#include <SFML/System/Time.hpp>
#include <SFML/System/Vector2.hpp>

#include <memory>
#include <vector>
Expand Down Expand Up @@ -82,8 +83,8 @@ class MapLayer final : public sf::Drawable
const auto tileSize = map.getTileSize();
m_chunkSize.x = std::floor(m_chunkSize.x / tileSize.x) * tileSize.x;
m_chunkSize.y = std::floor(m_chunkSize.y / tileSize.y) * tileSize.y;
m_MapTileSize.x = map.getTileSize().x;
m_MapTileSize.y = map.getTileSize().y;
m_mapTileSize.x = map.getTileSize().x;
m_mapTileSize.y = map.getTileSize().y;
const auto& layer = layers[idx]->getLayerAs<tmx::TileLayer>();
createChunks(map, layer);

Expand All @@ -99,32 +100,35 @@ class MapLayer final : public sf::Drawable

const sf::FloatRect& getGlobalBounds() const { return m_globalBounds; }

void setTile(int tileX, int tileY, tmx::TileLayer::Tile tile, bool refresh = true)
void setTile(std::int32_t tileX, std::int32_t tileY, tmx::TileLayer::Tile tile, bool refresh = true)
{
sf::Vector2u chunkLocale;
const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale);
selectedChunk->setTile(chunkLocale.x, chunkLocale.y, tile, refresh);
}

tmx::TileLayer::Tile getTile(int tileX, int tileY)
tmx::TileLayer::Tile getTile(std::int32_t tileX, std::int32_t tileY)
{
sf::Vector2u chunkLocale;
const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale);
return selectedChunk->getTile(chunkLocale.x, chunkLocale.y);
}
void setColor(int tileX, int tileY, sf::Color color, bool refresh = true)
void setColor(std::int32_t tileX, std::int32_t tileY, sf::Color color, bool refresh = true)
{
sf::Vector2u chunkLocale;
const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale);
selectedChunk->setColor(chunkLocale.x, chunkLocale.y, color, refresh);
}

sf::Color getColor(int tileX, int tileY)
sf::Color getColor(std::int32_t tileX, std::int32_t tileY)
{
sf::Vector2u chunkLocale;
const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale);
return selectedChunk->getColor(chunkLocale.x, chunkLocale.y);
}

void setOffset(sf::Vector2f offset) { m_offset = offset; }
sf::Vector2f getOffset() const { return m_offset; }

void update(sf::Time elapsed)
{
Expand Down Expand Up @@ -161,8 +165,9 @@ class MapLayer final : public sf::Drawable
//sf::Vector2f m_chunkSize = sf::Vector2f(1024.f, 1024.f);
sf::Vector2f m_chunkSize = sf::Vector2f(512.f, 512.f);
sf::Vector2u m_chunkCount;
sf::Vector2u m_MapTileSize; // general Tilesize of Map
sf::Vector2u m_mapTileSize; // general Tilesize of Map
sf::FloatRect m_globalBounds;
sf::Vector2f m_offset;

using TextureResource = std::map<std::string, std::unique_ptr<sf::Texture>>;
TextureResource m_textureResource;
Expand All @@ -180,20 +185,23 @@ class MapLayer final : public sf::Drawable
{
public:
using Ptr = std::unique_ptr<Chunk>;

using Tile = std::array<sf::Vertex, 6u>;
Chunk(const tmx::TileLayer& layer, std::vector<const tmx::Tileset*> tilesets,
const sf::Vector2f& position, const sf::Vector2f& tileCount, const sf::Vector2u& tileSize,
std::size_t rowSize, TextureResource& tr, const std::map<std::uint32_t, tmx::Tileset::Tile>& animTiles)

Chunk(const tmx::TileLayer& layer, std::vector<const tmx::Tileset*> tilesets,
const sf::Vector2f& position, const sf::Vector2f& tileCount,
const sf::Vector2u& tileSize, std::size_t rowSize,
TextureResource& tr, const std::map<std::uint32_t, tmx::Tileset::Tile>& animTiles)
: m_animTiles(animTiles)
{
setPosition(position);
layerOpacity = static_cast<sf::Uint8>(layer.getOpacity() / 1.f * 255.f);

sf::Color vertColour = sf::Color(200 ,200, 200, layerOpacity);
auto offset = layer.getOffset();
layerOffset = { static_cast<float>(offset.x), static_cast<float>(offset.y) };
chunkTileCount = { tileCount.x, tileCount.y };
mapTileSize = tileSize;

const auto& tileIDs = layer.getTiles();

//go through the tiles and create all arrays (for latter manipulation)
Expand Down Expand Up @@ -229,7 +237,7 @@ class MapLayer final : public sf::Drawable
}
for (const auto& ca : m_chunkArrays)
{
sf::Uint32 idx = 0;
std::uint32_t idx = 0;
std::uint32_t xPos = static_cast<std::uint32_t>(getPosition().x / mapTileSize.x);
std::uint32_t yPos = static_cast<std::uint32_t>(getPosition().y / mapTileSize.y);
for (auto y = yPos; y < yPos + chunkTileCount.y; ++y)
Expand All @@ -251,17 +259,17 @@ class MapLayer final : public sf::Drawable
sf::Vector2f tileOffset(static_cast<float>(x) * mapTileSize.x, static_cast<float>(y) * mapTileSize.y + mapTileSize.y - ca->tileSetSize.y);

auto idIndex = m_chunkTileIDs[idx].ID - ca->m_firstGID;
sf::Vector2f tileIndex(idIndex % ca->tsTileCount.x, idIndex / ca->tsTileCount.x);
sf::Vector2f tileIndex(sf::Vector2i(idIndex % ca->tsTileCount.x, idIndex / ca->tsTileCount.x));
tileIndex.x *= ca->tileSetSize.x;
tileIndex.y *= ca->tileSetSize.y;
Tile tile =
{
sf::Vertex(tileOffset - getPosition(), m_chunkColors[idx], tileIndex),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(ca->tileSetSize.x, 0.f), m_chunkColors[idx], tileIndex + sf::Vector2f(ca->tileSetSize.x, 0.f)),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(ca->tileSetSize.x, ca->tileSetSize.y), m_chunkColors[idx], tileIndex + sf::Vector2f(ca->tileSetSize.x, ca->tileSetSize.y)),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(static_cast<float>(ca->tileSetSize.x), 0.f), m_chunkColors[idx], tileIndex + sf::Vector2f(static_cast<float>(ca->tileSetSize.x), 0.f)),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y))),
sf::Vertex(tileOffset - getPosition(), m_chunkColors[idx], tileIndex),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(ca->tileSetSize.x, ca->tileSetSize.y), m_chunkColors[idx], tileIndex + sf::Vector2f(ca->tileSetSize.x, ca->tileSetSize.y)),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(0.f, ca->tileSetSize.y), m_chunkColors[idx], tileIndex + sf::Vector2f(0.f, ca->tileSetSize.y))
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y))),
sf::Vertex(tileOffset - getPosition() + sf::Vector2f(0.f,static_cast<float>(ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(0.f, static_cast<float>(ca->tileSetSize.y)))
};
doFlips(m_chunkTileIDs[idx].flipFlags,&tile[0].texCoords,&tile[1].texCoords,&tile[2].texCoords,&tile[3].texCoords,&tile[4].texCoords,&tile[5].texCoords);
ca->addTile(tile);
Expand All @@ -274,25 +282,34 @@ class MapLayer final : public sf::Drawable
~Chunk() = default;
Chunk(const Chunk&) = delete;
Chunk& operator = (const Chunk&) = delete;
std::vector<AnimationState>& getActiveAnimations() { return m_activeAnimations; }
tmx::TileLayer::Tile getTile(int x, int y) const

std::vector<AnimationState>& getActiveAnimations()
{
return m_activeAnimations;
}

tmx::TileLayer::Tile getTile(std::int32_t x, std::int32_t y) const
{
return m_chunkTileIDs[calcIndexFrom(x,y)];
}
void setTile(int x, int y, tmx::TileLayer::Tile tile, bool refresh)

void setTile(std::int32_t x, std::int32_t y, tmx::TileLayer::Tile tile, bool refresh)
{
m_chunkTileIDs[calcIndexFrom(x,y)] = tile;
maybeRegenerate(refresh);
}
sf::Color getColor(int x, int y) const

sf::Color getColor(std::int32_t x, std::int32_t y) const
{
return m_chunkColors[calcIndexFrom(x,y)];
}
void setColor(int x, int y, sf::Color color, bool refresh)

void setColor(std::int32_t x, std::int32_t y, sf::Color color, bool refresh)
{
m_chunkColors[calcIndexFrom(x,y)] = color;
maybeRegenerate(refresh);
}

void maybeRegenerate(bool refresh)
{
if (refresh)
Expand All @@ -304,11 +321,16 @@ class MapLayer final : public sf::Drawable
generateTiles();
}
}
int calcIndexFrom(int x, int y) const

std::int32_t calcIndexFrom(std::int32_t x, std::int32_t y) const
{
return x + y * chunkTileCount.x;
return x + y * static_cast<std::int32_t>(chunkTileCount.x);
}

bool empty() const
{
return m_chunkArrays.empty();
}
bool empty() const { return m_chunkArrays.empty(); }

void flipY(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5)
{
Expand Down Expand Up @@ -428,9 +450,11 @@ class MapLayer final : public sf::Drawable
{
public:
using Ptr = std::unique_ptr<ChunkArray>;

tmx::Vector2u tileSetSize;
sf::Vector2u tsTileCount;
std::uint32_t m_firstGID, m_lastGID;

explicit ChunkArray(const sf::Texture& t, const tmx::Tileset& ts)
: m_texture(t)
{
Expand All @@ -450,14 +474,19 @@ class MapLayer final : public sf::Drawable
{
m_vertices.clear();
}

void addTile(const Chunk::Tile& tile)
{
for (const auto& v : tile)
{
m_vertices.push_back(v);
}
}
sf::Vector2u getTextureSize() const { return m_texture.getSize(); }

sf::Vector2u getTextureSize() const
{
return m_texture.getSize();
}

private:
const sf::Texture& m_texture;
Expand All @@ -478,6 +507,7 @@ class MapLayer final : public sf::Drawable
std::map<std::uint32_t, tmx::Tileset::Tile> m_animTiles; // animation catalogue
std::vector<AnimationState> m_activeAnimations; // Animations to be done in this chunk
std::vector<ChunkArray::Ptr> m_chunkArrays;

void draw(sf::RenderTarget& rt, sf::RenderStates states) const override
{
states.transform *= getTransform();
Expand All @@ -490,14 +520,16 @@ class MapLayer final : public sf::Drawable

std::vector<Chunk::Ptr> m_chunks;
mutable std::vector<Chunk*> m_visibleChunks;
Chunk::Ptr& getChunkAndTransform(int x, int y, sf::Vector2u& chunkRelative)

Chunk::Ptr& getChunkAndTransform(std::int32_t x, std::int32_t y, sf::Vector2u& chunkRelative)
{
uint32_t chunkX = floor((x * m_MapTileSize.x) / m_chunkSize.x);
uint32_t chunkY = floor((y * m_MapTileSize.y) / m_chunkSize.y);
chunkRelative.x = ((x * m_MapTileSize.x) - chunkX * m_chunkSize.x ) / m_MapTileSize.x ;
chunkRelative.y = ((y * m_MapTileSize.y) - chunkY * m_chunkSize.y ) / m_MapTileSize.y ;
std::uint32_t chunkX = (x * m_mapTileSize.x) / static_cast<std::uint32_t>(m_chunkSize.x);
std::uint32_t chunkY = (y * m_mapTileSize.y) / static_cast<std::uint32_t>(m_chunkSize.y);
chunkRelative.x = ((x * m_mapTileSize.x) - chunkX * static_cast<std::uint32_t>(m_chunkSize.x)) / m_mapTileSize.x ;
chunkRelative.y = ((y * m_mapTileSize.y) - chunkY * static_cast<std::uint32_t>(m_chunkSize.y)) / m_mapTileSize.y ;
return m_chunks[chunkX + chunkY * m_chunkCount.x];
}

void createChunks(const tmx::Map& map, const tmx::TileLayer& layer)
{
//look up all the tile sets and load the textures
Expand All @@ -524,7 +556,7 @@ class MapLayer final : public sf::Drawable
for (const auto& ts : usedTileSets)
{
const auto& path = ts->getImagePath();
//std::unique_ptr<sf::Texture> newTexture = std::make_unique<sf::Texture>();

std::unique_ptr<sf::Texture> newTexture = std::make_unique<sf::Texture>();
sf::Image img;
if (!img.loadFromFile(path))
Expand Down Expand Up @@ -578,17 +610,17 @@ class MapLayer final : public sf::Drawable
sf::Vector2f viewCorner = view.getCenter();
viewCorner -= view.getSize() / 2.f;

int posX = static_cast<int>(std::floor(viewCorner.x / m_chunkSize.x));
int posY = static_cast<int>(std::floor(viewCorner.y / m_chunkSize.y));
int posX2 = static_cast<int>(std::ceil((viewCorner.x + view.getSize().x) / m_chunkSize.x));
int posY2 = static_cast<int>(std::ceil((viewCorner.y + view.getSize().x)/ m_chunkSize.y));
std::int32_t posX = static_cast<std::int32_t>(std::floor(viewCorner.x / m_chunkSize.x));
std::int32_t posY = static_cast<std::int32_t>(std::floor(viewCorner.y / m_chunkSize.y));
std::int32_t posX2 = static_cast<std::int32_t>(std::ceil((viewCorner.x + view.getSize().x) / m_chunkSize.x));
std::int32_t posY2 = static_cast<std::int32_t>(std::ceil((viewCorner.y + view.getSize().x)/ m_chunkSize.y));

std::vector<Chunk*> visible;
for (auto y = posY; y < posY2; ++y)
{
for (auto x = posX; x < posX2; ++x)
{
std::size_t idx = y * int(m_chunkCount.x) + x;
std::size_t idx = y * std::int32_t(m_chunkCount.x) + x;
if (idx >= 0u && idx < m_chunks.size() && !m_chunks[idx]->empty())
{
visible.push_back(m_chunks[idx].get());
Expand All @@ -599,8 +631,11 @@ class MapLayer final : public sf::Drawable
std::swap(m_visibleChunks, visible);
}


void draw(sf::RenderTarget& rt, sf::RenderStates states) const override
{
states.transform.translate(m_offset);

//calc view coverage and draw nearest chunks
updateVisibility(rt.getView());
for (const auto& c : m_visibleChunks)
Expand Down
36 changes: 32 additions & 4 deletions SFMLExample/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*********************************************************************
(c) Matt Marchant & contributors 2016 - 2019
(c) Matt Marchant & contributors 2016 - 2024
http://trederia.blogspot.com
tmxlite - Zlib license.
Expand All @@ -25,12 +25,13 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/


#include "SFMLOrthogonalLayer.hpp"

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>

#include <tmxlite/Map.hpp>

#include "SFMLOrthogonalLayer.hpp"

int main()
{
Expand All @@ -44,18 +45,45 @@ int main()
MapLayer layerTwo(map, 2);

sf::Clock globalClock;
sf::Clock wiggleClock;

bool doWiggle = false;

while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}

else if( event.type == sf::Event::KeyPressed )
{
switch(event.key.code)
{
case sf::Keyboard::W:
// toggle doWiggle
doWiggle = !doWiggle;
break;
}
}
}


sf::Time duration = globalClock.restart();
layerZero.update(duration);

sf::Vector2f newOffset = sf::Vector2f(0.f, 0.f);
if (doWiggle)
{
newOffset = sf::Vector2f(std::cos(wiggleClock.getElapsedTime().asSeconds()) * 100.f, 0.f);
}
layerZero.setOffset(newOffset);
layerOne.setOffset(newOffset);
layerTwo.setOffset(newOffset);

window.clear(sf::Color::Black);
window.draw(layerZero);
window.draw(layerOne);
Expand Down
2 changes: 1 addition & 1 deletion tmxlite.sln
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Global
{2298A657-D09A-438E-B976-5EE827966124}.Debug|ARM.ActiveCfg = Debug|Win32
{2298A657-D09A-438E-B976-5EE827966124}.Debug|ARM64.ActiveCfg = Debug|Win32
{2298A657-D09A-438E-B976-5EE827966124}.Debug|x64.ActiveCfg = Debug|x64
{2298A657-D09A-438E-B976-5EE827966124}.Debug|x64.Build.0 = Debug|x64
{2298A657-D09A-438E-B976-5EE827966124}.Debug|x86.ActiveCfg = Debug|Win32
{2298A657-D09A-438E-B976-5EE827966124}.Debug|x86.Build.0 = Debug|Win32
{2298A657-D09A-438E-B976-5EE827966124}.Release|ARM.ActiveCfg = Release|Win32
Expand All @@ -83,7 +84,6 @@ Global
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Debug|ARM64.ActiveCfg = Debug|x64
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Debug|ARM64.Build.0 = Debug|x64
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Debug|x64.ActiveCfg = Debug|x64
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Debug|x64.Build.0 = Debug|x64
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Debug|x86.ActiveCfg = Debug|Win32
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Debug|x86.Build.0 = Debug|Win32
{70A3EB5D-CEB9-4353-9964-7023B6C07A44}.Release|ARM.ActiveCfg = Release|x64
Expand Down

0 comments on commit ba50823

Please sign in to comment.