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

AWT/Swing Java Discussion :

Problème de temps de latence avec KeyAdapter


Sujet :

AWT/Swing Java

  1. #1
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut Problème de temps de latence avec KeyAdapter
    Bonjour,

    j'essaye de faire déplacer un personnage sur une map de jeu, le soucis vient de la gesion du clavier.

    Lorsque j'appuie sur une de mes touches (haut, bas, gauche, droite), mon petit bonhomme se déplace bien selon le comportement que je lui ai attribué mais le déplacement sacade sur la deuxième image.

    Par exemple, si j'appuie sur "Bas", le personnage fait un pas vers le bas, puis il y a une demi-seconde d'arrêt, et ensuite tout se passe bien. De même pour chaque touche.

    Ce sont ces petits temps de latences après chaque appuie sur une touche que je n'explique pas... Mais surtout c'est très désagréable, ça empêche les déplacements d'être fluides.

    Quelqu'un a-t-il déjà eu ce type de problème ?
    Voila un extrait de mon code :

    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
    public void keyPressed(KeyEvent e)
    {
                switch(e.getKeyCode())
                {
                    case KeyEvent.VK_DOWN:
                        // Mon code pour la touche du bas
                        break;
     
                    case KeyEvent.VK_UP:
                        // Mon code pour la touche du haut
                        break;
     
                    // Code pour les autres touches
                }
                source.getGame().repaint();
    }

    Merci beaucoup !

  2. #2
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Ca doit être le temps d'exécuter "// Mon code pour la touche du bas", non?

  3. #3
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    Possible, je ne sais pas.
    Le code que j'execute est juste le démarrage d'une animation.

    Et surtout ce qui est bizarre, c'est que ça ne se produit qu'une seule fois par appuie de touche.

    C'est à dire si je maintiens la touche enfoncée, tout va bien se passer, le petit bonhomme va bien se déplacer et s'animer correctement, mais sur la première demi-seconde, il y aura un retard...

  4. #4
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Montre ton code exécuté

  5. #5
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    case KeyEvent.VK_DOWN:
                        source.getGame().getCharacter().walkDown(source.getGame().getMap());
                        source.getGame().getCharacter().enableDown(true);
                        break;

    Cette méthode dans une autre classe permet de tester les collisions, et de faire avancer notre bonhomme.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	public void walkDown(Map map)
    	{
    		// Test de collision avec le décors
    	    if (map.getGrille().canWalk(x, y+this.step))
    	    {
    	        y+=this.step;
    	    }
    	}
    La méthode enableDown permet d'executer ceci :

    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
     
    	public void run()
    	{
    	    try
    	    {
    	        while (true)
    	        {
    	            if (down)
    	            {
    	                this.animDown();
    	            }
    	            if (left)
    	            {
    	                this.animLeft();
    	            }
    	            if (up)
    	            {
    	                this.animUp();
    	            }
    	            if (right)
    	            {
    	                this.animRight();
    	            }
    	            sleep(100);
    	        }
    	    }
    	    catch(InterruptedException e)
    	    {
     
    	    }
    	}
    Ma classe Character est un Thread, ça permet de jouer les animations.

    Quand keyRelease s'execute, je fais un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    source.getGame().getCharacter().enableDown(false);
    pour stoper l'animation.

  6. #6
    Membre expérimenté Avatar de herve91
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 282
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 282
    Points : 1 608
    Points
    1 608
    Par défaut
    Citation Envoyé par marissa_mean
    Et surtout ce qui est bizarre, c'est que ça ne se produit qu'une seule fois par appuie de touche.

    C'est à dire si je maintiens la touche enfoncée, tout va bien se passer, le petit bonhomme va bien se déplacer et s'animer correctement, mais sur la première demi-seconde, il y aura un retard...
    Bonjour,
    ne serait-ce pas lié à l'"auto-repeat" ? Quand tu appuies sur une touche et que tu la maintiens enfoncée, il y a un délai initial ~ 1/2 s avant la prise en compte de la répétition. Sans ce délai, au lieu d'écrire 'a' par exemple, tu écrirais 'aa...' sans le vouloir.

  7. #7
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    Je n'y avais pas pensé !
    Oui ça m'a bien l'air d'être ce délai d'auto-repeat.

    Maintenant il ne reste plus qu'a trouver comment enlever ça.

    Merci beaucoup !

  8. #8
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Il faut écouter les évènements "key pressed" et "key released" (enfoncée, relâchée)...

  9. #9
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    Après avoir cherché un peu sur Internet, il semble que les évènements keyPressed et keyReleased sont envoyés par Windows, donc il n'y aura rien à faire pour éviter le délai de répétition de cette manière.

    Certains parlent de démarrer un Timer dans le KeyPressed et de l'arrêter dans le keyRelease mais je ne vois pas ce que ça va changer.

    Je pense que je vais tout simplement tenter une autre approche pour le déplacement de mon personnage.


    Si j'ai du résultat convenable je vous tiendrau au courant.

  10. #10
    Expert éminent

    Profil pro
    Fabricant et casseur d'avions
    Inscrit en
    Avril 2004
    Messages
    3 814
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : Fabricant et casseur d'avions
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2004
    Messages : 3 814
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par marissa_mean
    Après avoir cherché un peu sur Internet, il semble que les évènements keyPressed et keyReleased sont envoyés par Windows, donc il n'y aura rien à faire pour éviter le délai de répétition de cette manière.
    Tu n'auras (normalement) pas de délai de répétition en passant par keyPressed et keyReleased... ça détectera juste le moment où tu appuieras sur une touche, et le moment où tu relâcheras la touche. Il peut très bien y avoir 3 heures entre les deux, à toi de gérer... du genre, tant que tu n'as pas intercepté le keyReleased, ton personnages bouge...
    "Errare humanum est, sed perseverare diabolicum"

    Ma page sur DVP.com

  11. #11
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    J'utilise depuis le début keyPressed et keyReleased (cf mon premier post) que j'ai redéfinit de KeyAdapter.

    Il y a un délai de répétition d'une demi seconde. C'est bien ça le problème.

  12. #12
    Expert éminent

    Profil pro
    Fabricant et casseur d'avions
    Inscrit en
    Avril 2004
    Messages
    3 814
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : Fabricant et casseur d'avions
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2004
    Messages : 3 814
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par marissa_mean
    J'utilise depuis le début keyPressed et keyReleased (cf mon premier post) que j'ai redéfinit de KeyAdapter.

    Il y a un délai de répétition d'une demi seconde. C'est bien ça le problème.
    Je ne comprends pas trop quelle répétition il pourrait bien y avoir en utilisant ça (mais j'ai déjà eu des soucis avec, mais c'était avec les touches de fonctions...)

    D'après ce que je vois de ton code, tu appuies sur la touche, ça lance l'animation, qui s'arrête quand on relâche la touche.

    L'auto-repeat ne doit pas intervenir dans l'histoire... à moins que tu n'aies un "enableDown(false)" intempestif quelque part... il n'y en aurait pas un qui traine dans ta méthode animDown()?
    "Errare humanum est, sed perseverare diabolicum"

    Ma page sur DVP.com

  13. #13
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    ne serait-ce pas lié à l'"auto-repeat" ? Quand tu appuies sur une touche et que tu la maintiens enfoncée, il y a un délai initial ~ 1/2 s avant la prise en compte de la répétition. Sans ce délai, au lieu d'écrire 'a' par exemple, tu écrirais 'aa...' sans le vouloir.
    j'ai trouvé un exemple qui reproduit mon problème.

    http://math.hws.edu/eck/cs124/javanotes3/c6/s5.html


    Lorsqu'on essaye de bouger le cube vers la gauche ou la droite, il y a une petite pause avant qu'il se mette à bouger.

  14. #14
    Expert éminent

    Profil pro
    Fabricant et casseur d'avions
    Inscrit en
    Avril 2004
    Messages
    3 814
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : Fabricant et casseur d'avions
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2004
    Messages : 3 814
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par marissa_mean
    j'ai trouvé un exemple qui reproduit mon problème.
    Ok... bon, sauf que là ils n'utilisent que le keyPressed, et laisse le keyReleased vide... et qu'ils ne lancent pas d'animation dans un thread séparé... donc ça réagit uniquement sur les messages Windows...

    Je vois mieux le soucis... en fait le keyPressed doit être déclenché à chaque mesage de Windows, comme tu l'as souligné, ce que je trouve embêtant quand même... ton animation doit être plus rapide que le temps de latence, et donc tu le sens...

    Enfin bon... ce que tu pourrais faire, c'est utiliser un booléen pour savoir si tu es dans une boucle d'animation, ou si tu en es sorti. Et utiliser le booléen dans le keyPressed, pour voir si tu dois traiter le message, ou pas.
    En gros:

    - tu définis un booléen en variable de classe, initialisé par défaut à false
    - dans le keyPressed, tu testes le booléen. Si il est à false, tu le passe à true, et tu lances l'animation. Si il est à true, tu ne fais rien.
    - dans le keyReleased, tu arrêtes l'animation, et tu passes le booléen à false.

    Mais je ne pige toujours pas comment ton animation peut s'arrêter, alors qu'elle n'a pas vu le keyReleased...
    "Errare humanum est, sed perseverare diabolicum"

    Ma page sur DVP.com

  15. #15
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    Oui, j'allais justement faire comme ce que tu proposes.

    Actuellement il n'y a pas grand choses dans mon keyRelease, j'ai une variable qui contient le numéro de l'image actuelle correspondant à la frame d'animation (1/25) par exemple.

    A chaque keyPressed, j'incrémentais ce numéro.

    Dans le keyRelease, je remettais la clé d'animation à 0.


    Avec la nouvelle méthode, j'espère que ça ne va pas poser de problème au cas ou on appuie sur plusieurs touches en même temps.


    Je vais tester.

  16. #16
    Expert éminent

    Profil pro
    Fabricant et casseur d'avions
    Inscrit en
    Avril 2004
    Messages
    3 814
    Détails du profil
    Informations personnelles :
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : Fabricant et casseur d'avions
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2004
    Messages : 3 814
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par marissa_mean
    Avec la nouvelle méthode, j'espère que ça ne va pas poser de problème au cas ou on appuie sur plusieurs touches en même temps.
    Ben va falloir gérer ça judicieusement... parce que si tu appuies sur deux touches en même temps, et que tu en relâches une seule, faudrait pas que le booléen passe à false!
    Il faudra sans doute en utiliser plusieurs... un par direction... et un global...
    "Errare humanum est, sed perseverare diabolicum"

    Ma page sur DVP.com

  17. #17
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 16
    Points : 5
    Points
    5
    Par défaut
    Mon problème est résolu, voici comment j'ai du procéder :

    Une classe Control (qui hérite de Thread et implémente KeyListener)
    Cette classe gère le déplacement du personnage sur la carte, c'est à dire ses coordonnées et les collisions avec le décors.

    Une classe Character (qui hérite de Thread)
    Cette classe gère l'animation du personnage et uniquement l'animation, c'est à dire les frames de déplacement.

    Pourquoi avoir utilisé deux Threads ?
    De cette façon je peux gérer indépendamment les deux taches, c'est à dire donner des cadences différentes au déplacement et à l'animation. Concrètement, ça se traduit par un sleep(100) dans l'animation et un sleep(30) dans le déplacement.

    Dans chaque méthode run() des classes, je teste si un booléen est vrai, auquel cas je lance l'animation et le déplacement. Les booléens sont activés/désactivés dans la classe Control dès qu'une touche est enfoncée/relachée.


    Merci à tous pour votre aide.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 30/05/2011, 11h28
  2. Réponses: 2
    Dernier message: 04/04/2011, 15h54
  3. Réponses: 4
    Dernier message: 09/06/2010, 17h44
  4. Réponses: 1
    Dernier message: 28/09/2009, 08h30
  5. Réponses: 0
    Dernier message: 04/08/2008, 17h05

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