Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Collision avec intersects  (Lu 3783 fois)

0 Membres et 1 Invité sur ce sujet

pascalb

  • Newbie
  • *
  • Messages: 7
    • Voir le profil
Collision avec intersects
« le: Juin 20, 2014, 08:52:30 pm »
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

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! à+

Erwsaym

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
    • ErnSoft.com
    • E-mail
Re : Collision avec intersects
« Réponse #1 le: Juin 21, 2014, 12:24:27 pm »
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
- ♪ -

PtichapronRouge

  • Newbie
  • *
  • Messages: 41
    • Voir le profil
    • E-mail
Re : Collision avec intersects
« Réponse #2 le: Juin 21, 2014, 12:27:41 pm »
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 ^^'
Un coca, un ordinateur, et un livre SFML Game Development. Elle est pas belle la vie ?

Erwsaym

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
    • ErnSoft.com
    • E-mail
Re : Collision avec intersects
« Réponse #3 le: Juin 21, 2014, 02:30:06 pm »
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 !
- ♪ -

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Collision avec intersects
« Réponse #4 le: Juin 30, 2014, 10:43:25 pm »
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 :)