I'm trying to program a hexagon tile map by adapting the tile map code from
the vertex tutorial to use sf::TriangleFan hexes. Unfortunately, I'm getting some weird distortions of the tiles. I attached a screenshot. In the code I define the centre of the fan and then use trigonometry to define the corners of the hexagons. The math I used for that is from
here.. The texture is 110 x 64 pixels, white on the left half, red on the right half.
If anyone has an idea what's going with this I would be grateful.
#include <SFML/Graphics.hpp>
#include <cmath>
const double PI =3.141592653589793238462;
class TileMap : public sf::Drawable, public sf::Transformable
{
public:
bool load(const std::string& tileset, int hex_size, const int* tiles,
unsigned int map_width, unsigned int map_height, int relative_offset)
{
int offset = relative_offset * hex_size;
float height = hex_size * 2;
float width = std::sqrt(3) * hex_size;
// load the tileset texture
if (!m_tileset.loadFromFile(tileset))
return false;
// resize the vertex array to fit the level size
m_vertices.setPrimitiveType(sf::TrianglesFan);
m_vertices.resize(map_width * map_height * 8);
// populate the vertex array, with one fan per tile
for (unsigned int i = 0; i < map_width; ++i)
for (unsigned int j = 0; j < map_height; ++j)
{
// get the current tile number
int tileNumber = tiles[i + j * map_width];
// find its position in the tileset texture
int tx = tileNumber % (m_tileset.getSize().x / (int) width);
int ty = tileNumber / (m_tileset.getSize().x / width);
// get a pointer to the current tile's hex
sf::Vertex* hex = &m_vertices[(i + j * width) * 8];
// define its centre
hex[0].position= sf::Vector2f ( offset + i * width, offset + j * height);
//define its corners
for (int k = 1; k < 7; k++)
{
float angle = 2 * PI / 6 * (k + 0.5);
hex[k].position = sf::Vector2f (
hex[0].position.x + hex_size * cos(angle),
hex[0].position.y + hex_size * sin(angle) );
}
hex[7].position = hex[1].position;
// define its texture centre
hex[0].texCoords = sf::Vector2f(
(width/2) + (tx * width), hex_size + (ty * height) ) ;
//define its corners
for (int k = 1; k < 7; k++)
{
float angle = 2 * PI / 6 * (k + 0.5);
hex[k].texCoords = sf::Vector2f (
hex[0].texCoords.x + hex_size * cos(angle),
hex[0].texCoords.y + hex_size * sin(angle) );
}
hex[7].texCoords = hex[1].texCoords;
}
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, 1//, 0//, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
// create the tilemap from the level definition
TileMap map;
if (!map.load("tileset.png", 32, level, 3, 1, 2))
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;
}