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.