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 En ligne Administrateur Points: 24673 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


Lephenixnoir En ligne Administrateur Points: 24673 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 (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 20/03/2016 12:07 | #


Donc on doit avoir :
-> Un timer Clavier (avec le Getkey) avec une fréquence à minimum 2f.
-> Un timer Moteur Physique (Changement de coordonnées, Collisions, etc...) à une fréquence f.
-> Pas de timer de Moteur Graphique (l'Affichage).
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 En ligne Administrateur Points: 24673 Défis: 170 Message

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


En fait dans l'idéal il faudrait ceci :
→ Un clavier qui interrompt le programme quand un événement est généré (le must, le plus économe) : pas de timer.
→ Un timer pour le moteur physique à une fréquence fixe.
→ Un affichage graphique qui utilise ou non un timer selon ses besoins. La régulation de puissance se fait à ce niveau-là.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 20/03/2016 13:08 | #


Je suis d'accord avec ce que tu dis Lephenixnoir
Il faut faire du y += 1 * temps_entre_frames_getkey
Enfin ce n'est pas tout, puisque qu'il faut tout coefficienter pour tout remmettre en unité de base : le pixel par seconde histoire d'avoir des unitées "homogènes".

lephenixnoir a écrit :
Un affichage graphique qui utilise ou non un timer selon ses besoins
On est obligé d'utiliser un timer puisque GetKey stop le programme. Il n'y a pas de moyen d'avoir la fonction draw() appelée en continue.

Imaginons que la moteur physique tourne à la fréquence f et le moteur graphique à 2f. Ce qui se passe c'est que l'on va afficher 2 fois la même frame puisque les informations calculées par le moteur physique n'auront pas changées.
En me référant à cet article, il faut faire une interpolation linéaire entre chaque frame du moteur physique...
Ça devient hyper compliqué pour pas grand chose
Je suis en train de modifier le niaiseux pour intégrer tout ça.
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 20/03/2016 13:16 | #


Ninestars a écrit :
Enfin ce n'est pas tout, puisque qu'il faut tout coefficienter pour tout remmettre en unité de base : le pixel par seconde histoire d'avoir des unitées "homogènes".

Oui, c'est exact. Il faut donc modifier la formule en fonction de la durée du timer. Enfin tout ça c'est théorique hein, en pratique on peut s'en passer comme je l'ai fait dans mon niaiseux : avec les réglages que j'ai laissés on a une vitesse raisonnable parce qu'on se moque d'avoir un vrai « pixel par seconde ».

Ninestars a écrit :
On est obligé d'utiliser un timer puisque GetKey stop le programme. Il n'y a pas de moyen d'avoir la fonction draw() appelée en continue.

Nope, GetKeyWait(), les interruptions sont des exemples de solution. Le meilleur étant la seconde, que je tenterai d'utiliser avec gint.

Ninestars a écrit :
Imaginons que la moteur physique tourne à la fréquence f et le moteur graphique à 2f. Ce qui se passe c'est que l'on va afficher 2 fois la même frame puisque les informations calculées par le moteur physique n'auront pas changées.

En effet, ce qui signifie que l'effet réel sur le FPS est de la fréquence f

Ce qui rappelle cette remarque de Kirafi :
Kirafi a écrit :
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à).

En réalité, si physique < graphique on a des FPS inutiles, et si graphique < physique on saute des frames physiques. En conclusion, je pense que le meilleur est encore:

fréquence graphique = fréquence physique


Ninestars a écrit :
il faut faire une interpolation linéaire entre chaque frame du moteur physique...
Ça devient hyper compliqué pour pas grand chose

Ouh là, pas besoin de tant que ça ! Mais en effet dans la théorie pure, c'est ce qu'il faudrait faire
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 02/02/2017 07:41 | #


Enfer et damnation !
Faut passer des fonctions sans paramètres... ça casse tout .
Parce que ma fonction de dessin prends TOUS les "éléments" du jeu à afficher, soit, des 10ène de structures de coordonnées etc.
Du coup c'est relou, dois-je vraiment tout passer en global ? Dans ce cas, cela représente à mon sens une grosse faiblesse dans l'utilisation de cette technique.
J't'explique pas le bazard avec des global avec mes fonctions dans des fichiers différents .

Aussi il faudrait préciser que pour les touche F1..6, c'est pas 0x0710
Mais 0x07A, etc. .

Edit
Bon je me suis débrouillé .
Et du coup j'ai refait Sleep "propre" , voici pour ceux que ça intéresse.
volatile int not_elapsed;
void sleep(int t)
{
    not_elapsed = 1;

    SetTimer(ID_USER_TIMER1, t, elapsed);
    while(not_elapsed);
    KillTimer(ID_USER_TIMER1);
}
void elapsed()
{
    not_elapsed = 0;
}


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 En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 02/02/2017 12:27 | #


Il te faut de près ou de moin des globales, désolé. Il y a de meilleures solutions mais le simple fait que tu doives écrire toute la liste des structures du jeu chaque fois que tu appelles ta fonction de dessin est une faiblesse au moins équivalente.

Ton sleep() est, je suis désolé, aussi moche que celui du système : tu as fait comme eux. L'erreur est la boucle while, tu ne peux pas résoudre ce problème sans invoquer l'instruction sleep.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 02/02/2017 12:31 | #


Ah mince, donc on ne pourra pas avoir de sleep() correct avec le SDK sous Windows .
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 Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 02/02/2017 14:36 | #


Pas sans appel de très bas niveau (c'est à dire au niveau proco) si je ne m'abuse.
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 02/02/2017 16:38 | #


Bien sûr que si.

  .export _cpu_sleep

_cpu_sleep:
  sleep
  rts
  nop

  .end

Tu enregistres ça dans un fichier (d'extension src) de ton projet et tu remplaces ta boucle par :

while(not_elapsed) cpu_sleep();


Voyez les sources du module clock de gint, il y a quasiment texto la même fonction, exceptée qu'elle compte en microsecondes et pas en paquets de 25 ms.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 02/02/2017 17:53 | #


Okay ça marche ça , du coup c'est propre .

Me reste juste le soucis de la répétition de touche, c'est embêtant sous SDK Windows y'a moyen de faire quelque chose pour éviter de devoir faire du coup par coup ?

Sinon j'pensais caler ça
if(!isKeyDown) key = getkey();

Edit
Bon j'arrive pas à créer tout ce bazar de moteur physique 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 En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 02/02/2017 19:59 | #


Répétition des touches ? Tu peux configurer le délai de répétition de GetKey() :
void Bkey_Set_RepeatTime(int first, int others);

L'unité est de 1 pour 25 millisecondes de délai. Les valeurs par défaut sont (5, 1).

Le coup de mélanger IsKeyDown() et GetKey(), même si en théorie c'est licite et ça repose le proco, franchement c'est pas une bonne idée. Mélanger du bloquant et du non-bloquant peut révéler des surprises... honnêtement, je sais qu'avec gint ce serait le bordel. C'est pas vraiment pensé pour.

Par exemple Cake avait proposé une fois pour détecter, disons SHIFT + MENU, quelque chose comme :
GetKey(&key);
if(key == KEY_CODE_SHIFT && IsKeyDown(KEY_CODE_MENU)) { ... }

Ça a l'air innocent, mais ça peut échouer pour pas mal de raisons. Je ne le conseille vraiment pas, et je suis certain qu'on peut toujours l'éviter à peu près proprement.

Pour le moteur physique c'est pas si difficile. Voici en gros à quoi peut ressembler la structure globale du programme :
→ Des variables (disons globales pour simplifier) contenant l'état du jeu à tout instant.
→ Un module (ou une fonction, enfin) pour dessiner le jeu à l'écran en lisant les variables (moteur graphique).
→ Un module pour calculer les interactions et mettre à jour l'état du jeu à chaque frame (moteur physique).

Le principe consiste à exécuter le calcul et le dessin périodiquement à l'aide d'un timer. A priori rien n'empêche de calculer à 50 Hz et afficher à 30 FPS, mais avec un seul timer on ne peut que faire les deux à la même fréquence (ce qui n'est pas absurde pour autant : un état du jeu, un frame à l'écran), et c'est tout aussi simple. Ainsi :
→ La procédure principale configure le timer et se met en attente d'événements avec GetKey().
→ Régulièrement, le timer arrive à expiration, ce qui engendre le calcul d'un nouveau frame à partir de l'état courant (appel du moteur physique) et l'affichage de ce nouveau frame (appel du moteur graphique).
→ Lorsqu'une touche est pressée, la procédure principale modifie un paramètre dans l'état du jeu (e.g. la direction du joueur sur une map 2D) pour que le moteur physique puisse prendre en compte le changement au prochain calcul de frame.
→ Et c'est tout. Quand le jeu se termine, la procédure principale arrête le timer.

Est-ce clair ?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 02/02/2017 20:23 | #


Okay okay voilà ce que j'ai fait :
Un moteur physique en même temps que graphique, enfin, calcul puis affichage à la fin dans le même timer.
Et dans la boucle principale le getkey qui met à jour la variable key, cette dernière servant à faire le lien entre le clavier et les moteur physique.
Note : J'ai pas encore étudié la répétition du getkey, je regarde.
// Moteur physique / graphique de l'accueil
void menu()
{
        // Déplacement du personnage
    if(key == K_LEFT) perso_move(&p, L, C);
    else if(key == K_RIGHT) perso_move(&p, R, C);
    else perso_d(&p, C);

    display_home();    // Affichage de l'accueil
}

// Prog principal
...
    // Boucle (en théorie infini) de l'accueil
    while(1)
    {
        // Si la touche pressée est différente d'une touche qui nécessite une répétition
        if(!key_down(38) && !key_down(27))
        {
            key = 0;        // Reinitialisation de la touche
            key = getkey();    // Attente de l'appuis d'une touche (mise en pause du processeur)

            if(key == K_MENU || key == K_EXIT) exit_programme();
        }
    }
...

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 En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 02/02/2017 20:25 | #


Afficher et calculer en même temps est possible, mais séparer a un avantage certain : parfois tu veux redessiner le jeu sans calculer un nouveau frame, par exemple quand le jeu démarre (et ce, sans attendre que le timer arrive au moins une fois à expiration).

Attends, de l'accueil ? Il ressemble à quoi ton accueil pour que t'aies besoin de faire cette construction complexe ? ô_o
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 02/02/2017 21:36 | #


Lephenixnoir a écrit :
Bien sûr que si.

  .export _cpu_sleep

_cpu_sleep:
  sleep
  rts
  nop

  .end


Heu chez moi, faire un bout d'assembleur pour utiliser l'instruction du proco, c'est faire un appel au niveau du proco xD
Enfin, passons.
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 02/02/2017 21:56 | #


Ah oui je vois ce que tu veux dire Lephé, pour genre mettre en pause ou un truc dans le style .

Pour l'accueil , en fait c'est juste que la sélection se fait avec le personnage, un peu comme dans "Evasion Survival" de Dodormeur . Donc j'utilise la boucle principale qui fait tourner 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)
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 03/02/2017 07:37 | #


Bien sûr Darks. Ma réponse était surtout par rapport à cette remarque :
Kirafi a écrit :
Ah mince, donc on ne pourra pas avoir de sleep() correct avec le SDK sous Windows .


Oh, je vois. Je m'étais douté un peu du coup de l'accueil dans le moteur de jeu mais je n'étais pas sûr.

Il faut que vous compreniez que getkey() n'est pas là juste pour endormir le processeur : c'est une fonction de gestion du clavier qui en corollaire appelle cpu_sleep(). Donc servez-vous-en pour lire le clavier et effacez à tout jamais les key_down() de vos programmes. Si vous réalisez la construction de ce tutoriel en gardant des key_down() c'est que vous n'avez pas compris le principe..
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 04/02/2017 14:40 | #


Bon voilà ce que j'ai pour ma boucle de jeu, est-ce correct ?
while(1)
{
    Bkey_Set_RepeatTime(1, 1); // Répétition de touche

    key = 0; // Reinitialisation de la touche
    screen_refresh(screen, &d, &p, &g); // Premier affichage du jeu

    SetTimer(ID_USER_TIMER1, MS_ENGINE, engine); // Moteur

    // Boucle du jeu, si Menu ou Exit pressée, sortie du programme
    while(key != K_MENU && key != K_EXIT)
    {
        key = getkey(); // Attente de l'appuis d'une touche
    }

    KillTimer(ID_USER_TIMER1); // Arrêt du timer du moteur

    Bkey_Set_RepeatTime_Default(); // Répétition de touche par défaut

    system_menu();     // Retour "propre" au menu de la calculatrice
}


Ajouté le 04/02/2017 à 14:43 :
Ah mince quand on laisse appuyé sur menu ça clignote , j'avais pas ça tout à l'heure mais c'était mal conçu.

Edit : Ah tiens, sur Calto ça le fais pas .
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 En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 04/02/2017 15:22 | #


Je vais me répéter, mais n'allez pas dire que c'est de ma faute.
Arrêtez de gérer vos timers et votre configuration dans vos boucles !

On configure une fois la vitesse de répétition du clavier pour tout le jeu et seulement quand on s'en va on la réinitialise. Le timer, c'est pareil. Vous vous rendez compte que si votre jeu va vite parce que l'utilisateur appuie souvent sur des touches votre timer va se faire arrêter puis redémarrer à chaque frame ?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Kirafi Hors ligne Membre Points: 2180 Défis: 10 Message

Citer : Posté le 04/02/2017 15:27 | #


Ah mais non mais non !
La "grosse" boucle c'est quand il quitte le jeu .
C'est pour ça que tu vois l'arrêt des timers et tout.

En gros, plutôt que de faire comme dans ton post principal
key = getkey();
if(key == KEY_MENU)
{
    KillTimer(ID_USER_TIMER1);
    system_menu();
    draw();
    SetTimer(ID_USER_TIMER1, 1000, callback);
}


Bah je sort de ma petite boucle.
Cela évite d'avoir à créer le même timer à 2 endroits dans le code, soit au lancement, et quand on rerentre sans avoir lancé d'autre Add-In entre temps .
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 En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 04/02/2017 15:38 | #


Pardon, je me suis trompé. T'as le droit de m'engueuler.

Oui, c'est tout à fait ça. C'est juste que t'as pas de moteur encore...
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (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 148 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