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] Maitrisez le temps en C/C++ !
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

[Tutoriel] Maitrisez le temps en C/C++ !

Posté le 27/02/2014 21:59

Un des meilleurs atouts que possède la programmation d'addins en C/C++, c'est de bénéficier du système Real Time Clock (RTC), et surtout du syscall RTC_getTicks(). Dans ce tutoriel, nous verrons en détail les différentes façon d'utiliser RTC_getTicks(), comme régulateur de FPS, compte à rebours, etc.

Sommaire
1. Rappels sur les sycalls
2. Appeler RTC_getTicks()
3. Réguler ses FPS
4. Afficher les FPS
5. Chronométrer du temps
6. Régulariser des opérations avec les timers (n'utilise pas RTC_getTicks)
7. Générer des nombres aléatoires
Conclusion


1. Rappels sur les syscalls

RTC_getTicks() est un syscall ("System Call" ou "Appel système"), c'est à dire une fonction déjà présente dans l'OS de la calculatrice. Il suffit donc de sauter à l'endroit où elle est stockée pour l'exécuter.

Pour cela, la meilleure méthode est de créer un fichier contenant les instructions en assembleur (ASM), puis de compiler le tout. Toutefois, cette méthode est lourde, et pas forcément très compréhensible par un programmeur lambda, d'autant plus que l'assembleur est un langage de bas niveau, c'est à dire très abstrait. Nous utiliserons donc une astuce plus ou moins correcte et valide, mais qui reste intégralement fonctionnelle.

Voici le code commenté pour appeler un syscall (ici RTC_getTicks()) :

// Code d'une fonction *globale* pour appeler un syscall
static int SysCallCode[] = { 0xD201422B, 0x60F20000, 0x80010070 };
// Nom et paramètres de la fonction
static int (*SysCall)(int R4, int R5, int R6, int R7, int FNo ) = (void *)&SysCallCode;
// (Ces deux lignes ne sont à placer dans votre code qu'une seule fois)

int RTC_getTicks(void)
{
    // On donne le numéro du syscall (0x3b) et on transmet les arguments
    // (ici il n'y en a pas donc on met des 0, ça n'a aucune importance)
    return (*SysCall)(0, 0, 0, 0, 0x3b);
}

// On peut répéter l'opération avec d'autres syscalls
// (ceci est un exemple sûrement non fonctionnel) :
int SYS_call(int x, int y)
{
    return (*SysCall)(x, y, 0, 0, 0x42);
}

Vous pouvez placer ces fonctions n'importe où tant que vous avez mis un prototype avant le main().


2. Appeler RTC_getTicks()

Maintenant que nous avons défini RTC_getTicks(), nous allons l'utiliser. La fonction retourne le nombre de "ticks", des périodes durant 1/128ème de seconde, mesurées par l'horloge interne de la calculatrice depuis sa mise en service (ou une autre date, Casio n'ayant jamais fourni de renseignements sur ce point).

Pour cela, prévoyez un int pour récupérer la valeur :

int ticks = 0;
ticks = RTC_getTicks();



3. Réguler ses FPS

Les Frames Per Second (FPS), en français "images par seconde", sont un élément important d'un jeu. En effet, si ceux-ci ne sont pas régulés, il peut et y aura des différences d'exécution entre différents modèles, particulièrement entre les SH3 et les SH4. De plus, certaines fonctions comme IsKeyDown() provoquent des ralentissements lorsque des touches sont enfoncées, et peuvent fortement modifier la vitesse d'exécution du jeu, le rendant moins agréable à utiliser.

Heureusement, nous avons à notre disposition en C/C++ la fonction RTC_getTicks(). Grace à celle-ci, nous allons réguler de manière dynamique le nombre de FPS de notre jeu.

Nous allons donc créer une fonction qui retiendra le nombre de ticks écoulés depuis le dernier appel de la fonction. Du coup, si le programme est en avance, nous le mettons en pause jusqu'à ce qu'il soit à l'heure. Nous définissons donc un nombre précis de ticks qu'il faudra laisser écouler par frame.

Sachant que 1 tick = 1/128 seconde, nous pouvons en déduire que laisser 1 tick s'écouler équivaut à 128 / 1 = 128 FPS, 2 ticks = 128 / 2 = 64 FPS, 3 ticks = 128 / 3 = 42 FPS, etc. Nous donnerons donc en argument à la fonction le nombre de ticks à laisser tourner. Voici un récapitulatif des valeurs les plus utilisées :

Cliquez pour découvrir
Cliquez pour recouvrir
1 = 128 FPS
2 = 64 FPS
3 = 42 FPS
4 = 32 FPS
5 = 25 FPS
6 = 21 FPS
7 = 18 FPS
...
128 / x = y FPS


Voici la fonction complète :

void setFps(int fpsWish)
{
    // "static" permet de garder les valeurs en mémoire entre les différents appels
    static unsigned int fps = 0, fps_count = 0;

    do
    {
        fps = RTC_getTicks(); // on enregistre les "ticks"
        Sleep(1); // permet d'économiser de la batterie
    }
    while(fps < fps_count+fpsWish); // tant que ceux-ci ne se sont pas suffisamment écoulés

    fps_count = RTC_getTicks(); // on met à jour les dernières valeurs
}

Pour l'utiliser, rien de plus simple :

while(1) // boucle principale
{
    ... // instructions
    
    setFps(5); // pour réguler à 25 FPS
}



4. Afficher les FPS

Réguler les FPS, c'est cool, mais dans le cas d'un jeu qui demande beaucoup de ressources, il est intéressant de connaitre le nombre maximal de FPS que l'on peut avoir. Pour cela, nous allons une fois de plus utiliser RTC_getTicks(). La fonction que nous allons créer retournera un int, le nombre de FPS de la dernière seconde écoulée.

int getFps()
{
    // variables utilisées (en static, pour pouvoir garder en mémoire les valeurs)
    static int disp_fps=0, fps=1, time=0;

    if(RTC_getTicks() - time > 128) // si il s'est écoulé une seconde complète
    {
        disp_fps = fps; // alors on récupère le nombre de FPS
        fps = 0; // on remet à 0 le compteur
        time = RTC_getTicks(); // et on se rappelle du nombre de ticks de la dernière seconde écoulée
    }

    fps++; // on monte la valeur des FPS

    return disp_fps;
}

Vous n'avez plus qu'à appeler la fonction dans votre boucle principale pour récupérer le nombre de FPS :

int fps = 0;

while(1)// boucle principale
{
    ... // instructions

    fps = getFps();
    PrintVariable(fps);
}


NB 1 : La fonction PrintVariable(int variable) est supposée afficher une variable à l'écran. Vous devez adapter en fonction de vos besoins.
NB 2 : Vous trouverez dans les commentaires de ce tutoriel une autre méthode, tout aussi valable. A vous de choisir


5. Chronométrer du temps

Dans le cas d'un jeu qui a besoin de savoir combien de temps s'est écoulé depuis une action, vous pouvez enregistrer un temps de référence, puis calculer le temps écoulé en ticks en faisant une simple soustraction, puis convertir le résultat en secondes, minutes et autres unités de temps.

Par exemple, pour indiquer le temps écoulé depuis le lancement de la boucle :

... // instructions

temps_reference = RTC_getTicks(); // on enregistre le temps de référence

while(1)
{
    ... // instructions
    
    temps_actuel = RTC_getTicks(); // on récupère le temps actuel
    temps_ecoule = (int)((temps_actuel - temps_reference) / 128); // le cast (int) permet d'avoir un code plus propre et d'éviter des (W) lors de la compilation
    
    PrintVariable(temps_ecoule); // on affiche le temps en secondes

    ... // instructions
}



6. Régulariser des opérations avec les timers (sans RTC_getTicks())

En construction...
Vous pouvez déjà aller voir la documentation française de fxlib.
Je pense créer un tutoriel entier sur les timers, puisque nombreuses sont les astuces et utilisations que l'on peut en faire.



7. Générer des nombres aléatoires

Un tutoriel à déjà été écrit sur ce sujet, vous trouverez ici des explicitons sur l'utilisation de RTC_getTicks() dans la création de nombres aléatoires.


Conclusion

Avec ces quelques explications, vous devriez pouvoir maîtriser le temps sur votre calculatrice, même si, bien entendu, ces quelques exemples ne sont pas représentatifs de toutes les possibilités offertes par le système RTC. Vous pouvez par exemple créer un jeu qui lance des quêtes qu'à des horaires réguliers, des succès à débloquer si on a joué plus de 1 heure, etc.

Si toutefois vous avez encore des questions, n'hésitez pas à les poser-ci dessous, dans ce topic dédié.


A bientôt sur Planète Casio !


1, 2, 3, 4 Suivante
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 27/02/2014 22:04 | #


Pfiou, et un tuto de plus !

Faut que je pense à finir le sujet des 48h CPC maintenant
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Eltoredo Hors ligne Modérateur Points: 4301 Défis: 35 Message

Citer : Posté le 27/02/2014 22:16 | #


Super tuto, faudrait qu'un jour le basic en soit capable aussi ...
La procrastination est une vertu. (voir ma description pour comprendre mon raisonnement)
Alphacreator Hors ligne Membre Points: 1464 Défis: 43 Message

Citer : Posté le 28/02/2014 09:26 | #


Cool, merci pour ce tuto DS, ça va bien m'aider pour mon jeu en C.

J'ai hâte de connaître le sujet des CPC mais je ne pourrai pas y participer car j'ai pas mon ordi avant dimanche :oups: bah, c'est pas grave, je me suis bien amusé la dernière fois.
Lancelot Hors ligne Membre Points: 1274 Défis: 160 Message

Citer : Posté le 28/02/2014 11:33 | #


Super tutoriel

Bravo !
Calculatrices : Casio 35+ SH4 (modifiée 75) et fx-CG 20 PRIZM
Projets que je soutiens
Des exemples parmi tant d'autres
Pokémon Jade de Dododormeur
Zelda de Smashmaster
Super Geek Brothers de Siapran
Mes Programmes
Mes Programmes
Mes Projets
Mes Projets
ColorLib
Add-ins Jetpack Joyride et Pac-Man sur PRIZM (les 2 non commencés mais en réflexion)
A la recherche des sprites jetpack Joride si quelqu'un les a en couleur
Btl Hors ligne Ancien modérateur Points: 3879 Défis: 107 Message

Citer : Posté le 28/02/2014 16:42 | #


Bravo !
je n'ai pas tout lu par manque de temps mais, Le tuto à l'air très clair et lisible, de plus il est très utile.
C'est une très belle initiative et une très bonne chose pour tout ceux qui commence le C.
Un excellent tuto video qui vous explique comment transférer des fichiers de l'ordinateur vers la calculatrice et vice versa ma chaine youtube
mes jeux
mes jeux

Jouez à 6 sur une seule calto : Curve Fever
Un die and retry qui vous fera bieeeen rager Test Andropov
un très bon sokoban
le seul vrai jeu de foot en basic : FIFA 12
Ca c'est ce que j'appelle un jeu de reflexion jewel master
Qui vaincra l'intelligence artificielle de cet othello
Le célèbre pacman
Et tant d'autres BTL's games

Le jeu du mois de Novembre et award du jeu le plus dur de l'année 2013 MultiTask, testez-le
Positon Hors ligne Rédacteur Points: 2396 Défis: 57 Message

Citer : Posté le 28/02/2014 17:15 | #


Il y'a une erreur d'étourderie :
3 ticks=128/3=42 FPS
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 28/02/2014 17:16 | #


La calculatrice arrondit automatiquement les flottants
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 28/02/2014 17:20 | #


Non, elle les tronque
Mais au final, ça ne change pas grand chose
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 28/02/2014 17:22 | #


En effet, petite erreur de vocabulaire de ma part
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 28/02/2014 20:12 | #


Bon tutoriel, merci
Louloux Hors ligne Ancien administrateur Points: 7035 Défis: 61 Message

Citer : Posté le 28/02/2014 21:14 | #


Sympathique et fort utile !

Pourrais-tu juste ajouter un paragraphe sur les timers de fxlib ? Ça peut également être utile.
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 28/02/2014 21:15 | #


Exact
je fais ça dès que j'ai le temps.
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lancelot Hors ligne Membre Points: 1274 Défis: 160 Message

Citer : Posté le 05/03/2014 18:31 | #


Quelqu'un peut me montrer le bout de code pour compter les FPS.

EDIT 900 points !
Calculatrices : Casio 35+ SH4 (modifiée 75) et fx-CG 20 PRIZM
Projets que je soutiens
Des exemples parmi tant d'autres
Pokémon Jade de Dododormeur
Zelda de Smashmaster
Super Geek Brothers de Siapran
Mes Programmes
Mes Programmes
Mes Projets
Mes Projets
ColorLib
Add-ins Jetpack Joyride et Pac-Man sur PRIZM (les 2 non commencés mais en réflexion)
A la recherche des sprites jetpack Joride si quelqu'un les a en couleur
Nemhardy Hors ligne Grand maître des Traits d'Esprit Points: 1242 Défis: 54 Message

Citer : Posté le 05/03/2014 18:34 | #


int disp_fps=[maroon]0[/maroon], fps=[maroon]0[/maroon], time=[maroon]0[/maroon];
[purple]char[/purple] str_fps[8]=[gray]"FPS "[/gray];

[b][blue]if[/blue][/b](time_getTicks() - time > 128) {
    disp_fps = fps;
    itoa(disp_fps, str_fps+4);
    fps = [maroon]1[/maroon];
    time = time_getTicks();
} [b][blue]else[/blue][/b] fps++;


time_getTicks(); à remplacer par votre fonction qui "donne l'heure tickienne"

From Gravity Duck

Y'a qu'à afficher str_fps, ou juste récupérer la valeur de disp_fps
Lancelot Hors ligne Membre Points: 1274 Défis: 160 Message

Citer : Posté le 05/03/2014 18:44 | #


Merci
Calculatrices : Casio 35+ SH4 (modifiée 75) et fx-CG 20 PRIZM
Projets que je soutiens
Des exemples parmi tant d'autres
Pokémon Jade de Dododormeur
Zelda de Smashmaster
Super Geek Brothers de Siapran
Mes Programmes
Mes Programmes
Mes Projets
Mes Projets
ColorLib
Add-ins Jetpack Joyride et Pac-Man sur PRIZM (les 2 non commencés mais en réflexion)
A la recherche des sprites jetpack Joride si quelqu'un les a en couleur
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 08/03/2014 12:54 | #


Je rajoute cette astuce dans le tuto

Ajouté le 08/03/2014 à 13:20 :
J'ai légèrement modifié le code ci-dessus, en rappelant toutefois que c'est une méthode valide. (Je n'ai pas voulu expliquer le fonctionnement de atoi() et des strings, juste pour récupérer une valeur entière)
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Pierrotll Hors ligne Ancien administrateur Points: 5488 Défis: 41 Message

Citer : Posté le 08/03/2014 14:23 | #


Dans setFps, il serait peut-être plus judicieux d'utiliser Sleep plutôt qu'une boucle histoire d'économiser les piles de la machine.
Gollum Hors ligne Membre Points: 1262 Défis: 2 Message

Citer : Posté le 12/03/2014 17:42 | #


hey, vive le feed reader.
Je n'avais pas vu ce tuto, bravo
https://telegram.me/BrokenClock
Je suis de l'autre coté de la manche maintenant. Yay.
Dark storm Hors ligne Labélisateur Points: 11631 Défis: 176 Message

Citer : Posté le 18/04/2014 19:09 | #


J'ai ajouté un sommaire
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Drakalex007 Hors ligne Membre Points: 687 Défis: 0 Message

Citer : Posté le 02/06/2014 19:32 | #


J'ai un petit pb, après avoir ajouté le premier code avec les syscalls, j'ai cette erreur :

(E) A value of type "void *" cannot be used to initialize an entity of type "int (*)(int, int, int, int, int)"

Peut être que c'est parce que je suis en c++ ?
1, 2, 3, 4 Suivante

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 81 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