void load(const std::string& tileSet, sf::Vector2u tileSize, int* tiles,
unsigned int width, unsigned int height)
{
m_tileset.loadFromFile(tileSet);
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(width * height * 4);
for (unsigned int i = 0; i < width; ++i)
{
for (unsigned int j = 0; j < height; ++j)
{
int tileNumber = tiles[i + j * width];
sf::Vector2f topLeft(i * tileSize.x, j * tileSize.y);
sf::Vector2f topRight((i + 1) * tileSize.x, j * tileSize.y);
sf::Vector2f downLeft((i + 1) * tileSize.x, (j + 1) * tileSize.y);
sf::Vector2f downRight(i * tileSize.x, (j + 1) * tileSize.y);
sf::FloatRect rect(topLeft.x, topLeft.y, topRight.x - topLeft.x, downLeft.y - topLeft.y);
Tile tile(rect, tileNumber);
m_tiles.push_back(tile);
//Find the position in the tileset texture
int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
//Define its 4 corners
quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));
quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));
quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));
//Define its 4 texture coordinates
quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
}
}
}
That's the entirety of my drawing code.
Ok, here's the entirety of all of my relevant code:
Player.hpp
class Player : public Entity
{
public:
typedef std::shared_ptr<Player> Ptr;
static Ptr create(const std::string& id = "player") { Ptr temp(new Player(id)); return temp; }
void handleCollision();
void move(const sf::Vector2f& offset);
virtual void update(sf::Time dt);
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
Player(const std::string& id = "player", bool active = true);
sf::Texture m_texture;
sf::Sprite m_sprite;
sf::Vector2f m_viewArea;
bool nextPosValid(const sf::Vector2f& offset);
bool rectOverlapsTile(const sf::FloatRect& rect);
};
Player.cpp
Player::Player(const std::string& id, bool active) :
m_viewArea(sf::Vector2f(100, 100))
{
m_texture.loadFromFile("Resources/player.png");
m_sprite.setTexture(m_texture);
m_sprite.setPosition(350, 300);
registerAttribute("renderable", new bool(true));
registerAttribute("health", new int(20));
SceneManager::getView().setCenter(std::floor(350), std::floor(300));
SceneManager::getView().setSize(m_viewArea);
}
bool Player::nextPosValid(const sf::Vector2f& offset)
{
sf::Vector2f offsettedPos(std::floor(m_sprite.getPosition().x + offset.x), std::floor(m_sprite.getPosition().y + offset.y));
//The bounding rectangle of the future player
sf::FloatRect rect(offsettedPos, sf::Vector2f(std::floor(m_sprite.getGlobalBounds().width), std::floor(m_sprite.getGlobalBounds().height)));
if (SceneManager::getWorld().getCurrentCell()->getTileMap().collidesWithType(2, rect))
return false;
return true;
}
void Player::move(const sf::Vector2f& offset)
{
m_sprite.move(offset);
SceneManager::getView().move(offset);
}
void Player::update(sf::Time dt)
{
if (InputManager::isActive(User_Input::UPHOLD))
{
if (nextPosValid(sf::Vector2f(0, -100 * dt.asSeconds())))
move(sf::Vector2f(0, -100 * dt.asSeconds()));
}
if (InputManager::isActive(User_Input::LEFTHOLD))
{
if (nextPosValid(sf::Vector2f(-100 * dt.asSeconds(), 0)))
move(sf::Vector2f(-100 * dt.asSeconds(), 0));
}
if (InputManager::isActive(User_Input::DOWNHOLD))
{
if (nextPosValid(sf::Vector2f(0, 100 * dt.asSeconds())))
move(sf::Vector2f(0, 100 * dt.asSeconds()));
}
if (InputManager::isActive(User_Input::RIGHTHOLD))
{
if (nextPosValid(sf::Vector2f(100 * dt.asSeconds(), 0)))
move(sf::Vector2f(100 * dt.asSeconds(), 0));
}
if (InputManager::isActive(User_Input::PPRESS))
{
getAttribute<int>("health") -= 5;
std::cout << "Player health is now: " << getAttribute<int>("health") << std::endl;
}
if (InputManager::isActive(User_Input::VHOLD))
{
if (SceneManager::getView().getSize().x < 300 ||
SceneManager::getView().getSize().y < 300)
SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x + 0.5, SceneManager::getView().getSize().y + 0.5));
}
else if (InputManager::isActive(User_Input::IHOLD))
{
if (SceneManager::getView().getSize().x >= 100 ||
SceneManager::getView().getSize().y >= 100)
SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x - 0.5, SceneManager::getView().getSize().y - 0.5));
}
if (getAttribute<int>("health") <= 0)
setAttribute("renderable", new bool(false));
setPosition(m_sprite.getPosition());
setBounds(m_sprite.getGlobalBounds());
}
void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(m_sprite, states);
}
Tilemap.hpp
class TileMap : public sf::Drawable, public sf::Transformable
{
public:
struct Tile
{
Tile(const sf::FloatRect& bounds, int tileType) : bounds(bounds), tileType(tileType) {};
sf::FloatRect bounds;
int tileType;
};
void load(const std::string& tileSet, sf::Vector2u tileSize, int* tiles,
unsigned int width, unsigned int height)
{
m_tileset.loadFromFile(tileSet);
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(width * height * 4);
for (unsigned int i = 0; i < width; ++i)
{
for (unsigned int j = 0; j < height; ++j)
{
int tileNumber = tiles[i + j * width];
sf::Vector2f topLeft(i * tileSize.x, j * tileSize.y);
sf::Vector2f topRight((i + 1) * tileSize.x, j * tileSize.y);
sf::Vector2f downLeft((i + 1) * tileSize.x, (j + 1) * tileSize.y);
sf::Vector2f downRight(i * tileSize.x, (j + 1) * tileSize.y);
sf::FloatRect rect(topLeft.x, topLeft.y, topRight.x - topLeft.x, downLeft.y - topLeft.y);
Tile tile(rect, tileNumber);
m_tiles.push_back(tile);
//Find the position in the tileset texture
int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
//Define its 4 corners
quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));
quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));
quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));
//Define its 4 texture coordinates
quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
}
}
}
bool collidesWithType(int tileType, const sf::FloatRect& bounds)
{
for (auto& iter : m_tiles)
{
if (iter.tileType == tileType)
{
if (bounds.intersects(iter.bounds))
return true;
}
}
return false;
}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = &m_tileset;
target.draw(m_vertices, states);
}
sf::VertexArray m_vertices;
sf::Texture m_tileset;
std::vector<Tile> m_tiles;
};
As you can see, I tried using std::floor on my views and my tiles, but unfortunately nothing has been working so far.
Ok, here's the entirety of all of my relevant code:
Player.hpp
class Player : public Entity
{
public:
typedef std::shared_ptr<Player> Ptr;
static Ptr create(const std::string& id = "player") { Ptr temp(new Player(id)); return temp; }
void handleCollision();
void move(const sf::Vector2f& offset);
virtual void update(sf::Time dt);
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
Player(const std::string& id = "player", bool active = true);
sf::Texture m_texture;
sf::Sprite m_sprite;
sf::Vector2f m_viewArea;
bool nextPosValid(const sf::Vector2f& offset);
bool rectOverlapsTile(const sf::FloatRect& rect);
};
Player.cpp
Player::Player(const std::string& id, bool active) :
m_viewArea(sf::Vector2f(100, 100))
{
m_texture.loadFromFile("Resources/player.png");
m_sprite.setTexture(m_texture);
m_sprite.setPosition(350, 300);
registerAttribute("renderable", new bool(true));
registerAttribute("health", new int(20));
SceneManager::getView().setCenter(std::floor(350), std::floor(300));
SceneManager::getView().setSize(m_viewArea);
}
bool Player::nextPosValid(const sf::Vector2f& offset)
{
sf::Vector2f offsettedPos(std::floor(m_sprite.getPosition().x + offset.x), std::floor(m_sprite.getPosition().y + offset.y));
//The bounding rectangle of the future player
sf::FloatRect rect(offsettedPos, sf::Vector2f(std::floor(m_sprite.getGlobalBounds().width), std::floor(m_sprite.getGlobalBounds().height)));
if (SceneManager::getWorld().getCurrentCell()->getTileMap().collidesWithType(2, rect))
return false;
return true;
}
void Player::move(const sf::Vector2f& offset)
{
m_sprite.move(offset);
SceneManager::getView().move(offset);
}
void Player::update(sf::Time dt)
{
if (InputManager::isActive(User_Input::UPHOLD))
{
if (nextPosValid(sf::Vector2f(0, -100 * dt.asSeconds())))
move(sf::Vector2f(0, -100 * dt.asSeconds()));
}
if (InputManager::isActive(User_Input::LEFTHOLD))
{
if (nextPosValid(sf::Vector2f(-100 * dt.asSeconds(), 0)))
move(sf::Vector2f(-100 * dt.asSeconds(), 0));
}
if (InputManager::isActive(User_Input::DOWNHOLD))
{
if (nextPosValid(sf::Vector2f(0, 100 * dt.asSeconds())))
move(sf::Vector2f(0, 100 * dt.asSeconds()));
}
if (InputManager::isActive(User_Input::RIGHTHOLD))
{
if (nextPosValid(sf::Vector2f(100 * dt.asSeconds(), 0)))
move(sf::Vector2f(100 * dt.asSeconds(), 0));
}
if (InputManager::isActive(User_Input::PPRESS))
{
getAttribute<int>("health") -= 5;
std::cout << "Player health is now: " << getAttribute<int>("health") << std::endl;
}
if (InputManager::isActive(User_Input::VHOLD))
{
if (SceneManager::getView().getSize().x < 300 ||
SceneManager::getView().getSize().y < 300)
SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x + 0.5, SceneManager::getView().getSize().y + 0.5));
}
else if (InputManager::isActive(User_Input::IHOLD))
{
if (SceneManager::getView().getSize().x >= 100 ||
SceneManager::getView().getSize().y >= 100)
SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x - 0.5, SceneManager::getView().getSize().y - 0.5));
}
if (getAttribute<int>("health") <= 0)
setAttribute("renderable", new bool(false));
setPosition(m_sprite.getPosition());
setBounds(m_sprite.getGlobalBounds());
}
void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(m_sprite, states);
}
Tilemap.hpp
class TileMap : public sf::Drawable, public sf::Transformable
{
public:
struct Tile
{
Tile(const sf::FloatRect& bounds, int tileType) : bounds(bounds), tileType(tileType) {};
sf::FloatRect bounds;
int tileType;
};
void load(const std::string& tileSet, sf::Vector2u tileSize, int* tiles,
unsigned int width, unsigned int height)
{
m_tileset.loadFromFile(tileSet);
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(width * height * 4);
for (unsigned int i = 0; i < width; ++i)
{
for (unsigned int j = 0; j < height; ++j)
{
int tileNumber = tiles[i + j * width];
sf::Vector2f topLeft(i * tileSize.x, j * tileSize.y);
sf::Vector2f topRight((i + 1) * tileSize.x, j * tileSize.y);
sf::Vector2f downLeft((i + 1) * tileSize.x, (j + 1) * tileSize.y);
sf::Vector2f downRight(i * tileSize.x, (j + 1) * tileSize.y);
sf::FloatRect rect(topLeft.x, topLeft.y, topRight.x - topLeft.x, downLeft.y - topLeft.y);
Tile tile(rect, tileNumber);
m_tiles.push_back(tile);
//Find the position in the tileset texture
int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
//Define its 4 corners
quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));
quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));
quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));
//Define its 4 texture coordinates
quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
}
}
}
bool collidesWithType(int tileType, const sf::FloatRect& bounds)
{
for (auto& iter : m_tiles)
{
if (iter.tileType == tileType)
{
if (bounds.intersects(iter.bounds))
return true;
}
}
return false;
}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = &m_tileset;
target.draw(m_vertices, states);
}
sf::VertexArray m_vertices;
sf::Texture m_tileset;
std::vector<Tile> m_tiles;
};
As you can see, I tried using std::floor on my views and my tiles, but unfortunately nothing has been working so far.
You bumped... i repeat "Post minimal example that reproduces the error." i don't have time to waste going trough random code.
Meaning, you create a main function and you add intro it ONLY the things you need help with, make it compile and post the code, we will fix it for you.
By doing this you will most likely fix the mistake yourself.
EDIT:: also please, if you want to fix the error, post your specs, os, also did you update gpu drivers?
class TileMap : public sf::Drawable, public sf::Transformable
{
public:
bool load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height)
{
// load the tileset texture
if (!m_tileset.loadFromFile(tileset))
return false;
// resize the vertex array to fit the level size
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(width * height * 4);
// populate the vertex array, with one quad per tile
for (unsigned int i = 0; i < width; ++i)
for (unsigned int j = 0; j < height; ++j)
{
// get the current tile number
int tileNumber = tiles[i + j * width];
// find its position in the tileset texture
int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
// get a pointer to the current tile's quad
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
// define its 4 corners
quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y);
quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y);
quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y);
quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y);
// define its 4 texture coordinates
quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
}
return true;
}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
// apply the transform
states.transform *= getTransform();
// apply the tileset texture
states.texture = &m_tileset;
// draw the vertex array
target.draw(m_vertices, states);
}
sf::VertexArray m_vertices;
sf::Texture m_tileset;
};
int main()
{
// create the window
sf::RenderWindow window(sf::VideoMode(512, 256), "tilemap");
// define the level with an array of tile indices
const int level[] =
{
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 0, 0, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0,
0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 2, 0, 0,
0, 0, 1, 0, 1, 0, 2, 2, 0, 0, 1, 1, 1, 1, 2, 0,
2, 0, 1, 0, 1, 0, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 1, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1,
};
// create the tilemap from the level definition
TileMap map;
if (!map.load("spritesheet.png", sf::Vector2u(32, 32), level, 16, 8))
return -1;
// run the main loop
while (window.isOpen())
{
// handle events
sf::Event event;
while (window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
}
// draw the map
window.clear();
window.draw(map);
window.display();
}
return 0;
}
I wanted to attach the spritesheet that I'm using, but unfortunately it doesn't let me attach it to the post. For some reason it says that the upload folder is "full" and I need to contact an administrator, even though the file is only 136 bytes.
Thanks!