Timerlib pour Casio Graph100

version 1.2

Table des matières:

A propos de cette lib
Principe
Utilisation
Commentaires


A propos de cette lib

Le but de cette lib est de permettre une gestion plus aisée du temps réel, elle devrait surtout être utile pour les programmes de jeu par exemple ou dans tout autre cas où des animations doivent continuer à tourner même quand l'utilisateur ne fait rien. Exemple: un jeu en temps réel, avec des ennemis qui "vivent" et se déplacent indépendamment du personnage principal.

Un problème que l'on rencontre fréquemment dans ce genre de prog est la variation du framerate (ou de la vitesse d'animation du prog) qui peut parfois survenir lorsque le nombre d'objets ou d'ennemis à gérer augmente, ou qu'il y a subitement plus de choses à afficher par exemple.

La "solution" proposée ici n'est pas d'empêcher le framerate de varier (si y'a + de choses à faire, ça prend forcément + de temps, sauf si le prog est bridé dynamiquement), mais plutôt d'empêcher la vitesse des animations de varier en même temps, donc de la rendre indépendante du framerate. Donc en pratique, si vous faites clignoter du texte à l'écran par exemple, le clignotement restera constant, même si votre framerate passe subitement de 40 à 25 images par seconde.

L'idée développée est de mettre en place une sorte d'horloge qui s'incrémente un peu plus de 50 fois par seconde, et de manipuler des objets, appelés "timers", qui sont en fait des espèces de petits chronomètres que l'on peut lancer, arrêter, remettre à zéro etc, et qui donneront donc une certaine mesure du "temps" écoulé depuis leur lancement, indépendamment du nombre de cycles effectués par le programme durant ce laps de temps.

Ceci se fait en Programmation Orientée Objet, donc en C++. Ce n'est donc malheureusement pas compatible avec les programmes écrits en C, mais rien n'empêche de développer une méthode similaire avec des structures et non des classes, bien que la manipulation des timers en sera moins aisée.

La suite de ce fichier lisez-moi explique le mode de fonctionnement des timers ainsi que leur utilisation (notez qu'il n'est pas vraiment nécessaire de comprendre exactement comment ça fonctionne pour pouvoir les utiliser correctement, c'est tout le principe de la POO ;)).


Principe

Par l'idée de "timer", j'entends "variable qui s'incrémente toute seule régulièrement après un certain intervalle de temps". En quelque sorte, nous en connaissons déjà, même s'ils ne se présentent pas sous la forme d'une variable: il s'agit par exemple du port 0x1D de la calculatrice, qui s'incrémente après chaque seconde écoulée, et qui est utilisé pour mesurer des temps ou pour indiquer l'heure.

En fait ici, on va en créer d'autres "artificiellement", pour pouvoir les utiliser comme dans le programme. "Artificiellement", pour deux raisons:

En fait la seule chose qui est réellement incrémentée par l'interruption 1C, c'est une variable globale de type int, que l'on appellera "Horloge", et qui est commune à tous les timers. Ceux-ci sont en fait des espèces de petites variables qui savent à quel moment elles ont été initialisées, et qui, à chaque fois qu'on veut en connaitre la valeur, "vont regarder l'heure", c'est-à-dire consulter l'Horloge, et disent combien de "temps" s'est écoulé depuis leur dernière initialisation, grâce à une simple soustraction.

En ajoutant quelques fonctions supplémentaires, ces timers sont devenus de véritables chronomètres, que l'on peut activer, arrêter et réinitialiser à souhait. Ils peuvent normalement "afficher" des valeurs entre 0 et 65535, mais on peut également leur fixer une autre valeur maximale pour qu'ils reviennent automatiquement à zéro à chaque fois qu'il arrivent à 200, par exemple.

Voila pour le fonctionnement: il y a en gros une horloge qui tourne en continu, et tous les timers sont des objets qui vont consulter cette horloge pour dire depuis combien de temps ils sont activés.


Utilisation

Pour pouvoir utiliser correctement un timer, il suffit de s'imaginer que c'est un chrono, avec 3 gros boutons START, STOP et RESET, et un petit menu config. (Bon il vaut quand même mieux savoir +/- comment utiliser des instances de classe en c++... mais pour ça, lisez un chapitre d'un tuto parlant des fonctions membres et des constructeurs, ça suffira ;))

Initialisation de l'Horloge

Au début du programme, il faut activer l'horloge, et il faut la désactiver à la fin. Ceci se fait avec la fonction Timer::SetClock() à laquelle on passe 1 pour l'activation ou 0 pour la désactivation.

Voici un cas très simple à titre d'exemple:

   void main()
   {
   Timer::SetClock(1); // activation de l'horloge, les timers sont utilisables

   ... // les instructions à exécuter


   Timer::SetClock(0); // désactivation de l'horloge, les timers deviennent inutilisables

   return;
   }

Création des timers

Pour créer un timer, il suffit de déclarer une variable de type Timer. ex:

   Timer UnTimer;

Dans ce cas-ci, UnTimer aura 65535 comme valeur limite et sera tout de suite activé.

Pour qu'il soit à l'arrêt après sa création, il faut mettre TIMER_OFF entre parenthèses:

   Timer UnAutreTimer(TIMER_OFF); // timer inactif

Si on veut que le timer revienne à 0 chaque fois qu'il atteint la valeur 200 par exemple, il faut indiquer ce nombre entre parenthèses, mais dans ce cas on est OBLIGÉ (si,si) de spécifier d'abord si le timer doit être tout de suite activé ou non après sa création:

   Timer EncoreUnTimer(TIMER_ON,200); // timer actif avec 200 comme valeur max

Commandes

Pour qu'un chrono arrêté démarre, il faut appuyer sur le bouton START.
Pour qu'un timer inactif s'active, il faut donc appeler sa fonction start().

   Timer UnTimer(TIMER_OFF); // le timer est inactif, sa valeur reste sur 0
   ...
   UnTimer.start(); // activation du timer, sa valeur est maintenant incrémentée

La situation est identique pour les commandes STOP et RESET.

   unTimer.stop(); // arrêt
   unTimer.reset(); // réinitialisation, la valeur revient à 0
                    // (mais le timer ne s'arrête pas s'il était encore actif)

Lecture

Normalement, on lit la valeur d'un timer grâce à sa fonction time(). On devrait donc écrire

   int temps=UnTimer.time();
   ...
   if( UnTimer.time() > 50 ) UnTimer.stop();

mais comme c'est relativement encombrant, les principaux opérateurs (==, !=, >=, <=, > , <, !, +, -, *, /, %, >>, <<) ont été surchargés pour pouvoir manipuler DANS UN CALCUL le timer lui-même comme sa propre valeur. on peut donc écrire quelque chose comme

   Timer timer_affichage(TIMER_ON,40);
   int indice_sprite;

   while(1)
   {
       indice_sprite=timer_affichage/10;
       draw(20,10,indice_sprite);
   }

Dans cet exemple, quelle que soit la vitesse à laquelle la fonction draw() peut dessiner les sprites dont les indices sont les valeurs de indice_sprite (ici 0,1,2,3), le temps d'affichage des sprites sera toujours le même (et en particulier si les sprites n'ont pas la même taille, donc ne mettent pas le même temps pour être dessinés, leurs temps d'affichage resteront toujours identiques).

Attention toutefois que cette astuce n'est pas toujours disponible et la fonction time() est obligatoire quand aucun des opérateurs cités plus haut n'est utilisé pour lire la valeur. Exemple, pour afficher à l'écran la valeur d'un timer:

   printf("%d",UnTimer); // INCORRECT!!!
   printf("%d",UnTimer.time()); // correct.

Faites également attention au fait que ce n'est pas parce que la valeur d'un timer valait 15 quand vous l'avez lue (par exemple), qu'elle vaudra 16 la fois suivante (ça serait contre la nature des timers)... Donc tester si un timer est arrivé à une valeur précise est quelque chose d'extrêmement dangereux! Plutôt que de faire

   if(UnTimer==25) UnTimer.reset();

faites plutôt

   if(UnTimer>=25) UnTimer.reset();

Et comme ça il n'y a pas de problème si la valeur 25 a été "sautée".

Il peut être utile parfois de vérifier si un timer est actif ou s'il est à l'arrêt. la fonction isRunning() renvoie 1 si le timer est actif et 0 si sa valeur reste constante.

   if(UnTimer.isRunning()==0) // si le timer est à l'arrêt
   {
       UnTimer.reset(); // initialisation
       UnTimer.start(); // lancement
   }

Valeur maximale

La valeur maximale est la limite que le timer ne peut pas dépasser; elle sera toujours plus petite ou égale à 65535. Lorsque cette limite est atteinte, le timer repart à zéro sans s'arrêter.

Il est parfois nécessaire de modifier cette valeur au cours d'un prog, lorsqu'un même timer est utilisé différemment par exemple. On utilise pour ça la fonction set_max(), à laquelle il suffit de passer la nouvelle valeur maximale.

   Timer EncoreUnTimer; // limite par defaut à 65535
   ...
   EncoreUnTimer.set_max(500); // nouvelle limite à 500


Commentaires

Voilà pour ce qui est du fonctionnement et de l'utilisation de cette lib, j'espère que mes explications vous paraissent suffisamment claires... :)

Je rappelle quand même que "malheureusement" c'est réservé au C++... Il s'agit ici de POO assez classique et pas franchement compliquée, si vous débutez en POO il pourrait être intéressant de jeter un coup d'oeil sur les fonctions (la + grosse fait 5 lignes...) pour bien comprendre comment jongler avec les propriétés des objets etc. ;)

Je rappelle aussi que c'est uniquement utilisable sur une casio graph100, vu que l'interruption 0x1C n'est pas la même sur PC. Maintenant, si quelqu'un connait une interruption sur pc qui est aussi appelée au moins 50 fois par seconde, ça m'intéresse... :)

Pour toute remarque ou suggestion, pensez à m'envoyer un mail!

08/12/2003
Julien PATTE
orwell01@hotmail.com