Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » [Tutoriel] La gestion du clavier en C
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

[Tutoriel] La gestion du clavier en C

Posté le 17/02/2016 14:11

Pour des questions de pratique ou d'habitude, beaucoup d'entre nous utilisent des fonctions comme IsKeyDown() pour gérer leurs entrées claviers. C'est mal, et voici pourquoi.

Le problème

Le principe d'un programme disposant d'une interface graphique est simple : il travaille quand l'utilisateur lui donne du boulot et le reste du temps il attend patiemment de recevoir des ordres (travailleur acharné, je vous dis), et se met donc en pause pour un temps indéterminé. En clair, il dort.

Seulement voilà, les bons jeux en temps réel donnent au programme du travail à faire régulièrement (comme faire bouger les adversaires sur une map ou faire avancer des animations) et cet ordre ne se donne pas au clavier.

Et là, l'erreur de logique apparaît : au lieu de réveiller le programme régulièrement pour lui rappeler qu'il a du travail, on va plutôt l'empêcher de dormir. « De toute façon il fonctionne tout aussi bien donc autant le maltraiter, ça ne fait de mal à personne », me direz-vous.

Sauf que ça fait du mal à la machine, qui d'une part n'apprécie pas de ne jamais pouvoir se reposer (effet similaire à de l'overlock), ce qui use les piles, et la rend peu réceptive aux signaux qu'on lui envoie puisqu'elle est occupée à faire autre chose.

Alors n'en déplaise aux concepteurs de bibliothèques (je pense à input mais cela n'a rien contre Ninestars), les méthodes de gestion du clavier qui ne mettent pas le programme en pause (puisque finalement le clavier c'est l'interface de l'utilisateur pour donner des ordres) ne sont pas propres.

« On a setFps() » me répondrez-vous, mais setFps() utilise Sleep() (de manière un peu barbare d'ailleurs) et Sleep() est une fonction qui ne prend même pas la peine d'endormir le processeur (désassemblez le syscall 0x420, vous verrez, y'en a pour 20 lignes d'assembleur et c'est une horreur), donc c'est du pareil au même.

La solution

Assez parlé, la méthode correcte est donc, si l'on reprend notre analogie, de laisser dormir notre processeur, en lui programmant tout de même un réveil pour qu'il n'oublie pas de faire son boulot. Ça tombe bien, ce réveil s'appelle un timer et c'est probablement la fonctionnalité la moins utilisée de fxlib.

#include "fxlib.h"
#include "timer.h"

void SetTimer(int timer_id, int elapse, void (*callback)(void));
void KillTimer(int timer_id);

Ces fonctions sont très simples d'utilisation. Le timer_id s'écrit ID_USER_TIMERX, avec X variant de 1 à 5. Si vous avez la flemme vous pouvez aussi écrire de 1 à 5, ça fonctionne aussi.

La durée s'exprime en millisecondes mais le résultat est arrondi à un multiple de 25 ms (probablement tronqué en fait). Vous parlez donc en millisecondes mais vous indiquez un multiple de 25.

Si vous n'êtes pas familier avec la notation du troisième paramètre, il s'agit d'un pointeur sur une fonction de la forme « void fonction(void) ». En gros c'est la fonction quoi.

Une fois SetTimer() appelée, le timer se lance et chaque fois que la durée indiquée s'écoule, la fonction que vous avez passée en troisième argument est appelée (et ce quoi que le programme soit en train de faire à ce moment-là). Notez que le timer se recharge automatiquement.

Lorsque vous voulez arrêter le timer, vous faites appel à KillTimer(). N'oubliez pas d'arrêter le timer quand vous quittez votre fonction, vous n'avez définitivement pas envie que vos ennemis continuent à bouger sur l'écran alors que vous êtes revenu au menu principal.

Maintenant que vous avez de quoi réveiller votre processeur, vous allez pouvoir lui octroyer du temps de sommeil avec la fameuse fonction GetKey().

int GetKey(unsigned int *key);

GetKey() endort le processeur jusqu'à ce qu'une pression sur une touche le réveille, excepté qu'aujourd'hui vous avez aussi prévu un timer pour le réveiller. L'argument est l'adresse d'une variable dans laquelle le code de la touche sera stocké en suivant la norme de l'en-tête keybios.h, et la valeur de retour n'intéresse jamais personne. Votre processeur retrouve enfin le sommeil, et le sourire.

Un exemple

Voici un exemple simple permettant d'afficher des animations à deux frames d'une seconde. C'est volontairement exhaustif. Il n'y a pas particulièrement de commentaires à faire, je pense que c'est assez simple. Si vous avez une question, laissez un commentaire.

#include "fxlib.h"
#include "timer.h"

static void draw(void);
static void callback(void);
static int animation_state = 0;

int main(void)
{
    unsigned int key;

    // On dessine une premiere fois le contenu de l'ecran au frame 0
    animation_state = 0;
    draw();

    // On met en place le timer pour une seconde de delai
    SetTimer(ID_USER_TIMER1, 1000, callback);

    while(1)
    {
        // On laisse dormir le processeur \o/
        GetKey(&key);
        if(key == KEY_CTRL_EXIT) break;
    }

    // On arrete le timer avant de quitter la fonction
    KillTimer(ID_USER_TIMER1);
}

static void draw(void)
{
    Bdisp_AllClr_VRAM();

    if(animation_state == 0)
    {
        // Dessiner au frame 0
    }
    else
    {
        // Dessiner au frame 1
    }

    Bdisp_PutDisp_DD();
}

static void callback(void)
{
    // On passe de 0 a 1, ou de 1 a 0
    animation_state = !animation_state;
    // Et bien sur on redessine !
    draw();
}


Le problème du retour au menu

Vous êtes sans doute déjà fou de joie de ces nouvelles connaissances et vous vous apprêtez probablement à les mettre en œuvre avec un enthousiasme renouvelé, et vous vous rendez soudain compte que GetKey() possède quelques fonctionnalités de plus que ses cousines de la famille de IsKeyDown() :

- La capacité de revenir au menu quand on appuie sur MENU
- La modification du contraste avec SHIFT et REPLAY

Le premier vous intéresse peut-être, mais il y a un souci : en effet, lorsque vous revenez au menu, les timers ne sont pas arrêtés. Donc une seconde après votre retour au menu, votre fonction callback() est appelée de nouveau et redessine la map de votre jeu alors que l'utilisateur se trouve bien dans le menu principal de la calculatrice.

Pour cela, il existe une solution (un workaround, en fait) qui consiste à passer par un peu d'assembleur (c'est du syscall en fait, mais les syscalls C sont très peu pratiques à utiliser) mais qui nécessite de vous convertir aux matrix codes.

Les matrix codes, c'est une autre façon de noter les codes des touches. C'est plus intuitif que la liste classique de KEY_CTRL_EXE, KEY_CTRL_EXIT et tout le reste. Observez le tableau suivant :

F1      F2      F3      F4      F5      F6              09
SHIFT   OPTN    VARS    MENU    ←       ↑               08
ALPHA   ^2      ^       EXIT    ↓       →               07
XTT     log     ln      sin     cos     tan             06
ab/c    F↔D     (       )       ,       →               05
7       8       9       DEL                             04
4       5       6       x       div                     03
1       2       3       +       -                       02
0       .       EXP     (-)     EXE                     01
                                                AC      00
06      05      04      03      02      01      00

Vous voulez le code de la touche MENU ? Aucun problème, repérez la colonne... 3, et la ligne... 8. Vous ajoutez 1 (oui, désolé), ça fait 4/9, et vous avez tout de suite le code : 0x0409. EXE est en position 2/1, son code sera donc 0x0302. ALPHA donnera 0x0708. Facile, non ? Libre à vous de refaire des macros ensuite, par exemple :

#define KEY_UP          0x0209
#define KEY_RIGHT       0x0208
#define KEY_DOWN        0x0308
#define KEY_LEFT        0x0309
#define KEY_SHIFT       0x0709
#define KEY_ALPHA       0x0708
#define KEY_EXE         0x0302
#define KEY_EXIT        0x0408
#define KEY_MENU        0x0409

Pour régler le problème du menu, il vous suffit (si vous travaillez avec le fx-9860G SDK, les linuxiens trouveront tous seuls) d'inclure le fichier getkey.src, en fichier joint au tutoriel, à votre projet, et d'utiliser la fonction getkey() qui s'y trouve au lieu de GetKey(). N'oubliez pas de modifier l'extension pour un .src, le site n'accepte pas ce format.

unsigned int key = getkey();

Et là, miracle, la fonction ne vous renvoie plus au menu lorsque vous appuyez sur la touche mais vous renvoie le code de KEY_MENU défini plus haut (0x0409). Notez que cette fonction renvoie systématiquement les matrix codes, donc la touche EXE ne donne plus KEY_CTRL_EXE (30001) mais KEY_EXE (0x0302).

Et alors vous pouvez stopper vous-mêmes vos timers, lancer le menu principal en utilisant la deuxième fonction fournie dans le fichier, et redémarrer vos timers dès que l'utilisateur retourne dans votre application.

key = getkey();
if(key == KEY_MENU)
{
    KillTimer(ID_USER_TIMER1);
    system_menu();
    draw();
    SetTimer(ID_USER_TIMER1, 1000, callback);
}

Notez qu'il est intéressant de redessiner le contenu de votre écran pour éviter à l'utilisateur de contempler le menu principal encore une seconde avant que votre timer n'arrive à expiration et ne le fasse lui-même.

Je n'ai pas encore de solution viable pour le problème du contraste (SHIFT + REPLAY), n'oubliez pas lorsque vous testez sur émulateur qu'après SHIFT les directions gauche et droite ne répondent plus, ce n'est pas un bug de votre programme.

En conclusion

Si vous avez lu jusqu'ici, vous n'avez plus le droit d'utiliser IsKeyDown(). Rappelez-vous, il n'y a quasiment aucune circonstance atténuante qui justifie que vous maltraitiez votre processeur.

Je terminerai sur une petite citation de Kirafi :
Kirafi a écrit :
Bon c'est bien beau tout ça , mais maintenant faut balancer le tuto sur le Combo Getkey/Timer pour que Phénix arrête de vomir à chaque fois que quelqu'un sort un Add-In ...

Je compte sur vous...

Fichier joint


Dark storm En ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 18/02/2016 12:22 | #


C'est en fichier joint. Il faut appuyer sur une touche fléchée (n'importe laquelle). J'ai ajouté des petits pour éviter qu'on sorte de l'écran.

J'ai pas testé, mais si ça marche je m'excuse, je pensais que Bkey_Set_RepeatTime arrondissait elle aussi à 25ms. Du coup ça marche très bien comme ça
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
-florian66- Hors ligne Ancien rédacteur Points: 2383 Défis: 20 Message

Citer : Posté le 18/02/2016 13:01 | #


Faudra que je teste un peu pour voir
In Arch, I trust ! And you ?
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 18/02/2016 13:04 | #


Dark storm a écrit :
J'ai pas testé, mais si ça marche je m'excuse, je pensais que Bkey_Set_RepeatTime arrondissait elle aussi à 25ms. Du coup ça marche très bien comme ça

Bkey_Set_RepeatTime() prend un entier quelconque qui est mutiplié par 25 (vive l'inconsistance de l'API). Mais comme le timer est moins fréquent (je crois que j'ai mis 80, c'est-à-dire au moins le double), ça fonctionne bien. Évidemment on peut pas monter au-dessus de 40 Hz, mais franchement sur calculatrice on n'a vraiment pas besoin d'atteindre 60 FPS.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 09/03/2016 13:58 | #


Bon donc après avoir lu les pages précédentes, j'aimerais savoir si cette méthode est viable pour du in-game en temps réel ? (les arguments de Ninestar sont plutôt convaincant quant aux bugs d'affichages qui pourraient éventuellement surgir ).

Et puis au pire, on peut toujours faire cette gestion de touche uniquement sur le menu qui permet de quitter le jeu .
iPod
Pour des parties rapides
Jusqu'où pourras-tu aller dans ce jeu "partie rapide" qu'est Dextris (élu Jeu Du Mois)
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
Autres
Franchement ils valent le coups
Deviens l'amiral de la marine dans SeaRush (jeu concours) (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Dark storm En ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 09/03/2016 14:03 | #


C'est d'autant plus valable pour les jeux de gestion en temps réèl

Tu as un timer d'affichage, éventuellement un autre qui sert à actualiser les données (genre toutes les secondes par exemple), et t'es tranquille
Au pire, tu affiche 1/25ème de seconde une valeur incohérente (car actualisation en arrière plan).
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 09/03/2016 14:04 | #


Okay donc j'adopte !
Encore merci Lephé .
iPod
Pour des parties rapides
Jusqu'où pourras-tu aller dans ce jeu "partie rapide" qu'est Dextris (élu Jeu Du Mois)
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
Autres
Franchement ils valent le coups
Deviens l'amiral de la marine dans SeaRush (jeu concours) (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 09/03/2016 21:03 | #


Les problèmes évoqués par Ninestars se contournent, sauf le multikey, pour ça il faudra attendre gint
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 09/03/2016 21:23 | #


Ah oui voilà c'était ça le gros soucis qui m'embêtait le multikey qui m'est indispensable ...
Bon bah on compte sur toi Lephé !
D'ailleurs en passant, j'espère que t'avance également sur fxspriter .
iPod
Pour des parties rapides
Jusqu'où pourras-tu aller dans ce jeu "partie rapide" qu'est Dextris (élu Jeu Du Mois)
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
Autres
Franchement ils valent le coups
Deviens l'amiral de la marine dans SeaRush (jeu concours) (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 09/03/2016 21:25 | #


Kirafi a écrit :
Ah oui voilà c'était ça le gros soucis qui m'embêtait le multikey qui m'est indispensable ...
Bon bah on compte sur toi Lephé !

J'ai encore pas mal de problèmes avec gint, je suis obligé d'avancer très doucement... et pas particulièrement sûrement vu que ça fait quatre fois que je recommence. Mais j'y arriverai !

Kirafi a écrit :
D'ailleurs en passant, j'espère que t'avance également sur fxspriter .

Et moi qui voulait finir Atlantis... si je continue comme ça il va finir dans mon cimetière de programmes lui aussi... ^^' La compilation sous windows n'est pas particulièrement compliquée, si vraiment tu en as le temps et l'envie tu peux essayer toi-même Mes essais sont peu fructueux, mais il faudra bien que j'y arrive...
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2461 Défis: 24 Message

Citer : Posté le 17/03/2016 14:05 | #


C'est vraiment bien cette méthode, plus j'y pense, plus elle me séduit.
Je vais l'utiliser pour mon nouveau projet
Tu as avancé dessus ?

Ajouté le 17/03/2016 à 14:08 :
Lephenixnoir a écrit :
Les jeux sont faits comme ça, mon ami. Aucun programme informatique réel n'arrête le processeur en plein milieu pour des délais supérieurs à la ms.
En effet, j'ai lu des articles sur le moteur de Battlefield 4, je moteur physique tourne à 29.995 fps alors que l'affichage lui est vraiment variable. .. J'aime cette méthode !

Ajouté le 17/03/2016 à 14:12 :
Par contre est-ce normal que dans ton niauseux, on ne puisse pas maintenir la touche ? Comment faire sinon ?
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 18/03/2016 11:39 | #


Ninestars a écrit :
C'est vraiment bien cette méthode, plus j'y pense, plus elle me séduit.
Je vais l'utiliser pour mon nouveau projet
Tu as avancé dessus ?

Content que ça te plaise !
Non, je n'ai malheureusement pas avancé d'un pouce depuis qu'on en a parlé pour la dernière fois, faute de prépa...

Ninestars a écrit :
En effet, j'ai lu des articles sur le moteur de Battlefield 4, je moteur physique tourne à 29.995 fps alors que l'affichage lui est vraiment variable. .. J'aime cette méthode !

Tu vois qu'on est d'accord !

Ninestars a écrit :
Par contre est-ce normal que dans ton niauseux, on ne puisse pas maintenir la touche ? Comment faire sinon ?

En l'occurrence il faut utiliser les touches fléchées
Sinon je crois qu'il y a un syscall pour répéter toutes les touches. Cherche peut-être dans la doc, sinon un PutKey() un peu barbare réglera le problème... (même si c'est pas terrible ).
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2461 Défis: 24 Message

Citer : Posté le 18/03/2016 13:49 | #


The cursor key is the only key that can be set for repetition. Other keys will not repeat even if they are continuously pressed.
En effet ça c'est un peu dommage...
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 19/03/2016 12:21 | #


Tu peux toujours utiliser GetKeyWait() avec les options de timer et répéter manuellement l'event si KEYREP_TIMEREVENT est renvoyé

Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2461 Défis: 24 Message

Citer : Posté le 19/03/2016 18:35 | #


D'accord
J'ai pas trop eu le temps de coder mais j'ai touché à ton niaiseu pour faire des tests.
- Je remarque que quand on appuie sur un touche, l'acceleration devient positive et qu'elle est remise à sa valeur négative dans time, donc à partir du moment où la fréquence de répétition du GetKey est supérieure à celle du timer cela fonctionne bien car le calcul dans time utilise le a positif. Cependant, dans le cas contraire, le calcul dans time est effectué avec par moment a positif ou négatif. On en conclu qu'il faut forcement que la fréquence de répétition du GetKey soit supérieure ou égale à celle du timer.

- Maintenant, si au lieu de modifier l'accélération, on veut que le point monte de 1 pixel par frame. J'ai donc modifié un peu le code et ajouté y += 1; derrière le GetKey.
Voici ce que cela donne

A gauche je maintiens EXE, à droite je maintiens une flèche. Je ne vais parler que la partie droite.
Au lieu d'obtenir une droite continue à 45°, on obtient des trous car la fréquence de répétition du GetKey est supérieure à celle de l'affichage. C'est à dire que y += 1; est executé plusieurs fois entre chaque affichage.
Ainsi pour avoir une droite continue, il faut que la fréquence du GetKey et du timer soient égales.


Conclusion des deux paragraphes : la fréquence du timer et la répétion du Getkey doivent être égales.
On peut écrire :
int fps = 4
Bkey_Set_RepeatTime(1, fps);
SetTimer(ID_USER_TIMER1, fps*25, time);
Et on obtient ça

A gauche je maintiens EXE, à droite je maintiens une flèche.
Voilà maintenant c'est mieux, j'ai toujours la répétion que pour les touches fléchées, mais au moins j'ai une frame = 1 pixel de plus.

Seulement j'obtient aussi ceci :

A gauche je maintiens une flèche, à droite je martelle une fleche.
On remarque qu'il est possible d'executer plus rapidement le code y += 1; si la touche est martelée.
Et c'est ça le problème, les FPS ne sont pas limités pour les appuies de touche.
Cela revient exectement au problème que j'avais cerné plus tôt :
NineStars a écrit :
En m'appuyant sur ton exemple, imaginons que si j'appuie sur la touche droite, mon personnage va une case à droite.
Si j'appuie très rapidement, il va aller rapidement à droite, mais sans aucune limite de vitesse.



(ne lis pas à partir d'ici tu vas me détester XD)
Ainsi, quitte à avoir une fréquence de rafraichissement du clavier et de l'écran identique, je pensais à une façon d'organiser le code de la manière suivante :
int end = false;

void main()
{
    int key;
    SetTimer(1, 50, update)
    while (end == false)
    {
        GetKey(&key)
    }
    KillTimer(1);
}

void update()
{
    input_update();
    engine_update();
    graphics_update();
}

En gros le GetKey sert juste à faire patienter le processeur, et si une touche est appuyée, elle nous importe pas. En attendant, la jeu continue de tourner toutes les 50ms.
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 19/03/2016 18:54 | #


Ninestars a écrit :
On en conclu qu'il faut forcément que la fréquence de répétition du GetKey soit supérieure ou égale à celle du timer.

C'est exact, je ne sais plus combien j'ai paramétré dans mon niaiseux mais je crois qu'il y a au moins trois ou quatre fois la fréquence pour assurer la fluidité.

Ninestars a écrit :
J'ai donc modifié un peu le code et ajouté y += 1; derrière le GetKey.

Ça c'est une « erreur » : n'oublie pas que la fréquence du GetKey doit être conceptuellement supposée infinie donc il faut utiliser les variables temporelles normalement, et ajuster l'incrément de y en fonction du temps qui s'écoule (pour être tout à fait rigoureux)

Ninestars a écrit :
Voilà maintenant c'est mieux, j'ai toujours la répétion que pour les touches fléchées, mais au moins j'ai une frame = 1 pixel de plus.

Mauvaise conception, un ordinateur parfait doit tourner à une vitesse infinie et obtenir le même résultat donc il faut ne faut pas baser de mise à jour du moteur physique sur une donnée telle que le rafraîchissement de l'écran !

Ninestars a écrit :
En effet, j'ai lu des articles sur le moteur de Battlefield 4, je moteur physique tourne à 29.995 fps alors
que l'affichage lui est vraiment variable. .. J'aime cette méthode !

C'est précisément ce que tu disais là. Le moteur physique a une fréquence fixe indépendante de l'affichage... augmenter d'un pixel à chaque frame est un non-sens en soi

Ninestars a écrit :
On remarque qu'il est possible d'executer plus rapidement le code y += 1; si la touche est martelée.
Et c'est ça le problème, les FPS ne sont pas limités pour les appuies de touche.

Il faut bien faire la distinction entre le moteur graphique et le moteur physique.
Le moteur physique doit tourner à une fréquence très précise et très exacte.
Le moteur graphique doit tourner le plus rapidement possible sans empiéter sur le moteur physique.
Mon programme n'implémente pas ça correctement (le défi de Darks c'était « un niaiseux sans IsKeyDown() ») mais il faut le penser comme ça. On devrait avoir un diagramme comme ceci :
 timer                            programme
   |                                 |
   |  Événements            À pleine |
   |  réguliers            puissance |
   v                                 v
 moteur          données           moteur
physique ----> centralisées ----> graphique

Il est absurde de lier l'évolution des variables à l'affichage.

Ton code à la fin n'est pas moche mais conceptuellement c'est pas terrible. D'abord tu lie la fréquence d'affichage et la fréquence d'évolution du moteur physique. Donc si ton jeu lagge graphiquement t'es sûr de foutre en l'air les réflexes du joueur parce que l'affichage graphique fait patienter le moteur physique qui devrait avoir la priorité absolue. Ensuite si ton jeu a de faibles capacités graphiques parce que les procédures sont lourdes, tu risques de ne pas pouvoir dépasser 5 à 6 FPS (ce qui reste raisonnable sur une calto avec un écran de cette rémanence cela dit) et alors le timer va renvoyer un événement avant que le handler ne soit terminé -- et là le programme principal ne reprend jamais. Même s'il ne fait rien en soi c'est une erreur parce que tu freezes l'exécution ! Et si jamais tu réduis la fréquence du timer, tu réduis d'autant la réactivité du clavier... et 5 FPS sur le clavier ça fait mal !

Bref, je persiste et je signe : le moteur graphique sur le timer, le clavier sur un timer de fréquence ou moins double, et l'affichage dans le programme principal avec la puissance qu'il reste.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 20/03/2016 11:42 | #


Ce que tu appelle le clavier c'est le moteur physique du coup ?
Et le moteur graphique c'est genre les implémentations de coordonnées d'un objet ?
iPod
Pour des parties rapides
Jusqu'où pourras-tu aller dans ce jeu "partie rapide" qu'est Dextris (élu Jeu Du Mois)
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
Autres
Franchement ils valent le coups
Deviens l'amiral de la marine dans SeaRush (jeu concours) (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 20/03/2016 11:43 | #


Kirafi a écrit :
Ce que tu appelle le clavier c'est le moteur physique du coup ?
Et le moteur graphique c'est genre les implémentations de coordonnées d'un objet ?

Non, c'est tout l'inverse.
Le clavier n'est ni le moteur physique ni le moteur graphique et le moteur graphique c'est l'affichage. Voilà ce dont on dispose :

→ Moteur physique (fréquence f) : calcule les coordonnées et les interactions
→ Gestion du clavier (fréquence au moins 2f à défaut d'interruption) : récupération de l'état des touches
→ Moteur graphique (toute la puissance restante) : dessin à l'écran
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 20/03/2016 11:45 | #


Okay donc on affiche avec un max de vitesse, mais du coup ça ne met pas le prcesseur en "pause" ça
iPod
Pour des parties rapides
Jusqu'où pourras-tu aller dans ce jeu "partie rapide" qu'est Dextris (élu Jeu Du Mois)
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
Autres
Franchement ils valent le coups
Deviens l'amiral de la marine dans SeaRush (jeu concours) (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 20/03/2016 11:46 | #


Kirafi a écrit :
Okay donc on affiche avec un max de vitesse, mais du coup ça ne met pas le prcesseur en "pause" ça

Oui enfin tu affiches avec un max de vitesse quand tu manipules des gros environnements, comme de la 3D par exemple, sinon tu limites la fréquence
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 20/03/2016 11:50 | #


Oui si ça ne bouge pas des masse quoi, donc le fréquence du moteur graphique dois au moins être égale à f (soit celle du moteur physique avec ton exemple là).
iPod
Pour des parties rapides
Jusqu'où pourras-tu aller dans ce jeu "partie rapide" qu'est Dextris (élu Jeu Du Mois)
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
Autres
Franchement ils valent le coups
Deviens l'amiral de la marine dans SeaRush (jeu concours) (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 20/03/2016 11:52 | #


Non, pas forcément. Pourquoi ça ?

Le moteur physique a généralement une fréquence fixe (genre 10 FPS sur calto), l'affichage se débrouille comme il veut après.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 122 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd