I haven't worked on this for 2 days, so here's a cleaned code of how I left it.
I'm almost sure the problem resides in the main file, so other fils are here in case you want to test
Main :
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include "BackgroundTileMap.h"
#include <fstream>
#include <iostream>
#include <string>
int const TILESIZE = 32;
int main()
{
sf::RenderWindow window(sf::VideoMode(320, 320), "Tilemap");
sf::RenderWindow referencePic(sf::VideoMode(512, 512), "Tilemap", sf::Style::Titlebar); //Not tied to our problem, it's a secondary windows
//window.setVerticalSyncEnabled(true); Didn't solve the probleme in any way so we don't care : I got rid of it
window.setFramerateLimit(60);
sf::View view(sf::FloatRect(0, 0, 160, 160));
view.setViewport(sf::FloatRect(0, 0, 1, 1));
std::string fileoutputname;
// on définit le niveau à l'aide de numéro de tuiles
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, 3, 3, 3, 3, 3, 3, 3, 3,
0, 1, 0, 0, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 0, 0,
0, 1, 1, 0, 3, 3, 3, 0, 0, 0, 1, 1, 1, 2, 0, 0,
0, 0, 1, 0, 3, 0, 2, 2, 0, 0, 1, 1, 1, 1, 2, 0,
2, 0, 1, 0, 3, 0, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 3, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1,
};
// on crée la tilemap avec le niveau précédemment défini
BackgroundTileMap map;
if (!map.load("tileset_castle.png", sf::Vector2u(TILESIZE, TILESIZE), level, 16, 8))
return -1;
map.setRefWindow(&referencePic);
referencePic.setSize(sf::Vector2u(512,512));
referencePic.setTitle("Reference");
int newvalue;
int valueToApply = -1;
int brushSize = 1;
sf::Vector2i pixelPos;
sf::Vector2f worldPos;
sf::Vector2f wheelPos, wheelPos2;
bool wheelPressed = false;
// Main events handling
while (window.isOpen() || referencePic.isOpen())
{
// on gère les évènements
sf::Event event;
while (window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
window.close();
referencePic.close();
break;
case sf::Event::MouseButtonPressed:
pixelPos = sf::Mouse::getPosition(window);
worldPos = window.mapPixelToCoords(pixelPos);
worldPos.x /= TILESIZE;
worldPos.y /= TILESIZE;
newvalue = 1;
if (event.mouseButton.button == sf::Mouse::Right)
newvalue = -1;
if (event.mouseButton.button == sf::Mouse::Right || event.mouseButton.button == sf::Mouse::Left)
{
if (brushSize == 1)
{
if (valueToApply == -1)
map.changeTile((int)worldPos.x + (int)worldPos.y*map.getDimensions().x, newvalue);
else
map.changeTile((int)worldPos.x + (int)worldPos.y*map.getDimensions().x, valueToApply, false);
std::cout << "X : " << (int)worldPos.x << ". Y : " << (int)worldPos.y << std::endl;
}
else
{
for (int i = -brushSize +1 ; i < brushSize; i++)
for (int j = -brushSize +1; j < brushSize; j++)
{
if(map.getDimensions().x * j + i > 0)
{
if (valueToApply == -1)
map.changeTile((int)(worldPos.x + j) + (int)(worldPos.y+i)*map.getDimensions().x, newvalue);
else
map.changeTile((int)(worldPos.x + j) + (int)(worldPos.y+i)*map.getDimensions().x, valueToApply, false);
std::cout << "X : " << (int)worldPos.x << ". Y : " << (int)worldPos.y << std::endl;
}
}
}
/*
//*/
}
else if (event.mouseButton.button == sf::Mouse::Middle)
{
wheelPos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
wheelPressed = true;
}
break;
case sf::Event::MouseMoved:
if (wheelPressed)
{
wheelPos2 = window.mapPixelToCoords(sf::Mouse::getPosition(window));
wheelPos2.x = (int)(wheelPos.x - wheelPos2.x);
wheelPos2.y = (int)(wheelPos.y - wheelPos2.y);
view.move((float)wheelPos2.x, (float)wheelPos2.y);
std:: cout << (float)wheelPos2.x << "x" << (float)wheelPos2.y << std::endl;
wheelPos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
}
break;
case sf::Event::MouseButtonReleased:
if (wheelPressed && event.mouseButton.button == sf::Mouse::Middle)
wheelPressed = false;
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Subtract)
view.zoom(2.6);
else if (event.key.code == sf::Keyboard::Add)
view.zoom(0.38);
else if (event.key.code == sf::Keyboard::T)
{
pixelPos = sf::Mouse::getPosition(referencePic);
valueToApply = (int)(pixelPos.x / TILESIZE) + (int)(pixelPos.y / TILESIZE) * 16;
std::cout << valueToApply ;
}
else if (event.key.code == sf::Keyboard::Left)
{
view.move(-TILESIZE,0);
}
else if (event.key.code == sf::Keyboard::Right)
{
view.move(TILESIZE,0);
}
else if (event.key.code == sf::Keyboard::Up)
{
view.move(0,-TILESIZE);
}
else if (event.key.code == sf::Keyboard::Down)
{
view.move(0,TILESIZE);
}
break;
case sf::Event::MouseWheelScrolled:
if (event.mouseWheelScroll.delta < 0)
view.zoom(2.6);
else if (event.mouseWheelScroll.delta > 0)
view.zoom(0.38);
break;
default:
break;
}
//"Boucle" secondaire
referencePic.pollEvent(event);
switch (event.type)
{
case sf::Event::Closed:
referencePic.close();
break;
}
}
// on dessine le niveau
window.clear();
referencePic.clear();
//Arrondi de la vue
sf::Vector2f viewPos;
viewPos = view.getCenter();
viewPos.x = (int)viewPos.x;
viewPos.y = (int)viewPos.y;
view.setCenter(viewPos);
window.setView(view);
window.draw(map);
referencePic.display();
window.display();
}
return 0;
}
BackgroundTileMap.h
#ifndef BACKGROUNDTILEMAP_H
#define BACKGROUNDTILEMAP_H
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <string>
#include <sstream>
class BackgroundTileMap : public sf::Drawable, public sf::Transformable
{
public:
//tmp
//*
std::string WriteLevel() const
{
std::string retour = "";
for (int i = 0; i < m_level.size(); i++)
{
//retour += (m_level[i]+'0');
//retour += std::string(m_level[i]);
std::stringstream ss;
ss << m_level[i];
std::string str = ss.str();
retour += str;
retour += " ";
if ((i+1)%m_dimensions.x == 0)
retour+= "\r\n";
}
return retour;
}
bool WriteToFile(std::string const &filename);
const sf::Vector2u &getDimensions() const {return m_dimensions;}
const int getSize() const {return m_dimensions.x*m_dimensions.y;}
bool load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height);
bool setTexture(const std::string& texture) {
if (!m_tileset.loadFromFile(texture))
{ //Modification de la seconde fenetre
/*
if (secWindow != NULL)
{
sf::Sprite text(m_tileset);
secWindow->draw(text);
}
//*/
return false;
}
else return true;
}
bool loadNewMap(std::string const &filename); //fichier texte
bool changeTile(int tileNumber, int newvalue, bool addMode = true); //Si true, on met le tile suivant, si false, on change en valeur absolue
bool update();//Sans changer les valeurs
void CreateBlankMap(int newx, int newy);
void setRefWindow (sf::RenderWindow *new_window) {m_window = new_window;}
private:
sf::RenderWindow *m_window;
//attributs primaires
sf::VertexArray m_vertices;
sf::Texture m_tileset;
//attributs secondaires:
sf::Vector2u m_tileSize; //dimensions d'un Tile
sf::Vector2u m_dimensions; //Du tileset, en nombre de tiles (ex : 16*8)
std::vector<int> m_level; //contient les numéros d'un tile
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
// on applique la transformation
states.transform *= getTransform();
// on applique la texture du tileset
states.texture = &m_tileset;
// et on dessine enfin le tableau de vertex
target.draw(m_vertices, states);
//if(m_window->isOpen())
m_window->draw(sf::Sprite(m_tileset));
}
};
#endif // BACKGROUNDTILEMAP_H
And finally BackGroundTileMap.cpp
#include "BackgroundTileMap.h"
#include <fstream>
bool BackgroundTileMap::load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height)
{
// on charge la texture du tileset
if (!m_tileset.loadFromFile(tileset))
return false;
//Changement des "attributs secondaires"
m_tileSize = tileSize;
m_dimensions.x = width;
m_dimensions.y = height;
m_level.resize(width*height);
for (int i = 0; i < m_level.size(); i++)
{
m_level[i] = tiles[i];
}
// on redimensionne le tableau de vertex pour qu'il puisse contenir tout le niveau
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(width * height * 4);
// on remplit le tableau de vertex, avec un quad par tuile
for (unsigned int i = 0; i < width; ++i)
for (unsigned int j = 0; j < height; ++j)
{
// on récupère le numéro de tuile courant
int tileNumber = tiles[i + j * width];
// on en déduit sa position dans la texture du tileset
int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
// on définit ses quatre coins
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);
// on définit ses quatre coordonnées de texture
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;
}
bool BackgroundTileMap::loadNewMap(std::string const &filename)
{
//ouverture du fichier (avec la librairie standard)
std::ifstream file(filename.c_str());
if(!file.is_open())
return false;
std::string line;
//trois étapes : trouver la longuer, la largeur, les valeurs
int step = 0;
int value = 0;
m_dimensions.x=0;
m_dimensions.y=0;
m_level.resize(0);
while(step == 0)
{
std::getline(file, line);
if ( ! (std::istringstream(line) >> m_dimensions.x) ) return false;
//std::cout << "largeur "<<m_dimensions.x << std::endl;
if (m_dimensions.x > 0)
step++;
}
while(step == 1)
{
std::getline(file, line);
if ( ! (std::istringstream(line) >> m_dimensions.y) ) return false;
//std::cout << "hauteur "<< m_dimensions.y << std::endl;
if (m_dimensions.y > 0)
step++;
}
file.ignore();
while(step == 2)
{
char a;
file.get(a);
if (a == ':')
{
step++;
}
}
file.ignore();
while(m_level.size() < m_dimensions.y * m_dimensions.x)
{
file >> line;
if ( ! (std::istringstream(line) >> value) ) return false;
m_level.push_back(value);
}
file.close();
//std::cout << "fini !";
//suite
//Changement des "attributs secondaires"
//*
// m_tileSize = tileSize; //Déjà assigné : dans l'autre sens
sf::Vector2u tileSize = m_tileSize;
//m_dimensions.x = width; //ci-dessus
// m_dimensions.y = height;
int width = m_dimensions.x;
int height = m_dimensions.y;
if (m_level.size()!=width*height)
return false;
//for (int i = 0; i < m_level.size(); i++)
//{
// m_level[i] = tiles[i];
//}
// on redimensionne le tableau de vertex pour qu'il puisse contenir tout le niveau
//m_vertices.setPrimitiveType(sf::Quads); Pas besoin car déjà chargé
m_vertices.resize(width * height * 4);
// on remplit le tableau de vertex, avec un quad par tuile
for (unsigned int i = 0; i < width; ++i)
for (unsigned int j = 0; j < height; ++j)
{
// on récupère le numéro de tuile courant
int tileNumber = m_level[i + j * width];
// on en déduit sa position dans la texture du tileset
int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(i + j * width) * 4];
// on définit ses quatre coins
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);
// on définit ses quatre coordonnées de texture
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;
}
bool BackgroundTileMap::changeTile(int tileNumber, int newvalue, bool addMode)
{
if (addMode)
m_level[tileNumber] += newvalue;
else
m_level[tileNumber] = newvalue;
//std::cout << m_level[tileNumber];
return update();
/*
int width = m_dimensions.x;
int height = m_dimensions.y;
//int j = tileNumber%width;
//int i = tileNumber-(j*width); //x
// on en déduit sa position dans la texture du tileset
int tu = tileNumber % (m_tileset.getSize().x / m_tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / m_tileSize.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(tileNumber) * 4];
// on définit ses quatre coins
/* // La position ne change pas !
quad[0].position = sf::Vector2f(i * m_tileSize.x, j * m_tileSize.y);
quad[1].position = sf::Vector2f((i + 1) * m_tileSize.x, j * m_tileSize.y);
quad[2].position = sf::Vector2f((i + 1) * m_tileSize.x, (j + 1) * m_tileSize.y);
quad[3].position = sf::Vector2f(i * m_tileSize.x, (j + 1) * m_tileSize.y);
//*/
// on définit ses quatre coordonnées de texture
/* // défaillant
m_vertices[tileNumber*4].texCoords = sf::Vector2f(tu * m_tileSize.x, tv * m_tileSize.y);
m_vertices[tileNumber*4+1].texCoords = sf::Vector2f((tu + 1) * m_tileSize.x, tv * m_tileSize.y);
m_vertices[tileNumber*4+2].texCoords = sf::Vector2f((tu + 1) * m_tileSize.x, (tv + 1) * m_tileSize.y);
m_vertices[tileNumber*4+3].texCoords = sf::Vector2f(tu * m_tileSize.x, (tv + 1) * m_tileSize.y);
//*/
/* BACKUP
quad[0].texCoords = sf::Vector2f(tu * m_tileSize.x, tv * m_tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * m_tileSize.x, tv * m_tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * m_tileSize.x, (tv + 1) * m_tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * m_tileSize.x, (tv + 1) * m_tileSize.y);
//*/
/*/ TEST 0
quad[0].texCoords = sf::Vector2f(0,0);
quad[1].texCoords = sf::Vector2f(31,0);
quad[2].texCoords = sf::Vector2f(31,31);
quad[3].texCoords = sf::Vector2f(0,31);
//*/
//*/
return true;
}
bool BackgroundTileMap::update()
{
// on remplit le tableau de vertex, avec un quad par tuile
for (unsigned int i = 0; i < m_dimensions.x; ++i)
for (unsigned int j = 0; j < m_dimensions.y; ++j)
{
// on récupère le numéro de tuile courant
int tileNumber = m_level[i + j * m_dimensions.x];
// on en déduit sa position dans la texture du tileset
int tu = tileNumber % (m_tileset.getSize().x / m_tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / m_tileSize.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(i + j * m_dimensions.x) * 4];
// on définit ses quatre coins
quad[0].position = sf::Vector2f(i * m_tileSize.x, j * m_tileSize.y);
quad[1].position = sf::Vector2f((i + 1) * m_tileSize.x, j * m_tileSize.y);
quad[2].position = sf::Vector2f((i + 1) * m_tileSize.x, (j + 1) * m_tileSize.y);
quad[3].position = sf::Vector2f(i * m_tileSize.x, (j + 1) * m_tileSize.y);
// on définit ses quatre coordonnées de texture
quad[0].texCoords = sf::Vector2f(tu * m_tileSize.x, tv * m_tileSize.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * m_tileSize.x, tv * m_tileSize.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * m_tileSize.x, (tv + 1) * m_tileSize.y);
quad[3].texCoords = sf::Vector2f(tu * m_tileSize.x, (tv + 1) * m_tileSize.y);
}
//*/
return true;
}
bool BackgroundTileMap::WriteToFile(std::string const &filename)
{
std::ofstream outputFile;
outputFile.open(filename.c_str());
outputFile << m_dimensions.x << std::endl << m_dimensions.y << std::endl << std::endl << ":" << std::endl;
for (int i = 0; i < m_level.size(); i++)
{
outputFile << m_level[i] << " ";
}
}
void BackgroundTileMap::CreateBlankMap(int newx, int newy)
{
m_dimensions.x = newx;
m_dimensions.y = newy;
m_level.resize(newx*newy);
for (int i = 0; i < m_level.size(); i++)
{
m_level[i] = 0;
}
// on redimensionne le tableau de vertex pour qu'il puisse contenir tout le niveau
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(newx * newy * 4);
// on remplit le tableau de vertex, avec un quad par tuile
for (unsigned int i = 0; i < newx; ++i)
for (unsigned int j = 0; j < newy; ++j)
{
// on récupère le numéro de tuile courant
int tileNumber = m_level[i + j * newx];
// on en déduit sa position dans la texture du tileset
int tu = tileNumber % (m_tileset.getSize().x / m_tileSize.x);
int tv = tileNumber / (m_tileset.getSize().x / m_tileSize.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(i + j * newx) * 4];
// on définit ses quatre coins
quad[0].position = sf::Vector2f(i * m_tileSize.x, j * m_tileSize.y);
quad[1].position = sf::Vector2f((i + 1) * m_tileSize.x, j * m_tileSize.y);
quad[2].position = sf::Vector2f((i + 1) * m_tileSize.x, (j + 1) * m_tileSize.y);
quad[3].position = sf::Vector2f(i * m_tileSize.x, (j + 1) * m_tileSize.y);
// on définit ses quatre coordonnées de texture
quad[0].texCoords = sf::Vector2f(0,0);
quad[1].texCoords = sf::Vector2f(31,0);
quad[2].texCoords = sf::Vector2f(31,31);
quad[3].texCoords = sf::Vector2f(0,31);
}
}