1
Graphique / Problème de collisions avec des tiles
« le: Janvier 16, 2014, 05:29:55 pm »
Bonjour à toutes et à tous!
Je m'excuse tout d'abord si mon sujet a déjà été traité dans un autre endroit du forum, ma recherche ne m'a pas permis de trouver un sujet correspondant à mon problème.
Voilà, j'ai suivi le tutoriel ici-même, concernant le tile mapping(celui avec les Vertex Array). Tout fontionne correctement pour l'affichage, c'est super!
Cependant, j'ai voulu ensuite gérer un système de collisions. Ayant déjà vu un tutoriel sur le site du zéro de fvirtman (http://fr.openclassrooms.com/informatique/cours/tile-mapping), j'ai repris son algorithme de déplacement et de collision optimisé, qui ne vérifie que les tiles occupées par le personnage lui même.
Et c'est ici que ça coince. J'avais d'abord tenté de simuler un rectangle, connaissant 4 vertices, mais les collisions ne fonctionnaient pas. J'ai ensuite recherché sur internet, et j'ai vu que je pouvais simplement faire un tableau de char en plus du tableau d'int, contenant les information de collision.
Sauf que, j'obtiens une erreur de segmentation. J'ai tout essayé pour stopper ça, mais, pour une raison qui m'échappe, le programme plante seulement lorsque je me déplace à droite. (en fait, je crois que c'est le moment ou le tile en x n'est plus le premier mais le deuxieme.) J'ai essayé de changer plein de choses, mais rien n'y fait, ça plante toujours .
Est-ce que le problème vient de mon adaptation d'un code conçu pour la SDL à la SFML? Ou alors une petite erreur bizarre qui traîne par ci par là?
Je vous remercie donc d'avance pour toutes vos réponses !!
Donc voilà mes deux petits fichiers (Etant donné que c'est un fichier de test, ne vous étonnez pas si les noms des objets c'est genre lol, j'ai pas d'idées quand je teste un principe ) :
tileMap.hpp (l'objet avec la maudite fonction collision)
et le main.cpp qui l'utilise:
Je m'excuse tout d'abord si mon sujet a déjà été traité dans un autre endroit du forum, ma recherche ne m'a pas permis de trouver un sujet correspondant à mon problème.
Voilà, j'ai suivi le tutoriel ici-même, concernant le tile mapping(celui avec les Vertex Array). Tout fontionne correctement pour l'affichage, c'est super!
Cependant, j'ai voulu ensuite gérer un système de collisions. Ayant déjà vu un tutoriel sur le site du zéro de fvirtman (http://fr.openclassrooms.com/informatique/cours/tile-mapping), j'ai repris son algorithme de déplacement et de collision optimisé, qui ne vérifie que les tiles occupées par le personnage lui même.
Et c'est ici que ça coince. J'avais d'abord tenté de simuler un rectangle, connaissant 4 vertices, mais les collisions ne fonctionnaient pas. J'ai ensuite recherché sur internet, et j'ai vu que je pouvais simplement faire un tableau de char en plus du tableau d'int, contenant les information de collision.
Sauf que, j'obtiens une erreur de segmentation. J'ai tout essayé pour stopper ça, mais, pour une raison qui m'échappe, le programme plante seulement lorsque je me déplace à droite. (en fait, je crois que c'est le moment ou le tile en x n'est plus le premier mais le deuxieme.) J'ai essayé de changer plein de choses, mais rien n'y fait, ça plante toujours .
Est-ce que le problème vient de mon adaptation d'un code conçu pour la SDL à la SFML? Ou alors une petite erreur bizarre qui traîne par ci par là?
Je vous remercie donc d'avance pour toutes vos réponses !!
Donc voilà mes deux petits fichiers (Etant donné que c'est un fichier de test, ne vous étonnez pas si les noms des objets c'est genre lol, j'ai pas d'idées quand je teste un principe ) :
tileMap.hpp (l'objet avec la maudite fonction collision)
#ifndef DEF_TILEMAP
#define DEF_TILEMAP
#include <SFML/Graphics.hpp>
#include <cstdlib>
#include <math.h>
enum {MUR, VIDE};
class TileMap : public sf::Drawable, public sf::Transformable // Classe inspirée du tutoriel de Laurent Gomila sur son site de la SFML
{
public:
bool load(const std::string &tileset, sf::Vector2u tailleTile, const int *tiles,unsigned int longueur, unsigned int hauteur, const char **lvlCollision)
{
int i,j;
int tu,tv;
//tbconversion doit faire la même taille et indique quels tiles sont des MURS ou du VIDE (true, false, false, true; par exemple)
// tile est un tableau à deux dimensions qui contient les nombres correspondants aux tiles
m_tailleTile = tailleTile;
//m_tbconv = tbconversion;
m_schema = tiles;
m_lvlCollis = lvlCollision;
if(!m_tileset.loadFromFile(tileset))
{
std::cout << "Erreur lors du chargement du tileset" << std::endl;
return false;
}
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(longueur*hauteur*4); // Redimensionnement a la taille du niveau
for(i = 0; i < longueur; i++)
{
for(j = 0; j < hauteur; j++)
{
int tileNumber = tiles[i + j * longueur];
//Position du tile dans le tileset
tu = tileNumber % (m_tileset.getSize().x / tailleTile.x); // ex: '2'-'0' = 2 / ...
tv = tileNumber / (m_tileset.getSize().x / tailleTile.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(i + j * longueur) * 4];
// on définit ses quatre coins
quad[0].position = sf::Vector2f(i * tailleTile.x, j * tailleTile.y);
quad[1].position = sf::Vector2f((i + 1) * tailleTile.x, j * tailleTile.y);
quad[2].position = sf::Vector2f((i + 1) * tailleTile.x, (j + 1) * tailleTile.y);
quad[3].position = sf::Vector2f(i * tailleTile.x, (j + 1) * tailleTile.y);
// on définit ses quatre coordonnées de texture
quad[0].texCoords = sf::Vector2f(tu * tailleTile.x, tv * tailleTile.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tailleTile.x, tv * tailleTile.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tailleTile.x, (tv + 1) * tailleTile.y);
quad[3].texCoords = sf::Vector2f(tu * tailleTile.x, (tv + 1) * tailleTile.y);
}
}
return true; // Tout s'est bied passé, on renvoie true
}
bool collision(sf::Sprite *perso) // Fonction inspirée du cours de fvirtman sur le Site du Zero
{
int xmin = 0, xmax = 0, ymin = 0, ymax = 0, i = 0, j = 0;
char tileCurrent = '0';
sf::Vector2f posPerso = perso->getPosition(); // On récupère la position du perso
// On determine quels tiles le perso "occupe"
xmin = posPerso.x / m_tailleTile.x;
ymin = posPerso.y / m_tailleTile.y;
xmax = (posPerso.x + perso->getGlobalBounds().width) / m_tailleTile.x;
ymax = (posPerso.y + perso->getGlobalBounds().height) / m_tailleTile.y;
std::cout << "xmin,xmax : " << xmin << ";" << xmax << std::endl;
for(i = xmin; i <= xmax; i++)
{
for(j = ymin; j <= ymax; j++)
{
std::cout << m_lvlCollis[j][i] << std::endl;
tileCurrent = m_lvlCollis[j][i];
std::cout << "xmin,xmax : " << xmin << ";" << xmax << std::endl;
//std::cout << "OMG:" << tileCurrent << std::endl;
if (tileCurrent != '0') // Si on est pas face à un tile VIDE (A revoir)
return true;
}
}
/* on sort du for ; il n'y a pas eu de collisions*/
return false;
}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const // fonction draw de la sfml
{
states.transform *= getTransform();
states.texture = &m_tileset;
target.draw(m_vertices, states);
}
sf::Texture m_tileset;
//bool *m_tbconv;
const int *m_schema;
const char **m_lvlCollis;
sf::Vector2u m_tailleTile;
sf::VertexArray m_vertices;
};
#endif // DEF_TILEMAP
#define DEF_TILEMAP
#include <SFML/Graphics.hpp>
#include <cstdlib>
#include <math.h>
enum {MUR, VIDE};
class TileMap : public sf::Drawable, public sf::Transformable // Classe inspirée du tutoriel de Laurent Gomila sur son site de la SFML
{
public:
bool load(const std::string &tileset, sf::Vector2u tailleTile, const int *tiles,unsigned int longueur, unsigned int hauteur, const char **lvlCollision)
{
int i,j;
int tu,tv;
//tbconversion doit faire la même taille et indique quels tiles sont des MURS ou du VIDE (true, false, false, true; par exemple)
// tile est un tableau à deux dimensions qui contient les nombres correspondants aux tiles
m_tailleTile = tailleTile;
//m_tbconv = tbconversion;
m_schema = tiles;
m_lvlCollis = lvlCollision;
if(!m_tileset.loadFromFile(tileset))
{
std::cout << "Erreur lors du chargement du tileset" << std::endl;
return false;
}
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(longueur*hauteur*4); // Redimensionnement a la taille du niveau
for(i = 0; i < longueur; i++)
{
for(j = 0; j < hauteur; j++)
{
int tileNumber = tiles[i + j * longueur];
//Position du tile dans le tileset
tu = tileNumber % (m_tileset.getSize().x / tailleTile.x); // ex: '2'-'0' = 2 / ...
tv = tileNumber / (m_tileset.getSize().x / tailleTile.x);
// on récupère un pointeur vers le quad à définir dans le tableau de vertex
sf::Vertex* quad = &m_vertices[(i + j * longueur) * 4];
// on définit ses quatre coins
quad[0].position = sf::Vector2f(i * tailleTile.x, j * tailleTile.y);
quad[1].position = sf::Vector2f((i + 1) * tailleTile.x, j * tailleTile.y);
quad[2].position = sf::Vector2f((i + 1) * tailleTile.x, (j + 1) * tailleTile.y);
quad[3].position = sf::Vector2f(i * tailleTile.x, (j + 1) * tailleTile.y);
// on définit ses quatre coordonnées de texture
quad[0].texCoords = sf::Vector2f(tu * tailleTile.x, tv * tailleTile.y);
quad[1].texCoords = sf::Vector2f((tu + 1) * tailleTile.x, tv * tailleTile.y);
quad[2].texCoords = sf::Vector2f((tu + 1) * tailleTile.x, (tv + 1) * tailleTile.y);
quad[3].texCoords = sf::Vector2f(tu * tailleTile.x, (tv + 1) * tailleTile.y);
}
}
return true; // Tout s'est bied passé, on renvoie true
}
bool collision(sf::Sprite *perso) // Fonction inspirée du cours de fvirtman sur le Site du Zero
{
int xmin = 0, xmax = 0, ymin = 0, ymax = 0, i = 0, j = 0;
char tileCurrent = '0';
sf::Vector2f posPerso = perso->getPosition(); // On récupère la position du perso
// On determine quels tiles le perso "occupe"
xmin = posPerso.x / m_tailleTile.x;
ymin = posPerso.y / m_tailleTile.y;
xmax = (posPerso.x + perso->getGlobalBounds().width) / m_tailleTile.x;
ymax = (posPerso.y + perso->getGlobalBounds().height) / m_tailleTile.y;
std::cout << "xmin,xmax : " << xmin << ";" << xmax << std::endl;
for(i = xmin; i <= xmax; i++)
{
for(j = ymin; j <= ymax; j++)
{
std::cout << m_lvlCollis[j][i] << std::endl;
tileCurrent = m_lvlCollis[j][i];
std::cout << "xmin,xmax : " << xmin << ";" << xmax << std::endl;
//std::cout << "OMG:" << tileCurrent << std::endl;
if (tileCurrent != '0') // Si on est pas face à un tile VIDE (A revoir)
return true;
}
}
/* on sort du for ; il n'y a pas eu de collisions*/
return false;
}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const // fonction draw de la sfml
{
states.transform *= getTransform();
states.texture = &m_tileset;
target.draw(m_vertices, states);
}
sf::Texture m_tileset;
//bool *m_tbconv;
const int *m_schema;
const char **m_lvlCollis;
sf::Vector2u m_tailleTile;
sf::VertexArray m_vertices;
};
#endif // DEF_TILEMAP
et le main.cpp qui l'utilise:
#include <SFML/Graphics.hpp>
#include <iostream>
#include "tileMap.hpp"
int main()
{
sf::RenderWindow window(sf::VideoMode(12*32, 12*32), "Tilemapping");
window.setVerticalSyncEnabled(true);
int i = 0, j = 0;
const std::string tileset("tileset.bmp");
TileMap carte;
sf::Texture texlol;
texlol.loadFromFile("bonhomme.png");
sf::Sprite lol;
lol.setTexture(texlol);
sf::IntRect lolp1;
int V = 6;
/* lol.move(36*V, 6*V); */
const int lvl[] = {
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,2,2,2,
0,0,0,0,0,0,0,0,0,4,4,4,
0,0,0,0,0,0,0,0,0,4,4,4,
1,1,1,1,1,3,3,2,2,2,2,2};
const char *lvlCollision[] = {
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000222"
"000000000444"
"000000000444"
"111113322222"};
carte.load(tileset, sf::Vector2u(32,32), lvl, 12, 12, lvlCollision);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
if(!carte.collision(&lol))
lol.move(0,-V);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
if(!carte.collision(&lol))
{
std::cout << "lol" << std::endl;
lol.move(0,V);
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
if(!carte.collision(&lol))
lol.move(V,0);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
if(!carte.collision(&lol))
lol.move(-V,0);
window.clear();
window.draw(carte);
window.draw(lol);
window.display();
}
return EXIT_SUCCESS;
}
#include <iostream>
#include "tileMap.hpp"
int main()
{
sf::RenderWindow window(sf::VideoMode(12*32, 12*32), "Tilemapping");
window.setVerticalSyncEnabled(true);
int i = 0, j = 0;
const std::string tileset("tileset.bmp");
TileMap carte;
sf::Texture texlol;
texlol.loadFromFile("bonhomme.png");
sf::Sprite lol;
lol.setTexture(texlol);
sf::IntRect lolp1;
int V = 6;
/* lol.move(36*V, 6*V); */
const int lvl[] = {
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,2,2,2,
0,0,0,0,0,0,0,0,0,4,4,4,
0,0,0,0,0,0,0,0,0,4,4,4,
1,1,1,1,1,3,3,2,2,2,2,2};
const char *lvlCollision[] = {
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000000"
"000000000222"
"000000000444"
"000000000444"
"111113322222"};
carte.load(tileset, sf::Vector2u(32,32), lvl, 12, 12, lvlCollision);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
if(!carte.collision(&lol))
lol.move(0,-V);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
if(!carte.collision(&lol))
{
std::cout << "lol" << std::endl;
lol.move(0,V);
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
if(!carte.collision(&lol))
lol.move(V,0);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
if(!carte.collision(&lol))
lol.move(-V,0);
window.clear();
window.draw(carte);
window.draw(lol);
window.display();
}
return EXIT_SUCCESS;
}