Bonjour,
Je souhaiterais savoir comment gérer avec glut la pression simultanée de 2 touches clavier (par exemple gauche et haut).
Merci d'avance.
Version imprimable
Bonjour,
Je souhaiterais savoir comment gérer avec glut la pression simultanée de 2 touches clavier (par exemple gauche et haut).
Merci d'avance.
Je propose cette solution :
bool keys[256];
// Fonction callback appelée lorsqu'une touche est pressée (key contient le code de cette touche)
processSpecialKeysPressing(int key,int x,int y)
{
switch(key)
{
case GLUT_KEY_UP:keys[0]=true;break;
case GLUT_KEY_RIGHT:keys[1]=true;break;
// etc...
}
}
processSpecialKeysReleasing(int key,int x,int y)
{
switch(key)
{
case GLUT_KEY_UP:keys[0]=false;break;
case GLUT_KEY_RIGHT:keys[1]=false;break;
// etc...
}
}
int main(int argc,char** argv)
{
for(int i=0;i<256;i++)keys[i]=false;
glutInit(argc,argv);
glutSpecialUpFunc(processSpecialKeysPressing);
glutSpecialDownFunc(processSpecialKeysReleasing);
glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
// ...
}
Ce qui permet de mettre a jour constamment un tableau de booléens indiquant si telle ou telle touche est pressée.
Plus tard dans le code tu pourras en tirer parti de la sorte :
if(keys[0] and keys[1])
{
// les touches haut et droites sont pressées.
}
N'oublie pas de définir des constantes symboliques plus parlante que 0 et 1 pour indiquer l'index dans le tableau de booléen de tel ou tel état.
#define UP 0x00
#define RIGHT 0x01
etc...
keys[UP] etc...
Et n'oublie pas de placer cette cette ligne :
glutSetKeyRepeat(GLUT_KEY_REPEAT_ON);
avant de quitter ton programme :wink:
Voilà, bonne chance ;)
Oh, merci beaucoup pour ta réponse ! C'est super, je vais tester ça ...
J'ai quelques petites questions :
Pourquoi tu utilises des valeurs en hexa genre 0x01 ?
A quoi sert glutSetKeyRepeat(GLUT_KEY_REPEAT_ON); ?
Merci encore.
Comme ça ! Pourquoi, t'aimes pas l'hexa ? :DCitation:
Pourquoi tu utilises des valeurs en hexa genre 0x01 ?
A réautoriser l'API de l'OS de destination (soit X11, soit Windows) à notifier plusieurs fois en continu l'évènement "une touche du clavier a été pressée".Citation:
A quoi sert glutSetKeyRepeat(GLUT_KEY_REPEAT_ON);
Dans un logiciel comme le Bloc Notes de windows, lorsque tu appuis sur une touche, un message est envoyé à l'application qui le traite en affichant un caractère par exemple.
Si tu maintiens ton doigt sur cette touche, il se passe environ une seconde de "vide" vis a vis des évènements claviers, puis soudain plusieurs messages sont envoyés a la suite jusqu'a ce que tu relàches la touche, provoquant l'affichage rapide de plusieurs caractères identiques.
Ce comportement n'est pas souhaitable dans une application OpenGL, sauf si tu réalises un logiciel de traitement de texte en 3D mais bon, l'intérêt est limité :D
Donc on commence par demander a glut au début de notre prog d'arrêter cette répétition des messages intempestives, et a la fin on réautorise ce comportement. (C'est important car sinon ton programme modifiera le mode de gestion des évènements claviers de TOUT ton ordi ! Pour revenir a la normale il faudra rebooter... (ou exécuté un programme qui contient un équivalent de glutSetKeyRepeat(GLUT_KEY_REPEAT_ON); )).
Oh oh ok ! Merci encore pour tes explications. Pour ce qui est de l'hexa, j'aurais pensé que mettre un entier aurait été identique ...
Bonjour, suite à ton aide pour la gestion du clavier, qui marche très bien, j'ai une petite question d'utilisation. En effet, je fait un if(keys[3]) {} par exemple, mais je le fais dans la fonction de call-back pour l´affichage dans la fenêtre.
Or cette fonction n'est appellée qu'à chaque fois qu'on demande une réactualisation d'image. Je me suis donc dit qu'il fallait que je réactualise en boucle ma scène. C'est extra fluide en mettant un glutPostRedisplay(); après le glutSwapBuffers();.
Cependant, mon processeur est utilisé à 100%, c'est assez logique. Je suppose que, dans les jeux, l'image est elle aussi réactualisée en permanence, mais je ne crois pas que les jeux prennent 100% du CPU. Je pense mettre un simple Sleep() avant le glutPostRedisplay(); et je voulais savoir si c'était la meilleur manière où s'il y a mieux.
Merci encore pour ton aide.
Ca l'est. C'est juste pour aligné proprement la déclaration de constantes connues a la compilation.Citation:
Pour ce qui est de l'hexa, j'aurais pensé que mettre un entier aurait été identique ...
Oui, les jeux sont faits avec des langages réputés rapide a l'exécution car ils doivent en permanence redessiner le "monde" à l'écran, c'est ce que l'on appelle FPS (frames per second), plus le nombre de fps est grand, plus l'animation est fluide.Citation:
Or cette fonction n'est appellée qu'à chaque fois qu'on demande une réactualisation d'image. Je me suis donc dit qu'il fallait que je réactualise en boucle ma scène. C'est extra fluide en mettant un glutPostRedisplay(); après le glutSwapBuffers();.
Tu dois mettre tout le code de dessin d'OpenGL dans ta fonction glutDisplayFunc, donc éventuellement des tas de tests pour savoir quoi dessiner a chaque moment du jeu... (C'est trés brouillon, le but d'un moteur de jeu est de faciliter cet aspect notamment, en demandant a chaque entité du jeu d'exécuter son propre code d'affichage par exemple, enfin là c'est un autre sujet...).
Cette fonction doit se terminer par un glutSwapBuffers (si tu est en GLUT_DOUBLE evidemment).
Il est inutile de mettre un glutPostRedisplay a la suite.
Cette fonction a pour but de forcer l'exécution du code de ta fonction display, mais en le faisant plus proprement (sinon tu pourrais l'appeler telle quelle dans le code).
Le glutPostRedisplay doit être placé a la fin de ta boucle principale, cad a la fin de glutIdleFunc
A ce propos je te conseille d'abandonner glut qui est une API vieillissante est limité, au profit d'une implémentation OpenSource de glut (FreeGlut, OpenGlut, etc...) mise a jour plus souvent, rétrocompatible avec glut et offrant de nouvelles fonctions intéressantes (comme le controle de la boucle principal, la possibilité de sortir proprement de glut, etc...)
Alors là ça dépend... les jeux de dernières générations sur des PC de dernières générations ne prennent pas tout le CPU mais pas loin...Citation:
Cependant, mon processeur est utilisé à 100%, c'est assez logique. Je suppose que, dans les jeux, l'image est elle aussi réactualisée en permanence, mais je ne crois pas que les jeux prennent 100% du CPU. Je pense mettre un simple Sleep() avant le glutPostRedisplay(); et je voulais savoir si c'était la meilleur manière où s'il y a mieux.
Ca dépend de ce que tu veux faire toi, faire mumuse avec un cube ?
Faire un jeu en 2D ? Faire un jeu en 3D avec un gameplay orienté 2D ? Faire ton propre moteur 3D ?
Chacun de ses objectifs prend plus ou moins de CPU, étant donné un PC pas trop pourri.
La meilleure solution pour gérer le framerate consiste a faire un sleep (enfin encore que, sleep prend un argument exprimé en secondes alors tu vas pas allez loin, vise plutôt du côté de nanosleep, toujours dans time.h).
Mais l'argument du sleep ne doit surtout pas être une constante, sinon le jeu ira a vitesse normale sur ton PC (car tu règleras a ta convenance) et ira pas assez vite sur un vieux PC, et trop vite sur un super PC.
Il faut calculer cet argument en fonction du temps que met le programme a effectuer un tour de boucle principal de ton jeu.
Conseil : utilise glutGet(GLUT_ELAPSED_TIME);
A+
Intéressant ! J'en apprend pas mal la.
En fait, il me faut faire en tant que projet "étudiant" une balade dans un batiment 3D, un doom like en gros.
J'ai compris (ou je crois avoir compris) que l'idleFunc fonctionne uniquement si le PC ne rame pas ...
Pour ce qui est de faire des Sleep, je ne sais pas trop comment faire, mais pour l'instant, j'ai juste fait ça pour obtenir les fps et réactualiser l'image uniquement si le CPU n'a pas de mal :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 // fonction de call-back qui tourne en tache de fond // lorsqu'il n'y a pas d'autre tache à executer GLvoid window_idle() { // les calculs de position, les déplacements // sont effectués, mais on met à jour uniquement // lorsqu'on passe dans cette boucle, c'est à dire quand // on a de la puissance pour effectuer le rendering de l'image frame++; temps = glutGet(GLUT_ELAPSED_TIME); if (temps - tempsold > 1000) { fps = (frame*1000.0)/(temps-tempsold); printf("FPS : %f et temps mis par 1000 boucles : %d\n",fps,temps-tempsold); //Sleep((temps-tempsold)/50); // paramètre en millisecondes tempsold = temps; frame = 0; } glutPostRedisplay(); // on est en tache de fond, donc ça ne rame pas on peut réactualiser }
AH moi suite a ce post j'ai une question vraiment bete,
j'ai meme honte de la poser, mais il le faut :
pour la fonction keyboard habituelle, on l'active avec
glutKeyboardFunc(keyboard);
mais pour tes fonctions spéciale :
processSpecialKeysReleasing(int key,int x,int y)
et
processSpecialKeysPressing(int key,int x,int y)
on les actives comment?????
ah ces debutants en openGL franchement ils ont de ces Questions.....
merci de me repondre quand ca me soulagerai.....
:)
En fait, les 2 fonctions sont glutSpecialFunc(&tafonctionquivabien) et glutSpecialUpFunc(&tafonctionquivabien)Citation:
pour la fonction keyboard habituelle, on l'active avec
glutKeyboardFunc(keyboard);
mais pour tes fonctions spéciale :
processSpecialKeysReleasing(int key,int x,int y)
et
processSpecialKeysPressing(int key,int x,int y)
;) Au moins j'aurais pu repondre a une question :D.
Huh ? Quel niveau d'étude, quelle école ... ?Citation:
En fait, il me faut faire en tant que projet "étudiant" une balade dans un batiment 3D, un doom like en gros.
L'idle func est une fonction exécutée en continue, quand l'application n'est pas occupé a géré les évènements ou le réaffichage, c'est une sorte de boucle principale si tu veux. Mais ne t'inquiètes pas, ça n'existe plus depuis longtemps les PCs qui n'auraient même pas le temps de gérer une dizaine d'appels a l'idleFunc par seconde, et heureusement !Citation:
J'ai compris (ou je crois avoir compris) que l'idleFunc fonctionne uniquement si le PC ne rame pas ...
Ta boucle principale doit contenir le code du moteur (le calcul des nouvelles positions des objets, etc...) puis un glutPostRedisplay, et enfin une fonction destinée a ralentir les PCs trop puissants.
Si par exemple tu as choisi une vitesse de 50 FPS, ce qui signifie que idéalement le PC doit mettre 20 miliseconde a effectuer un tour de ta boucle principale (une exécution du code contenu dans idleFunc), et que ce dernier ne met que 15 milisecondes, il faut lui dire d'attendre 5 milisecondes, temps pendant lequel il pourra se consacrer aux autres processus.
Le calcul de cette fonction de gestion de l'attente est assez simple :wink:
Pour l'affichage des FPS dans la console par exemple, il faut placer cette fonction dans la boucle principale également, voici le code que j'utilise :
La fonction getElapsedTime me renvoie le nombre de ms écoulées depuis le lancement du programme (elle est équivalente a glutGet(GLUT_ELAPSED_TIME); )Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 void gmlApplication::displayFPS()const { static uInt32 currentTime=0; static uInt32 timeBase=0; static uInt16 frame=0; static char s[30]; frame++; currentTime=getElapsedTime(); if(currentTime-timeBase>1000) { std::sprintf(s,"FPS:%4.2f",frame*1000.0/(currentTime-timeBase)); timeBase=currentTime; frame=0; std::cout<<s<<std::endl; } }
Voilà, A++
Pour les études, je suis en licence informatique, en région parsiennne.
Voici en gros les affichages que j'ai :Code:
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 GLvoid window_idle() { // les calculs de position, les déplacements // sont effectués, mais on met à jour uniquement // lorsqu'on passe dans cette boucle, c'est à dire quand // on a de la puissance pour effectuer le rendering de l'image frame++; temps = glutGet(GLUT_ELAPSED_TIME); if (temps - tempsold > 1000) { fps = (frame*1000.0)/(temps-tempsold); printf("FPS : %f et Temps mis par 1 boucle : %f et pause :%f\n",fps,((float)(temps-tempsold)/1000),20-((float)(temps-tempsold))/1000); // temps mis par 1000 boucles : temps-tempsold // temps mis par une boucle : (temps-tempsold)/1000 // si on choisi une vitesse de 50 FPS, soit 20 ms pour une boucle (une image) // si le temps mis par une boucle est de 15ms par // exemple, on va faire une pause de 5 ms Sleep((int)(20-((float)(temps-tempsold))/1000)); // paramètre en millisecondes //Sleep((temps-tempsold)/50); tempsold = temps; frame = 0; } glutPostRedisplay(); // on est en tache de fond, donc ça ne rame pas, on peut réactualiser }
Ca parrait correct. Le problème, c'est que mon microprocesseur est toujours utilisé à fond :SCode:FPS : 57 et Temps mis par 1 boucle : 1.016 et pause : 18.98
J'ai trouvé, il fallait faire le sleep en dehors du if, en effet, au lieu de faire une pause avant chaque réactualisation d'image, je ne le faisais que toutes les 1000 images ...