-
Salut à tous!
Je n'arrive pas à bien gérer les collisions dans mon programme. J'ai un personnage que je déplace avec la souris, et j'ai un autre carré qui a une position fixe.
J'ai réussi à gérer les collision pour les côté droit et gauche du personnage, mais quand j'essaie de gérer celles du haut et du bas, mon programme prend quand même les collisions de gauche et de droite en compte.. C'est dur à expliquer pour un débutant comme moi alors j'ai fait une petite vidéo très simple :
http://videobam.com/JnqjK (http://videobam.com/JnqjK)
Et voici mon code source :
void Player::update(sf::Vector2i mousePosition, Level *level) {
// Ma class Player hérite de sf::RectangleShape
sf::Vector2f position = getPosition();
m_delta.x = mousePosition.x - position.x;
m_delta.y = mousePosition.y - position.y;
// On déplace le personnage vers la souris
move(m_delta.x * m_playerSpeed, m_delta.y * m_playerSpeed);
// Rectangle du personnage
sf::FloatRect playerRect = getGlobalBounds();
// Rectangle temporaire avant d'avoir toutes les cases du niveau à gérer (pour tester avec une seule case)
sf::FloatRect levelTemp;
levelTemp.top = 10 * CELL_SIZE;
levelTemp.left = 10 * CELL_SIZE;
levelTemp.width = levelTemp.height = CELL_SIZE;
// Rectangle d'intersection
sf::FloatRect intersection;
if (playerRect.intersects(levelTemp, intersection)) {
if (playerRect.left < levelTemp.left + CELL_SIZE &&
playerRect.left + CELL_SIZE > levelTemp.left + CELL_SIZE) {
move(intersection.width, 0);
}
else if (playerRect.left + CELL_SIZE > levelTemp.left &&
playerRect.left < levelTemp.left) {
move(-intersection.width, 0);
}
else if (playerRect.top < levelTemp.top + CELL_SIZE &&
playerRect.top + CELL_SIZE > levelTemp.top + CELL_SIZE) {
move(0, intersection.height);
}
}
}
J'espère que vous pouvez m'aider. Ça fait des heures que je tente de trouver une solution.. :S
Merci d'avance! à+
-
Bonjour !
Bon j'ai regardé un peu, et en regardant ton code je pense que dans ta condition ici :
if (playerRect.intersects(levelTemp, intersection)) {
if (playerRect.left < levelTemp.left + CELL_SIZE &&
playerRect.left + CELL_SIZE > levelTemp.left + CELL_SIZE) {
move(intersection.width, 0);
}
else if (playerRect.left + CELL_SIZE > levelTemp.left &&
playerRect.left < levelTemp.left) {
move(-intersection.width, 0);
}
else if (playerRect.top < levelTemp.top + CELL_SIZE &&
playerRect.top + CELL_SIZE > levelTemp.top + CELL_SIZE) {
move(0, intersection.height);
}
}
Tu vérifies en premiers lieu si tout est correct sur l'axe X, cependant quand tu arrives en collision sur l'axe Y, tu seras aussi sur l'axe X décrite dans ta condition dans ton code, et comme elle sera lu en première alors ton code considérera que tu es en collision uniquement sur cet axe, bon je suis pas sur à 100% puisque je ne peux pas tester ton code mais pour moi je pense que dans tes conditions tu devrais : tester pour l'axe X ET pour l'axe Y en même temps, du genre à avoir des conditions bien spécifique.
Bon encore une fois je ne suis pas certains mais je cherchais dans ce coin là, en espérant aussi avoir étais assez clair ^^"
Bonne journée
-
Si je comprends bien ton code, quand il y a collision, tu testes les positions relatives des deux carrés. Si Player est trop a droite, tu le déplaces vers la gauche, et réciproquement.
Mais quand il y a collision par le haut et le bas, les coordonnées en abscisse de ton Player vérifient quand même les tests de collision des côtés (le if et le premier else if).
En gros, quand il y a collision, ton code vérifie d'abord si l’abscisse d'un des cotés de Player n'est pas comprise entre les abscisses des cotés de l'obstacle. Et comme c'est presque toujours le cas puisque Player est plus petit que l'obstacle, eh bien ton code ne prend jamais en compte la collision par le haut, mais toujours celle par le côté. D'ou le fait que l'ordi décale Player sur le côté à chaque fois.
C'est peut être pas très clair, si tu comprends pas ce que je veux dire, dis le et j'essaierai de reformuler ^^'
edit : d'ailleurs, c'est ce que vient de dire plus clairement Erwsaym ^^'
-
Bof au moins comme ça il y a deux explications :P
Mais ça me rassure que je ne suis pas le seul a penser ça !
-
Voici la fonction que j'utilise pour gérer ce cas :
sf::Vector2f CollisionManager::handleCollision(sf::FloatRect box)
{
sf::Vector2f movement;
if(isCollide(box)) // J'utilise un conteneur de toutes les entités créant des collisions et je teste si "box" entre en collision
{
sf::FloatRect rect = getRectCollide(box); // Ici je récupère la première entité qui entre en collision avec ma "box"
sf::Vector2f diff = sf::Vector2f(rect.left - box.left, rect.top - box.top);
sf::Vector2i dir;
if(diff.x > 0 && diff.x < box.width)
dir.x++;
if(diff.x < 0 && diff.x > -rect.width)
dir.x += 2;
if(diff.y > 0 && diff.y < box.height)
dir.y++;
if(diff.y < 0 && diff.y > -rect.height)
dir.y += 2;
// HANDLE SIMPLE COLLISION
if(dir == sf::Vector2i(1,0))
movement.x--;
else if(dir == sf::Vector2i(2,0))
movement.x++;
else if(dir == sf::Vector2i(0,1))
movement.y--;
else if(dir == sf::Vector2i(0,2))
movement.y++;
// HANDLE DOUBLE COLLISION
else if(dir == sf::Vector2i(1,1))
{
if(-abs(diff.x)+box.width < -abs(diff.y)+box.height)
movement.x--;
else
movement.y--;
}
else if(dir == sf::Vector2i(2,2))
{
if(rect.width - abs(diff.x) < rect.height - abs(diff.y))
movement.x++;
else
movement.y++;
}
else if(dir == sf::Vector2i(1,2))
{
if(-abs(diff.x)+box.width < rect.height - abs(diff.y))
movement.x--;
else
movement.y++;
}
else if(dir == sf::Vector2i(2,1))
{
if(rect.width - abs(diff.x) < -abs(diff.y)+box.height)
movement.x++;
else
movement.y--;
}
}
return movement;
}
Voilà j'espère que cela aidera :)
Si tu as besoin je peux publier mon CollisionManager en entier :)