IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Intelligence artificielle Discussion :

Algo A* problème de perfs


Sujet :

Intelligence artificielle

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut Algo A* problème de perfs
    Bonjour,

    Pour un jeu en 2D que je suis en train de développer, j'ai implémenté l'algorithme A* pour le déplacement des ennemis.
    L'algo à l'air de pas trop mal marcher, sauf que le calcul du chemin est très lent : Pour déplacer un personnage de 200 pixels, le calcul dure environ 15 secondes.
    Je me suis inspiré de ce tuto : http://khayyam.developpez.com/articles/algo/astar/

    Ce qui ralenti mon calcul c'est le test de collision (fonction ajouter_cases_adjacentes du tuto) à la ligne :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (*((Uint8 *)s->pixels + j * s->pitch + i * s->format->BytesPerPixel) == NOIR)
                    /* obstace, terrain non franchissable, on oublie */
                    continue;

    Sauf que j'utilise un quadtree pour optimiser les tests de collisions justement, mais bon ma fonction de test de collision marche bien je l'ai testé.
    Le problème vient du fait que mes ennemis se déplacent au pixel près, pas par case (tiles), du coup cette fonction est appelée plusieurs fois par pixel analysés.

    Ma classe QuadTreeNode :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class QuadTreeNode
    {
    public:
         [...]
     
        sf::IntRect getBounds() const;
     
        bool isCollision (Collisionnable *c, sf::Vector2i p); // Renvoie true si le point passé en paramètre est en collision avec un autre objet que celui passé en paramètre
     
    private:
        QuadTreeNode *m_ParentNode;
        sf::IntRect m_Bounds;
        QuadTreeNode *m_ChildNodes[4];                  // Dans l'ordre : NE SE SW NW
        std::vector<Collisionnable*> m_Objets;
     
    };

    L'implémentation de ma méthode isCollision du quadtree :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    bool QuadTreeNode::isCollision(Collisionnable *c, sf::Vector2i p)
    {
        for (unsigned int i = 0; i < m_Objets.size(); i++)
        {
            if (m_Objets[i] != c)
            {
                sf::IntRect b = m_Objets[i]->getBounds ();
     
                if (b.contains(p)) return true; // si je commente cette ligne le calcul est quasiment instantané
            }
        }
     
        for (unsigned int i = 0; i < 4; i++)
        {
            if (m_ChildNodes[i] != 0)
            {
                sf::IntRect b = m_ChildNodes[i]->getBounds ();
                if (b.contains(p))
                {
                    if (m_ChildNodes[i]->isCollision(c, p)) return true; // si je commente cette ligne le calcul est quasiment instantané également
                }
            }
        }
     
        return false;
    }

    Et voici comment j'appelle cette fonction dans ajouter_cases_adjacentes() :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
                if (m_Map->getQuadTree()->isCollision(this, sf::Vector2i (i,j)))
                {
                    // obstacle, terrain non franchissable, on oublie
                    continue;
                }

    Pour déplacer un personnage de la coordonnée 865,466 à la coordonnée 600,449 (il y a des obstacles entre le point de départ et le point d'arrivée) cette fonction est appelée 2096504 fois par la fonction ajouter_cases_adjacentes().

    Merci d'avance pour votre aide...

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut
    Après différents tests, j'arrive à la conclusion que ce qui ralentis l'algo c'est lorsqu'il détecte une collision, ca l'oblige à rallonger le chemin...

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Je pense que votre fonction de collision est appelée bien trop souvent pour le déplacement que vous avez décrit.

    Votre fonction isCollision est fausse dans la classe QuadTreeNode.
    Le principe du quadtree est qu'il est récursif. Le test fait est le suivant :

    - Si l'objet pour lequel on teste la collision n'est pas dans ce rectangle (le rectangle du quad), alors on retourne (false pour indiquer qu'li y n'y a pas la collision là)
    - Si ne suis pas dans un noeud final, alors je parcours les 4 sous noeuds (récursion)
    - Si je suis dans un noeud final, alors je test les N objets présent dans ce noeud, pour savoir si je suis bien en collision avec l'un d'eux. On retourne le résultat à la fonction parente (qui fera remonter le résultat).

    Il me semble que vous n'avez pas du tout fait cela et du coup, vous n'utilisez pas efficacement votre quad tree
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut
    Salut Littlewhite (tu peux me tutoyer hein )

    Merci de m'avoir répondu

    Ma fonction isCollision marche très bien :

    Dans mon node racine je test d'abord la collision avec chaque objet contenu par celui ci, s'il y a collision avec l'un d'entre eux je retourne true (collision).
    Sinon, j'appelle la fonction isCollision de mes quatres noeuds enfants (récursion), qui font de même. Si l'un d'entre eux me retourne true, alors le noeud parent retourne true.
    S'il aucune collision n'a étée détectée par mes noeuds enfant alors je retourne false (pas de collision)

    En fait j'ai bien analysé le problème... Il faut que je revoit la façon dont mes personnages se déplacent. j'ai modifié mon algo A* pour que les personnages se déplacent tile par tile et là c'est quasiment instantané...

  5. #5
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Citation Envoyé par bombseb Voir le message
    Ma fonction isCollision marche très bien :
    Oui, elle fonctionne, mais pas de façon optimale, d'après moi.

    Citation Envoyé par bombseb Voir le message
    Dans mon node racine je test d'abord la collision avec chaque objet contenu par celui ci, s'il y a collision avec l'un d'entre eux je retourne true (collision).
    Sinon, j'appelle la fonction isCollision de mes quatres noeuds enfants (récursion), qui font de même. Si l'un d'entre eux me retourne true, alors le noeud parent retourne true.
    S'il aucune collision n'a étée détectée par mes noeuds enfant alors je retourne false (pas de collision)
    En théorie, vous n'avez pas besoin de tester les objets du noeud courant, car ces mêmes objets seront dans un noeuds enfant. Mais cela dépend énormément de comment vous construisez/gérer le quad tree.
    De plus, en théorie, vous n'avez aucune obligation d'appeler à chaque fois, les quatres noeuds enfant (seul un, devrait être appelé).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  6. #6
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut
    En théorie, vous n'avez pas besoin de tester les objets du nœud courant, car ces mêmes objets seront dans un nœud enfant. Mais cela dépend énormément de comment vous construisez/gérer le quad tree.
    En fait, mes objets se trouvent toujours dans les derniers enfants (au niveau hiérarchique le plus bas), donc dans un parent il ne devrais même pas rentrer dans la 1ere boucle (puisque m_Objet.size() == 0). Mais sur le fond je suis bien d'accord.

    De plus, en théorie, vous n'avez aucune obligation d'appeler à chaque fois, les quatre nœuds enfant (seul un, devrait être appelé).
    Oui je teste d'abord les limites du nœud enfant et j'appelle sa fonction isCollision seulement si l'objet envoyé en paramètre est contenu dans ses limites :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    sf::IntRect b = m_ChildNodes[i]->getBounds ();
    if (b.contains(p))
    {
         if (m_ChildNodes[i]->isCollision(c, p)) return true; // si je commente cette ligne le calcul est quasiment instantané également
    }

  7. #7
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Combien faites vous de subdivision ?
    Combien de pixels sont contenu dans les derniers quad et quel est la taille de l'objet testé ?
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  8. #8
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut
    Ma map fait 3200 pixels par 3200 pixels (100 tiles par 100 tiles)
    Le node racine fait donc la même dimension, les derniers nodes enfants font 100 pixels par 100pixels mais j'ai mis une valeur arbitraire pour l'instant.
    L'objet testé, et bien ca dépend, j'ai des objets de toutes les tailles. Mes personnages font 38*36 et par exemple j'ai un mur qui fait 256 pixels par 32.
    Mais bon la map et les sprties sont temporaires, je me concentre d'abord sur le moteur du jeu, je chercherais un graphiste plus tard

  9. #9
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Essayez de descendre jusqu'à des noeuds de 32x32, ou peut être 64x64.
    Après, à part un bogue de remplissage du quadtree, je vois pas cette fois :s
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  10. #10
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut
    Oui j'essaierais...

    Non mais sinon mon problème de lenteur est simple en fait. J'utilise l'algo A* pour déplacer mes personnage au pixel, c'est ca qui demande trop de calcul.
    Et ca demande encore plus de calcul lorsqu'il y a collision car l'algo est obligé de toruver un autre chemin.
    Finalement je l'ai modifié pour que mes personnages se déplacent tile par tile, et le calcul est maintenant instantané...

Discussions similaires

  1. Problème de perf sous Tomcat 5.5
    Par gamodio dans le forum Tomcat et TomEE
    Réponses: 14
    Dernier message: 18/07/2006, 11h48
  2. [VBA-E] Problème de perf'
    Par MatMeuh dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 05/07/2006, 16h22
  3. Réponses: 11
    Dernier message: 19/06/2006, 16h54
  4. problèmes de perfs IE6/Firefox
    Par fredoche dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 26/08/2005, 17h44
  5. Problème de perfs Sous requetes IN
    Par ias83 dans le forum SQL
    Réponses: 4
    Dernier message: 15/06/2005, 12h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo