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

 C++ Discussion :

algorithme pour translation "smooth"


Sujet :

C++

  1. #1
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut algorithme pour translation "smooth"
    Bonjour à tous,

    Dans le cadre de mon petit projet graphique perso, j'ai besoin de simuler des déplacements en 3D tenant compte d'une certaine accélération. Seulement voilà, j'utilise SFML, et si je souhaite avoir des déplacements "smooth" réalisés via clavier (ou pas) je dois donc passer par des booléens. Rien de complexe dans tout ça, mais je pense que ma manière de faire est loin d'être la plus optimale.

    Par exemple, j'aurais tendance à pondre un code comme suivant :

    Code : 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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
     
    glm::mat4 transform(1.0f);   // tenseur identité pour les transformations
     
    glm::vec3 speed(.0f, .0f, .0f);  // vitesse sur x, y et z
    glm::vec3 accel(1.0f, 1.0f, -9.81f); // accélération sur x, y et z (je pense que tout le monde comprends que c'est en m.s-²)
    glm::vec3 decel(.5f, .3f, 2.2f);    // décélération 
     
    bool trans_x;           // on veut aller en x positif
    bool trans_x_inv;     // on veut aller vers x négatif
    bool trans_y;          // etc...
    bool trans_y_inv;
    bool trans_z;
    bool trans_z_inv;
     
    if(trans_x)
    {
        if(speed.x < 15.0f)
        {
            speed.x += accel.x;
        }
        if(speed.x > 15.0f)
        {
            speed.x = 15;
        }
    }
    else if (!trans_x && !trans_x_inv)
    {
        if(speed.x > .0f)
        {
            speed.x -= decel.x;
        }
        if(speed.x < .0f)
        {
            speed.x = .0f;
        }
    }
     
    // on imagine facilement la suite...
    // et enfin : 
     
    transform = glm::translate(transform, speed);
     
    // et on continue le code nécessaire
    Donc voilà l'idée en fait... Comme ça, on a quelque chose qui peut marcher, mais il est certainement envisageable de faire plus optimal (un code moins lourd à écrire). j'imagine bien une ou deux autres méthodes possibles, mais dans le doute, je préfère m'orienter vers vous, qui avez certainement plus d'expérience que moi en développement & algorithmique et/ou simplement une meilleure idée.

    Pour résumer, un algorithme qui, en fonction de simples booléens dans les 3 dimension d'un espace euclidien ( x2 pour les inverse aussi), tenant compte d'accélérations et décélérations différentes pour chacun des axes, me fourni en sortie un vecteur vitesse.

    Précision complémentaire : oui, si l'objet est déjà en mouvement, le simple fait de stopper tout mouvement (en gros passer tout les booléens à 0) induit une décélération (liée à l'inertie de l'objet).

    Merci d'avance pour vos retours ! Si le sujet n'est pas clair ou que vous avez besoin de plus d'infos, n'hésitez pas à me demander.

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Tu pourrais déjà utiliser quelques éléments qui pourraient te simplifier la vie, tels que:
    • une matrice 3*3 (dmat3x2 ) pour représenter l'accélération et la décélération, étant entedu que l'on peut accélérer sur un axe et décélérer sur un autre
    • un système de masque qui te permettrait de préciser la direction d'un déplacement (d'une accélération ) sous une forme proche de move{Xplus | Yminus | Znone}; et qui te permettrait de le tester sous une forme proche de if(move & Xplus == Xplus){/* ... */}
    • une énumération représentant les différents axes
    • une énumération pour représenter l'accélération et la décélération

    Cela ne se fera sans doute pas sans peine, ne serait-ce que parce que tu devras veiller à être cohérent pour ton masque : les deux valeurs de X (XDecel et XAccel) de Y (YDecel et YAccel) et de Z (ZDecel et ZAccel)) sont exhaustives entre elle (on ne peut pas avoir, dans un même temps XDecel et XAccel dans le même masque ) mais chaque valeur de X, de Y et de Z peut être combinée avec n'importe quelle valeur des deux autres axes

    De cette manière, tu pourras écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    /* mat :  matrice à mettre à jour
      type : accélération ou décélération
      axis  : axe à manipuler
      diff   : différence à appliquer
    void updateDiff(matrice & mat, updateType update, axisType axis, double diff){
        //appliquer la différence à l'élément update, axis de la matrice
     }
    (bien sur, la différence peut avoir une valeur arbitraire, ce qui te permettrait d'éviter à avoir la transmettre à chaque fois, si sa valeur devait être fixe )
    et, à partir de là, tu pourras avoir un code qui applique les différences sur les éléments de ta matrice de manière adéquate à partir du masque fourni, qui pourrait prendre une forme proche de
    Code : 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
    /* mat: matrice à mettre à jour
       mask : masque des transformations à appliquer
       diff : différence à appliqer à la matrice
    */
    vpod updateDiff(matrice & mat, UpdateMask mask, double difff){
        if(mask & XDecel == XDecel)
            updateDiff(mat, decelerate, Xaxis, diff);
        if(mask & XAccel == XAccel)
            updateDiff(mat, accelerate, Xaxis, diff);
        if(mask & YDecel == YDecel)
            updateDiff(mat, decelerate, Yaxis, diff);
        if(mask & YAccel == YAccel)
            updateDiff(mat, accelerate, Yaxis, diff);
        if(mask & ZDecel == ZDecel)
            updateDiff(mat, decelerate, Zaxis, diff);
        if(mask & ZAccel == ZAccel)
            updateDiff(mat, accelerate, Zaxis, diff);
    }
    Une fois que tu aurais cela, tu pourrais calculer la vitesse de l'élément sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /* speed : vitesse actuelle
       mat :matrice d'accélération / décélération
       mask : masque devant être utilisé
       diff : différence à appliquer
    vec3 computeSpeed(vec3 speed, matrix & mat,  UpdateMask mask, double difff){
        updateDiff(mat, mask, diff);
        auto x = speed[Xaxis]+mat(accelerate,Xaxis)-mat(decelerate,Xaxis); // voir comment accéder à un élément spécifique de la matrice
        auto x = speed[Yaxis]+mat(accelerate,Yaxis)-mat(decelerate,Yaxis); // dito
        auto x = speed[Zaxis]+mat(accelerate,Zaxis)-mat(decelerate,Zaxis); // dito
    }
    Et tu pourras utiliser la valeur renvoyée par cette fonction pour déterminer la nouvelle position de tes objets à partir de leur position "d'origine"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Bonjour, et merci pour ce retour !

    Effectivement, je n'avais pas vraiment penser à tout concaténer dans un tenseur... Je vais réfléchir à cette idée telle que tu la décris ; mais comme tu dis, il faut bien veiller à ce que le masque soit cohérent...
    mais cela me surprend ; il faut bien entendu réfléchir à cette solution, mais le problème me semble avoir une solution plus simple que ça pourtant.... Peut être que d'autres pourront confirmer ou non cette idée que je me fait du sujet ?

    En tout cas, merci pour cette première idée ; je vais voir si je peux la développer un peu ce soir.


    Petit sujet annexe, je vais tester ça plus tard dans la soirée aussi mais est-il possible de multiplier un booléen par une valeur quelconque (un int ou float) ? Je pense que oui mais je me demande... Si ce n'est pas le cas, la solution est assez simple mais bon. Je me demande ça car finalement, on pourrait traiter les situations via un vecteur contenant les booléens et le multiplier par le tenseur des accélérations.

    Code : 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
     
     
    // cas des accélérations : 
     
    glm::vec3 isAccelerating(0, 0, 0); // vecteur des booléens d'accélération
    glm::vec3 isDecelerating(0, 0, 0); // vecteur des booléens de décélération
     
    glm::vec3 speed(.0f, .0f, .0f);  // initialisation du vecteur vitesses
    glm::mat3 accel(.0f);  // initialisation du tenseur des valeurs d'accélération (tenseur diagonal)
    glm::mat3 decel(.0f);  // initialisation du tenseur des décélérations (tenseur diagonal)
     
    // je ne détaillerais pas ici, mais on défini les valeurs de chaque tenseurs et chaque vecteurs
    // [...]
    // et du coup, on fait le calcul suivant : 
     
    speed += isAccelerating * accel;
    speed += isDecelerating * decel;
    Comme tu dis, on ne peut pas accélérer et décélérer en même temps. Il me reste à réfléchir à la manière faire pour s'en assurer, mais je pense que, dans un premier temps, ce sujet peut être très simplement réglé par conception du code (on fait attention à ne pas demander d'accélération en même temps qu'une décélération simplement)...
    Autre point restant à valider aussi : le contrôle des valeurs aux limites. Cette méthode ne me permet pas, par le calcul, de stopper les accélérations et décélérations aux valeurs seuil... En fait il faudrait même piloter les accélération / décélérations aussi par le calcul, mais là ça ferait basculer mon très simple projet (qui a pour vocation de rester simple pour le moment) vers quelque chose de trop complexe en intégrant à minima une dimension temporelle... C'est un sujet très intéressant mais je pense que je développerais quelque chose de plus précis lorsque j'aurais plus d’aisance en programmation (et plus de temps !).

    En tout cas, merci pour ce retour. Si d'autres ont des idées à partager, n'hésitez pas !

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par BioKore Voir le message

    Petit sujet annexe, je vais tester ça plus tard dans la soirée aussi mais est-il possible de multiplier un booléen par une valeur quelconque (un int ou float) ?
    Je ne suis pas sur de comprendre ta question, et encore moins de comprendre le but recherché

    Le fait est que toute valeur numérique (qu'elle soit entière de type réel) peut être converti en valeur booléenne, selon une règle simple :
    1. 0 est converti en false
    2. tout ce qui n'est pas false est true

    Cependant, un booléen est la plus petite des informations que tu peux partager avec l'ordinateur, car il suffit que le courent passe (ou non) dans (la section d')un cable pour permettre de le représenter:
    • si le courent passe, on considère que le booléen vaut true
    • sinon, on considère que cela vaut false

    De plus, la multiplication n'existe pas en algèbre booléenne. on a :
    • la conjonction : le résultat de la conjonction de deux valeurs vaut true si les deux valeurs sont égales à true (ET)
    • la disjonction : le résultat de la disjonction entre deux valeurs booléen vaut true si l'une des deux valeurs (ou les deux) vaut true (OU)
    • la négation : le résultat d'une négation est vrai si la valeur d'origine était à faux, et inversement
    • la disjonction exhaustive : le résultat de la disjonction exclusive est vrai si une seule des valeur testées ést égale à vrai (et que l'autre est égale à faux) (ou exclusif)

    (NOTA: la disjonction exclusive n'est que la combinaison des trois première sous la forme de (A&!B) | (!A & B) )

    Donc, j'aurais tendance à dire que non, il est impossible de multiplier un booléen avec une valeur entière ou réelle
    Comme tu dis, on ne peut pas accélérer et décélérer en même temps. Il me reste à réfléchir à la manière faire pour s'en assurer, mais je pense que, dans un premier temps, ce sujet peut être très simplement réglé par conception du code (on fait attention à ne pas demander d'accélération en même temps qu'une décélération simplement)...
    Le problème est toujours le même : la loi de l'emmerdement maximum (aussi connue sous le nom de "loi de finagle") plane toujours sur ta tête comme l'épée de Damoclès sur un coupable : si tu laisse à qui que ce soit (*) l'occasion de faire une connerie, il ne sert à rien de perdre du temps à te demander SI il fera la connerie, car tu peux partir du principe qu'il la fera forcément à un moment ou à un autre.

    Tu peux directement passer à la question suivante : QUAND fera-t-il la connerie

    Pour ton propre malheur, la réponse sera toujours la même : au pire moment qui soit

    (*) et ne vas pas croire que, parce que c'est toi qui prend la décision, tu ne feras jamais l'erreur!!! Trop de choses peuvent se passer et faire que, pour une connerie (peut-être deux fonctions appelées dans un mauvais ordre) est trop vite arrivée)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Héhé, entièrement d'accord avec toi sur la seconde partie de ton retour ; dans la mesure du possible, même s'il s'agit en premier lieu de "tests", cela n’empêche rien à l'importance de faire quelque chose de propre. Je vais réfléchir au moyen de rendre impossible des accélérations et décélérations en même temps.

    Par contre, en ce qui concerne ma question sur la "multiplication" d'un booléen, c'est en fait pour savoir si le booléen est considéré comme 0 ou 1 par le compilateur (en valeur numérique), ou pas.. Tout simplement.
    Dans l'absolu, entièrement d'accord avec toi, cela n'a aucun sens de "multiplier" un booléen par un réel ou un entier... Si le compilateur ne souhaite pas comprendre ce que je veux faire, je peux passer directement par des entiers ; en plus, dans le cas présent, je pense que ce serait même plus simple.
    Le but recherché est tout simplement de multiplier une valeur par 0 si le booléen est faux, et le multiplier par 1 s'il est vrai...
    C'est ce que j'ai illustré dans mon précédent post avec le bout de code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    speed += isAccelerating * accel;   // isAccelerating vaut 0 ou 1

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    En théorie si tu static_cast un bool tu devrais avoir 0 ou 1.
    Sinon, je ne comprends pas comment tu veux un déplacement smooth avec des booléens ? Pour qu'un déplacement soit smooth, il doit être surtout fait en fonction du framerate.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Bonjour,

    En fait, si je souhaite utiliser ces booléens, c'est parce que j'utilise SFML, et les évènement clavier, eux, se répètent avec une répétition propre à l'OS (je crois), ou en tout cas, pas du tout à une vitesse compatible avec mon affichage (ça fait un peu comme si, en écrivant sur le forum, tu reste appuyé sur la touche "e"). Pour palier à ça, je souhaite donc coller un booléen à "vrai" lorsque la touche est appuyée, et on réalise une certaine fonction tant que le booléen est "vrai", et on réalise une autre fonction tant que ce booléen est "faux" (passage à "faux" lorsque la touche est relachée par exemple).

    en SFML c'est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if(this->m_event.type == sf::Event::KeyPressed)
    {
        // [...] passage du booléen à true
    }
    else if(this->m_event.type == sf::Event::KeyReleased)
    {
        // [...] passage du booléen à false
    J'ai déjà réalisé l’exercice pour un seul sens de déplacement en utilisant un code similaire à celui présenté dans le premier post de ce fil, et j'obtiens le comportement souhaité. Cependant, je pense qu'il existe des moyens plus simples / rapides / efficaces que d'utiliser des conditions de partout.

    Pour info, je réalise l'affichage et la gestion des évènement dans deux threads différents.

    Si vous connaissez une méthode fonctionnelle sans passer par des booléens, ça m'intéresse aussi ; je ne suis pas figé sur l'utilisation de ce système...

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    void sf::Window::setKeyRepeatEnabled(bool enabled);
    Et sinon au lieu de faire x booléen pour chaque bouton, il suffirait d'une simple map.
    Il est inutile d'avoir une valeur d'accélération et une de décélération, une décélération c'est juste une accélération négative. Et en encapsulant ça dans une classe ce serait encore plus propre.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Oui, mais le "enableKeyRepeat" active ou désactive simplement la répétition des touches, il ne permet pas une activation continue et fluide de cette touche. Je dois donc trouver une autre solution pour obtenir quelque chose de fluide.

    Sinon, je suis d'accord avec toi sur le fait qu'une décélération est une accélération négative... Je n'ai pas de soucis avec ça. Par contre, je peux avoir des accélérations différentes des décélérations (par exemple, soit +15, soit -2, et les valeurs peuvent évoluer). Ces valeurs sont fixes et propres à l'objet, pas au gestionnaire d’événement. Je dois donc juste dire "avance" ou "recule", sans rien préciser d'autre. Il me faut donc bien stocker ces valeurs quelque part à un moment ou un autre.

    Quoi qu'il en soit, je dirais que la question n'est pas vraiment de savoir comment gérer mes accélérations ou autre, mais comment faire pour éviter de blinder mon code de conditions pour faire ça correctement.

    Quand j'appuie sur "avancer", il faut que l'objet accélère jusqu'à atteindre une valeur X. Si je relâche la touche "avancer", l'objet doit décélérer jusqu'à atteindre la valeur 0.

    En réalité, finalement, on s'en fiche même de l'accélération, le problème serait le même sans : la répétition des touches saccade le mouvement ; je dois donc trouver un moyen de faire plus fluide, ça ok, je sais faire, mais de le faire sans passer 3h à coder des if et me triturer le cerveau à savoir quoi désactiver quand j'active autre chose.

    Après, les solutions alternatives sont peut être moins bonnes ou plus complexes à mettre en œuvre, mais je pense qu'au moins une doit sortir du lot...

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par BioKore Voir le message
    la répétition des touches saccade le mouvement
    Par quelle magie ? Suffit d'avoir un gestionnaire d'évènements correct, qui sache faire la différence entre une nouvelle touche et son repeat.
    Ou de désactiver la répétition, mais tu sembles pas vouloir cette solution.
    Ou de se plugger correctement sur le OnPress et non sur le OnRepeat, mais ça revient à avoir un gestionnaire d'évènements correct.

    Citation Envoyé par BioKore Voir le message
    Oui, mais le "enableKeyRepeat" active ou désactive simplement la répétition des touches, il ne permet pas une activation continue et fluide de cette touche. Je dois donc trouver une autre solution pour obtenir quelque chose de fluide.
    Qu'est-ce que tu veux dire par fluide encore ?
    Soit tu veux savoir quand un évènement se produit et tu utilises les évènements. Et tu ne peux toujours le savoir qu'à chaque frame de toutes façons, ou quand tu process les évènements - ce qui est inutile entre chaque frame.
    Et désactiver la répétition des touches peut être une solution dans une implémentation donnée.
    Soit tu veux savoir quand une touche est utilisée, et tu ne peux toujours le savoir qu'à chaque frame.
    static bool sf::Keyboard::isKeyPressed(Key key);

    Et oui comment gérer tes accélérations ou autre fait partie du problème, à moins que tu sois content d'avoir 6 variables pour gérer 1 dimension d'accélération ? auquel cas "be my guest" comme qui dirait, on peut pas t'empêcher de faire du code de qualité moindre.
    Ça n'a rien à voir avec le fait d'utiliser des constantes différentes ou non pour initialiser ou modifier ces valeurs.
    Et vu qu'on est sur le forum C++, une classe gère ça très bien et encapsulerait ces traitements.
    Une telle classe aurait une interface trivialle telle que accelerate(), decelerate(), update(), getAcceleration().
    Les valeurs de min, max etc seraient bien sûr dans le constructeur et non des chiffres magiques au milieu du code.

    Et ton problème se limitera à appeler start/stop correctement et ne sera pas polué par 300 variables.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #11
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Bonjour,

    En fait, la répétition des touches est déjà désactivée. Là n'est pas le problème. Ma question initiale, justement, c'est la manière de traiter les booléens (ou autre !) "Avance" et "recule" (un pour chaque, pour l'exemple), sans passer par 15 conditions if / else.

    Aujourd'hui, j'obtiens le résultat souhaité avec le code suivant :

    Code : 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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
     
     
    bool m_mfw;		// is moving forward
    bool m_mbw;		// is moving backward
    bool m_sfw;		// is stopping moving forward
    bool m_sbw;		// is stopping moving backward
     
    void agent::moveForward()
    {
    	this->m_mbw = false;
    	this->m_sfw = false;
    	this->m_mfw = true;
     
    	if(this->m_spd.x > 1.5f) this->m_spd.x = 1.5f;
    	else this->m_spd.x += this->m_accel.x;
     
    }
     
    void agent::stopForward()
    {
    	this->m_mfw = false;
    	this->m_sfw = true;
     
    	this->m_spd.x -= this->m_accel.x;
    	if(this->m_spd.x <= .0f)
    	{
    		this->m_spd.x = .0f;
    		this->m_sfw = false;
    	}
     
    }
     
     
    void agent::update()
    {
    	if(this->m_mfw) this->moveForward();
    	if(this->m_mbw) this->moveBackward();
    	if(this->m_sfw) this->stopForward();
    	if(this->m_sbw) this->stopBackward();
     
     
    	this->m_tensor = glm::rotate(this->m_tensor, glm::radians(this->m_anglSpd), glm::vec3(.0f, .0f, 1.0f));
    	this->m_tensor = glm::translate(this->m_tensor, this->m_spd);
    	this->m_pos = this->m_tensor * glm::vec4(.0f, .0f, .0f, 1.0f);
    	this->m_model.update(this->m_tensor);
    }

    et le code du "manager d’événements" :

    Code : 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
     
     
    this->m_window.setKeyRepeatEnabled(false);
     
    [...]
     
    if(this->m_event.type == sf::Event::KeyPressed)
    {
    	switch(this->m_event.key.code)
    	{
    	case sf::Keyboard::Escape:
    		run = false;
    		this->m_window.close();
    		break;
    	case sf::Keyboard::Up:
    		this->m_agent.moveForward();
    		break;
     
             [...]

    mais les fonctions "moveForward" / "stopForward" / "update" me semblent pouvoir être réalisées d'un manière plus simple et optimale... Après, ce n'est peut être pas le cas...



    Merci encore !!

  12. #12
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par BioKore Voir le message
    mais les fonctions "moveForward" / "stopForward" / "update" me semblent pouvoir être réalisées d'un manière plus simple et optimale... Après, ce n'est peut être pas le cas...
    Et un comme cela

    Code : 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
    bool m_mfw;		// is moving forward
    bool m_mbw;		// is moving backward
    bool m_sfw;		// is stopping moving forward
    bool m_sbw;		// is stopping moving backward
     
    void agent::moveForward()
    {
    	this->m_mbw = false;
    	this->m_sfw = false;
    	this->m_mfw = true;
     
    	this->m_spd.x = ((this->m_spd.x <= 1.5f)? (this->m_spd.x + this->m_accel.x): 1.5f); // clamp
    }
     
    void agent::stopForward()
    {
    	this->m_mfw = false;
     
    	this->m_spd.x = ((this->m_spd.x > this->m_accel.x)? (this->m_spd.x - this->m_accel.x): 0.0f);
    	this->m_sfw   = (this->m_spd.x != 0.0f); // TODO : test double be careful
    }

+ Répondre à la discussion
Cette discussion est résolue.

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