-
Bonjour,
j'ai appliqué les astuces trouvées dans le forum pour gérer la collision entre mon personnage et un bloc de mon tileset (merci au passage) grâce au masque, mais j'ai un problème assez hargneux. En effet, quand il y a une collision mon personnage reste coincé sur place, je ne peux plus le déplacer. J'ai beau cherché, je ne vois pas l'erreur (de logique, ça compile bien). Si quelqu'un pouvait m'aider... je lui serais reconnaissant. Merci :)
Mon code, simplifié au possible :
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cmath>
#include "TileMap.cpp"
sf::RenderWindow window;
int speed=2;
sf::Texture perso;
sf::Sprite sprite_perso;
enum Dir{Down,Left,Right,Up};
sf::Vector2i anim(1, Down);
bool updateFPS = false;
int blockSize = 32;
sf::View view;
int screenW = 800;
int screenH = 600;
sf::Music music;
int LARGEUR_TILE = 40;
int HAUTEUR_TILE = 40;
bool colisionTile;
void gestionClavier();
bool collision(bool masque[], int x, int y, int tailleCase)
{
if( masque[ int(x/tailleCase) + 8*int(y/tailleCase) ] == 1)
return true;
return false;
}
int main()
{
// On crée la fenêtre et ses paramètres
window.create(sf::VideoMode(screenW,screenH), "Jeu v. 0.000001a");
window.setPosition(sf::Vector2i(192,200));
window.setFramerateLimit(60);
sf::Texture myTexture;
if (!myTexture.loadFromFile("tileset.png"))
std::cout << "ERREUR : load tileset" << std::endl;
else
std::cout << "tileset : Done" << std::endl;
sf::Sprite mySprite(myTexture);
// On définit le niveau
const int level[] =
{
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 1, 1, 1, 1, 9, 9,
0, 0, 0, 0, 0, 1, 1, 1, 9, 1, 1, 0, 0, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0,
0, 8, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
};
bool masque[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 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,
};
TileMap map;
if (!map.load("tileset.png", sf::Vector2u(40, 40), level, 16, 8))
return -1;
// Horloge
sf::Clock time;
// On vérifie que la sprite joueur est bien chargée
if(!perso.loadFromFile("player.png"))
{
std::cout << "Erreur: player.png non charge" << std::endl;
}
perso.setSmooth(true); // pour lisser la texture
// On applique les textures au sprite joueur
sprite_perso.setTexture(perso);
// Tant que la fenêtre est ouverte
while(window.isOpen())
{
sf::Event event;
// Test des évènements
while(window.pollEvent(event))
{
// Si on clique sur fermer
if (event.type == sf::Event::Closed)
window.close();
// Gestion des FPS
if(event.type == sf::Event::KeyPressed)
updateFPS = true;
else
updateFPS = false;
}
if (updateFPS == true)
{
if (time.getElapsedTime().asMilliseconds() >= 50)
{
anim.x--;
if (anim.x * blockSize >= perso.getSize().x)
anim.x = 2;
time.restart();
}
}
// Gestion texture
sprite_perso.setTextureRect(sf::IntRect(anim.x * blockSize, anim.y * blockSize, blockSize, blockSize));
colisionTile = collision(masque, sprite_perso.getPosition().x, sprite_perso.getPosition().y, 40);
if (colisionTile == true)
{
std::cout << colisionTile << std::endl;
}
else
{
std::cout << "pas de colision :"<< colisionTile <<std::endl;
gestionClavier();
}
colisionTile = false;
/* vue */
view.reset(sf::FloatRect(0,0, screenW, screenH));
sf::Vector2f position(screenW / 2, screenH / 2);
position.x = sprite_perso.getPosition().x + (blockSize / 2) - (screenW / 2);
position.y = sprite_perso.getPosition().y + (blockSize / 2) - (screenH / 2);
if(position.x <0)
position.x = 0;
if(position.y <0)
position.y = 0;
view.reset(sf::FloatRect(position.x, position.y, screenW, screenH));
window.setView(view);
// On dessine
window.draw(map);
window.draw(sprite_perso);
window.display();
window.clear();
}
return 0;
}
/* Autres fonctions */
void gestionClavier()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
anim.y = Up;
sprite_perso.move(0, -speed);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
anim.y = Down;
sprite_perso.move(0, speed);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
anim.y = Left;
sprite_perso.move(-speed, 0);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
anim.y = Right;
sprite_perso.move(speed, 0);
}
if(sprite_perso.getPosition().x <= 0)
sprite_perso.setPosition(sf::Vector2f(0, sprite_perso.getPosition().y));
if(sprite_perso.getPosition().y <= 0)
sprite_perso.setPosition(sf::Vector2f(sprite_perso.getPosition().x,0));
}
(le fichier TileMap.cpp est le même que celui des tutos officiel, je l'ai pas remis)
-
Ton problème vient de ton raisonnement au niveau de la gestion de collision, dans ta boucle if tu test si oui ou non il y a collision.
Ta fonction gestionClavier ( ) est la fonction permettant à ton personnage de se déplacer, si tu regarde bien dans ta boucle tu appelle cette fonction uniquement lorsqu'il n'y a pas collision, normal que ton personnage s'arrête de bouger dès qu'il entre en collision puisque tu n'appelle pas la fonction gestionClavier ( ).
Tu devrais plutôt faire en sorte que ton personnage puisse bouger vers une direction où il peut aller, car s'il est bloqué à droite il peut aller à gauche, donc revois ton test de collision ;)
-
Merci pour ta réponse, j'ai donc essayé de faire comme ceci :
colisionTile = collision(masque, sprite_perso.getPosition().x, sprite_perso.getPosition().y, 40);
if (colisionTile == true)
{
std::cout << colisionTile << std::endl;
}
else
{
std::cout << "pas colision"<< colisionTile <<std::endl;
}
colisionTile = false;
//Gestion du clavier
gestionClavier2();
gestionClavier();
// avec les fonctions
void gestionClavier()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (directionH == true))
{
anim.y = Up;
sprite_perso.move(0, -speed);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && (directionB == true))
{
anim.y = Down;
sprite_perso.move(0, speed);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (directionG == true))
{
anim.y = Left;
sprite_perso.move(-speed, 0);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && (directionD == true))
{
anim.y = Right;
sprite_perso.move(speed, 0);
}
if(sprite_perso.getPosition().x <= 0)
sprite_perso.setPosition(sf::Vector2f(0, sprite_perso.getPosition().y));
if(sprite_perso.getPosition().y <= 0)
sprite_perso.setPosition(sf::Vector2f(sprite_perso.getPosition().x,0));
}
void gestionClavier2()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (colisionTile == true))
{
directionG = true;
directionD = true;
directionH = false;
directionB = true;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && (colisionTile == true))
{
directionG = true;
directionD = true;
directionH = true;
directionB = false;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && (colisionTile == true))
{
directionG = false;
directionD = true;
directionH = true;
directionB = true;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && (colisionTile == true))
{
directionG = true;
directionD = false;
directionH = true;
directionB = true;
}
}
le problème est qu'une fois qu'il y a une collision elle reste en mémoire donc ce que j'ai fait ne peut pas fonctionner. Je ne sais pas comment résoudre le problème, soit mon personnage reste bloqué soit il passe complètement à travers les bloques. Qu'est-ce qui ne va pas ? (encore merci ;D)
-
Je te conseil d'aller voir du côté de ce tutoriel : http://fr.openclassrooms.com/informatique/cours/theorie-des-collisions/formes-simples
En gros ce qu'il faut que tu comprenne c'est que tu dois faire en sorte de calculer la position future de ton personnage que l'on va appeler position2, tu fais ton test de collision sur position2, s'il n'y a pas collision alors tu fais un perso.setPosition(position2), s'il y a collision tu n'applique pas la nouvelle position.
Pour obtenir position2 il suffit d'ajouter à la position de ton personnage la vitesse :
sf::Vector2f position2;
position2.x = perso.getPosition().x + vitesseX;
position2.y = perso.getPosition().y + vitesseY;
//Une fois que tu as calculé position2 tu test si en position2 il y a collision
if(PAS COLLISION)
{
perso.setPosition(position2);
}
else
std::cout<<"Collision !"<<std::endl;
vitesseX et vitesseY sont seulement des variables dont la valeur dépend des touches sur lesquels tu appuies.
Voilà j'espère t'avoir aidé ;)
-
Ok merci même si j'ai mis plusieurs longues heures pour essayer de comprendre et d'adapter ce que tu m'as dis à mon programme. J'ai donc procédé à quelques petits changements :
// dans le main
gestionClavier();
position2.x = sprite_perso.getPosition().x + vitesseX;
position2.y = sprite_perso.getPosition().y + vitesseY;
colisionTile = collision(masque, position2.x, position2.y, 40);
if(colisionTile == false)
{
sprite_perso.setPosition(position2);
std::cout<<" pas Collision !"<<std::endl;
}
else
std::cout<<"Collision !"<<std::endl;
// et dans la fonction
void gestionClavier()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
anim.y = Up;
vitesseY = -speed;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
anim.y = Down;
vitesseY = +speed;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
anim.y = Left;
vitesseX = -speed;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
anim.y = Right;
vitesseX = +speed;
}
if(sprite_perso.getPosition().x <= 0)
sprite_perso.setPosition(sf::Vector2f(0, sprite_perso.getPosition().y));
if(sprite_perso.getPosition().y <= 0)
sprite_perso.setPosition(sf::Vector2f(sprite_perso.getPosition().x,0));
}
Cependant mon personnage glisse continuellement avec cette méthode, même quand j'arrête d'appuyer. Une idée ? :)
Merci
-
Vu que la seule fois où tu affectes une valeur à vitesseX et vitesseY c'est quand tu appuies sur une touche donc ils gardent cette valeur même quand tu n'appuies plus.
Mets vitesseX et vitesseY à 0 avant gestionClavier.
-
Exact merci ! ;)
J'avais trouvé une autre solution sûrement moins adéquate en faisant :
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
position2.y = sprite_perso.getPosition().y + vitesseY;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
position2.x = sprite_perso.getPosition().x + vitesseX;
}
Par contre, une dernière petite chose. ;D Je croyais que l'endroit des collisions correspond à mon masque mais ce n'est pas le cas, les collisions se font à des endroits inattendus. (le code de la fonction collision et son masque est dans mon premier message). Savez-vous pourquoi ?
-
Il me semble que le problème vient de cette ligne :
if( masque[ int(x/tailleCase) + 8*int(y/tailleCase) ] == 1)
Ton masque fait 8 lignes pour 16 colonnes, donc ce n'est pas 8*int... Que tu dois écrire mais 16*int...
Remplace le 8 par un 16 et ça devrait aller mieux je pense :)
-
Je pensais que les colonnes se situaient sur l'axe des Y plutôt d'où le 8*int. Mais même en le passant à 16 les obstacles ont l'air un peu mieux placés mais ils ne correspondent pas exactement au masque. ( je peux rentrer dans des grosses zones où cela ne devrait pas être possible). Ce n'est pas que ça... :/
-
Regarde ce tuto il est en C mais la logique est la même : http://fr.openclassrooms.com/informatique/cours/tile-mapping/simple-personnage
J'espère que ça t'aidera à comprendre pourquoi ton personnage passe parfois à travers les tiles de ta map ;)
-
Merci je l'ai lu c'était instructif mais mon problème n'est pas que mon personnage passe à travers certaines tiles en raison d'un bug. En faite, ce sont des zones entières de collision qui sont au mauvais endroit (il y a collision ou il ne devrait pas et vise versa).
-
Ah excuse moi j'avais mal compris ;D
Par contre je ne vois pas pourquoi les zones de collision ne correspondent pas au masque, as tu pensé à gérer les collisions directement avec ton tableau "level" sans passer par un masque?
-
Je ne vois pas comment je pourrais faire sans le masque vu qu'il me sert justement à savoir s'il y a une collision sur une case correspondant à mon tableau level. Ce que je peux peut-être faire c'est donner mon code entier avec mon personnage et mon tileset pour que quelqu'un de plus expérimenté l'essaie et comprenne pourquoi.
main.cpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cmath>
#include "TileMap.cpp"
sf::RenderWindow window; // Fenêtre
sf::RectangleShape rectangle; // un objet rectangle
int speed=2; // vitesse du personnage
sf::Texture perso; // Texture du perso
sf::Sprite sprite_perso; // Pour récupérer son sprite
enum Dir{Down,Left,Right,Up}; // Pour le déplacement
sf::Vector2i anim(1, Down); // Animation du personnage
bool updateFPS = false; // Fps
int blockSize = 32; // Taille du personnage
sf::View view; // Vue
int screenW = 800; // Largeur fenêtre
int screenH = 600; // Hauteur fenêtre
int LARGEUR_TILE = 40; // largeur d'une tuile du décor
int HAUTEUR_TILE = 40; // hauteur d'une tuile du décor
bool colisionTile; // Vraie si collision, faux si pas collision
sf::Vector2f position2; // Position du personnage calculée
int vitesseX = 0; // Vitesse du personnage
int vitesseY = 0; // Vitesse du personnage
// Déclaration des fonctions (comme elles ne sont pas dans un header...)
void gestionClavier();
void gestionSouris();
void playMusic();
void gestionClavier2();
bool collision(bool[], int, int, int);
// Fonction principale
int main()
{
// On crée la fenêtre et ses paramètres
window.create(sf::VideoMode(screenW,screenH), "Jeu");
window.setPosition(sf::Vector2i(192,200));
window.setFramerateLimit(60);
//window.setKeyRepeatEnabled(false);
sf::Texture myTexture;
if (!myTexture.loadFromFile("tileset.png"))
std::cout << "ERREUR : load tileset" << std::endl;
else
std::cout << "tileset : Done" << std::endl;
sf::Sprite mySprite(myTexture);
// On définit le niveau
const int level[] =
{
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 1, 1, 1, 1, 9, 9,
0, 0, 0, 0, 0, 1, 1, 1, 9, 1, 1, 0, 0, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0,
0, 8, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
};
// Le masque du niveau (0 : pas collision, 1 : collision)
bool masque[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 1, 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,
};
TileMap map;
if (!map.load("tileset.png", sf::Vector2u(40, 40), level, 16, 8))
return -1;
// Horloge
sf::Clock time;
// On vérifie que la sprite joueur est bien chargée
if(!perso.loadFromFile("player.png"))
{
std::cout << "Erreur: player.png non charge" << std::endl;
}
perso.setSmooth(true); // pour lisser la texture
// On applique les textures au sprite joueur
sprite_perso.setTexture(perso);
// Tant que la fenêtre est ouverte
while(window.isOpen())
{
sf::Event event;
// Test des évènements
while(window.pollEvent(event))
{
// Si on clique sur fermer
if (event.type == sf::Event::Closed)
window.close();
// Gestion des FPS
if(event.type == sf::Event::KeyPressed)
{
updateFPS = true;
}
else
{
updateFPS = false;
}
}
if (updateFPS == true)
{
if (time.getElapsedTime().asMilliseconds() >= 50)
{
anim.x--;
if (anim.x * blockSize >= perso.getSize().x)
anim.x = 2;
time.restart();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Gestion texture
sprite_perso.setTextureRect(sf::IntRect(anim.x * blockSize, anim.y * blockSize, blockSize, blockSize));
vitesseX = 0;
vitesseY = 0;
gestionClavier();
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
position2.y = sprite_perso.getPosition().y + vitesseY;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
position2.x = sprite_perso.getPosition().x + vitesseX;
}
colisionTile = collision(masque, position2.x, position2.y, 40);
if(colisionTile == false)
{
sprite_perso.setPosition(position2);
std::cout<<" pas Collision !"<<std::endl;
}
else
{
std::cout<<"Collision !"<<std::endl;
}
/* vue */
view.reset(sf::FloatRect(0,0, screenW, screenH));
sf::Vector2f position(screenW / 2, screenH / 2);
position.x = sprite_perso.getPosition().x + (blockSize / 2) - (screenW / 2);
position.y = sprite_perso.getPosition().y + (blockSize / 2) - (screenH / 2);
if(position.x <0)
position.x = 0;
if(position.y <0)
position.y = 0;
view.reset(sf::FloatRect(position.x, position.y, screenW, screenH));
window.setView(view);
// On dessine
window.draw(map);
window.draw(sprite_perso);
window.display();
window.clear();
}
return 0;
}
/* Fonctions */
// Deplacement personnage
void gestionClavier()
{
if(sf::Event::KeyPressed)
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
anim.y = Up;
vitesseY = -speed;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
anim.y = Down;
vitesseY = speed;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
anim.y = Left;
vitesseX = -speed;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
anim.y = Right;
vitesseX = speed;
}
}
else
{
vitesseX=0;
vitesseY=0;
}
// collision avec les bords gauche et haut
if(sprite_perso.getPosition().x <= 0)
sprite_perso.setPosition(sf::Vector2f(0, sprite_perso.getPosition().y));
if(sprite_perso.getPosition().y <= 0)
sprite_perso.setPosition(sf::Vector2f(sprite_perso.getPosition().x,0));
}
// Fonction qui teste la collision entre le masque et le personnage
bool collision(bool masque[], int x, int y, int tailleCase)
{
if( masque[ int(x/tailleCase) + 16*int(y/tailleCase) ] == 1)
return true;
return false;
}
TileMap.cpp (celui de la doc)
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)
{
// on charge la texture du tileset
if (!m_tileset.loadFromFile(tileset))
return false;
// 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;
}
private:
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);
}
sf::VertexArray m_vertices;
sf::Texture m_tileset;
};
-
Tu peux très bien te passer d'un masque, c'est ce que je fais et ça marche très bien.
Tu peux faire comme ça par exemple :
//Imaginons que le personnage entre en collision avec les tiles 5 et 9:
bool collision(int level[], int x, int y, int tailleCase)
{
if( level[ int(x/tailleCase) + 16*int(y/tailleCase) ] == 5 || level[ int(x/tailleCase) + 16*int(y/tailleCase) ] == 9)
return true;
else
return false;
}
J'espère que ça t'aidera :)
-
J'ai donc essayé en faisant la collision directement avec le level mais il y a toujours le même problème, les zone de collision ne correspondent pas comme il faut. :(
-
Le problème peut venir de ta tilemap, essai en remplaçant ça :
if (!map.load("tileset.png", sf::Vector2u(40, 40), level, 16, 8))
return -1;
par ça :
if (!map.load("tileset.png", sf::Vector2u(40, 40), level, 8, 16))
return -1;
Je dis surement n'importe quoi mais sait on jamais ;D
-
Je confirme tu dis n'importe quoi ;D
Cela sert juste à définir la structure de la map (16 colonnes pour 8 lignes). En inversant les deux valeur la map est juste affichée verticalement... Ce code est censé être bon comme je l'ai repris du tuto officiel.
Si tu veux tester par toi-même et que tu as la SFML 2.1 d'installée tu peux reprendre le code de mon message précédent.
Merci malgré tout d'essayer de m'aider ;)
-
Apres quelques recherches, je crois pouvoir t'affirmer que...les zones de collision correspondent très bien au masque :p
Le problème vient d'autre part, il vient du fait que tu testes les collisions avec le point correspondant à l'origine de ton sprite_perso. Or ce point, c'est le coin haut-gauche du sprite. Vérifie toi même, ton code gère les collisions avec ce point la uniquement, ce qui fait que tu as l'impression que les zones de collisions sont au mauvais endroit.
Si tu veux résoudre ce problème, je te conseille de réécrire ton code de façon plus propre, plus claire, moins redondante (parce que certaines actions sont répétées plusieurs fois dans la même frame, comme ta vue qui est réinitialisée 2 ou 3 fois), ca sera plus lisible et plus compréhensible parce que la...ben c'est dégueulasse :p
Et évite les variables globales ;)