MSX Village forum

La Place des Développeurs asmsx par un noob#2: Bouger un sprite... et ajout d'une boucle de tempo maison...

granced Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 09/10/2009 à 09h18

Messages: 1512

Le 19/10/2014 à 20h59

Reprise du message précédent

Volontiers (que ce soit Metalion ou z80), je suis toujours friand de ce genre d'info ! :)


MSX un jour, MSX toujours ! :D
Site web    
MSXosaure Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 03/10/2009 à 00h09

Messages: 781

Le 20/10/2014 à 09h36
granced :
Volontiers (que ce soit Metalion ou z80), je suis toujours friand de ce genre d'info ! :)


C'est un peu pour ça que j'ai lancé cette série de sujets. C'est pour que des membres calés en asm nius fasse partager leur savoir.



D'ailleurs, j'aurais plutôt du commencer lintitulé mes posts par: l'asmx par un noob:...:oups


Le MSXien le plus à l'ouest :fou ... ou presque :D
osaurer
   
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1503

Le 20/10/2014 à 11h42
L'idée m'est venue après avoir eu connaissance de la structure des jeux KONAMI. Tous leurs jeux (en tout cas, c'est ce qu'on dit) on la même structure : tout, absolument tout est géré par les interruptions. C'est très surprenant, mais c'est comme ça. Le jeu passe par une phase d'initialisation et puis arrive à une boucle fermée sans fin :

Code :
loop:   jr      loop

J'avoue ne pas avoir compris tout de suite, mais après réflexion, j'ai compris qu'en fait cela donnait un rythme régulier au programme : tous les 50e (ou 60e) de seconde (à chaque 'frame'), le programme est appelé à un point spécifique. Cela permet de gérer les temps et la chronologie de tous les événements. J'ai ensuite adapté cette technique à mes besoins.

Mise en place d'un compteur incrémenté à chaque interruption



C'est la technique déjà expliquée par MSXosaure : à chaque appel de l'interruption hardware VBLANK (générée par le VDP à chaque fin de frame), on incrémente un compteur, avec une valeur maximale qui dépend de la fréquence d'animation la plus basse. Dans l'exemple ci-dessous, cette valeur est 64. Cela veut dire que dans toutes les animations régulières du programme, celle qui est appelée la moins fréquemment est appelée toutes les 64 frames.

Code :
;-----------------------------------------------------------
; Interruption sur VBLANK
;-----------------------------------------------------------
VBLANK:
; Incrémentation du compteur VBLANK
        ld       a,[timer]
        inc      a
        cp       64
        jr       nz,CYCLE
        xor      a
CYCLE:  ld       [timer],a
; Exécution du hook original HTIMI et fin de gestion des interruptions
        jp       VBLANK_OLD


Routine d'attente du VBLANK


On écrit ensuite une routine qui va attendre l'incrémentation du compteur (et donc le déclenchement de l'interruption).

Code :
;-----------------------------------------------------------
; Attente VBLANK
;-----------------------------------------------------------
WAIT_VBLANK:
        ld      hl,timer
        ld      a,[timer]
@@loop: cp      [hl]
        jr      z,@@loop
        ret


Boucle d'attente principale



Dans le programme, après les phases d'initiallisation, on va arriver à une boucle d'attente qui va permettre de gérer l'attente du jouer et les animations régulières temporisées, en utilisant cette routine d'attente du VBLANK pour déclencher le coup de 'métronome'.

Code :
;===========================================================
; Boucle principale
;===========================================================
WAIT_PLAYER:
;-----------------------------------------------------------
; Synchro VBLANK
;-----------------------------------------------------------
        call    WAIT_VBLANK
;-----------------------------------------------------------
; Animation
;-----------------------------------------------------------
; toutes les frames
        call    EVERY_FRAME
; toutes les 2 frames
        ld      a,[timer]
        and     1
        call    z,EVERY_2_FRAMES
; toutes les 4 frames
        ld      a,[timer]
        and     3
        call    z,EVERY_4_FRAMES

;-----------------------------------------------------------
; Attente joueur
;-----------------------------------------------------------
; Boucle joystick
    ; flèches curseur
        xor     a
        call    GTSTCK
        and     a
        call    z,MOVE
    ; joystick
        ld      a,1
        call    GTSTCK
        and     a
        call    z,MOVE
    ; barre espace
        xor     a
        call    GTTRIG
        call    m,FIRE
    ; bouton joystick
        ld      a,1
        call    GTTRIG
        call    m,FIRE
    ; idle
        jp      WAIT_PLAYER


De cette façon, le programme va rythmer les animations, que l'on pourra régler exactement par pas de 50e (ou 60e) de seconde, tout en attendant le joueur (les animations ayant priorité dans l'exemple ci-dessus).

La seule contrainte est qu'il faut bien connaître le temps d’exécution total des routines d'animation et de mouvement du joueur. Car il faudra régler le 'métronome' en fonction de ce temps total. Si il ne dépasse pas le temps libre d'une frame (environ 50.000 T - ça a l'air beaucoup mais ça va très très vite !), on peut laisser un appel à WAIT_VBLANK par cycle. Sinon, il faudra gérer avec un ou plusieurs WAIT_VBLANK supplémentaires, mais en contrepartie on ne pourra plus gérer une animation faite à chaque frame, puisque l'on descendra la fréquence de test du 'timer'. Edité par Metalion Le 20/10/2014 à 12h11


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
MSXosaure Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 03/10/2009 à 00h09

Messages: 781

Le 20/10/2014 à 12h05
J'ai tout pigé ou presque, je crois que je vais faire + simple pour l'histoire des appels toutes les n frame pour mon exemple en cours. C'est pas que c'est si compliqué mais on pourra y revenir plus tard.

Par contre pour le WAIT_VBLANK: on donne à hl la valeur timer, puis dans a la valeur contenu à l'adresse timer que l'on compare avec la valeur contenu à l'adresse hl c'est à dire timer ???

Sinon dans ta boucle principale and 3 par exemple est utilisé comme cp 3 mais est plus économe ou préserve a, c'est ça?


Le MSXien le plus à l'ouest :fou ... ou presque :D
osaurer
   
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1503

Le 20/10/2014 à 12h23
MSXosaure :
Par contre pour le WAIT_VBLANK: on donne à hl la valeur timer, puis dans a la valeur contenu à l'adresse timer que l'on compare avec la valeur contenu à l'adresse hl c'est à dire timer ???


Oui, c'est ça ^^



On charge dans 'a' la valeur contenue dans 'timer' et puis on boucle en attendant qu'elle ait changé (d'où le 'cp (hl)'), puisqu'elle est incrémentée en arrière plan à chaque interruption par la routine VBLANK.



MSXosaure :
Sinon dans ta boucle principale and 3 par exemple est utilisé comme cp 3 mais est plus économe ou préserve a, c'est ça?


Non, c'est parce que c'est plus rapide. 'and 3' permet de savoir tout de suite si le compteur 'timer' est un multiple de 4 frames. L'instruction 'and 3' va donner zéro comme résultat pour chaque valeur de 'timer' multiple de 4. Par contre elle détruit la valeur de 'a', d'où la nécessité de recharger la valeur avant chaque test.


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
MSXosaure Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 03/10/2009 à 00h09

Messages: 781

Le 20/10/2014 à 12h49
Metalion :
MSXosaure :
Par contre pour le WAIT_VBLANK: on donne à hl la valeur timer, puis dans a la valeur contenu à l'adresse timer que l'on compare avec la valeur contenu à l'adresse hl c'est à dire timer ???


Oui, c'est ça ^^



On charge dans 'a' la valeur contenue dans 'timer' et puis on boucle en attendant qu'elle ait changé (d'où le 'cp (hl)'), puisqu'elle est incrémentée en arrière plan à chaque interruption par la routine VBLANK.





J'ai du mal à comprendre vu qu'au lancement de la boucle on compare la valeur contenu dans "timer" avec elle même:hum :hum :hum


Le MSXien le plus à l'ouest :fou ... ou presque :D
osaurer
   
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1503

Le 20/10/2014 à 13h42
MSXosaure :
J'ai du mal à comprendre vu qu'au lancement de la boucle on compare la valeur contenu dans "timer" avec elle même:hum :hum :hum




Non, tu la compares la valeur de 'a' avec la valeur contenue dans 'timer'. C'est une différence subtile mais très importante. La valeur de 'a' ne changera pas, mais la valeur contenue dans 'timer' va changer lorsque la routine VBLANK aura été appelée.



Imaginons que tu appelles la routine WAIT_VBLANK et que 'timer' contient la valeur 24.



Code :
WAIT_VBLANK:
        ld      hl,timer
        ld      a,[timer]




A ce stade là, on charge simplement la valeur 24 dans 'a'.



Code :
@@loop: cp      [hl]
        jr      z,@@loop




Maintenant on compare 'a' (donc 24) avec la valeur contenue dans 'timer'. Au début les deux valeurs sont identiques, et donc on boucle par 'jr z' sur l'instruction de comparaison. Pendant ce temps là, le VDP rafraîchit l'écran, les sprites, ... Bref il fait son boulot. Puis il arrive au dernier pixel affiché en (255,191). Là, il déclenche un signal sur le bus d'interruption du Z80. Le processeur s'arrête, exécute sa routine de gestion des interruptions, y compris celle qu'on a créée : la routine VBLANK. Cette dernière incrémente la valeur dans 'timer', qui passe donc à 25.



Au retour de l'interruption, le processeur reprend où il avait arrêté, c'est à dire dans la boucle de comparaison 'cp (hl) / jr z'. Il compare toujours la valeur de 'a', qui est toujours 24, avec la valeur contenue dans 'timer'. Mais cette fois ci, la valeur contenue dans 'timer' a été modifiée et vaut désormais 25.



Cela lui permet de sortir de la boucle et de revenir au point d'appel, et on aura donc attendu la fin d'une frame pour rendre la main, ce qui était le but attendu. Edité par Metalion Le 20/10/2014 à 13h59


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
z80 Membre non connecté

Villageois

Rang

Avatar

Inscrit le : 17/05/2013 à 22h52

Messages: 987

Le 20/10/2014 à 14h59
[EDIT] Je réponds un peut après Metalion et mon poste peut semblé hors de propos du coup. La méthode que je propose est semblable à la méthode "Konami" dans le sens ou je fais les appel au routines à chaque VBL

  • Gestion Héro
  • Gestion map
  • Gestion ennemis
  • Appel MusicPlayer & SFX

[fin du EDIT]

OK
Le concept est simple, il est préférable de prendre du recul et savoir ou on veut aller.
quelques règles:
  • Il faut résonner avec la position du héro (et des ennemis aussi) sur le plan de jeu (la carte, la map, appelez ça comme vous voulez).
  • Il faut que le héros puisse aller plus ou moins vite pour se déplacer


Pour que le héro sa déplace plus ou moins vite sur le plan on va lui attribuer un paramètre de vitesse.
exemple:
Position_x = Position_x + vitesse
Position_y = Position_y + vitesse

La gestion de la vitesse du héro (des ennemis), il faut pouvoir aller doucement et vite (accélérer et ralentir). Disons qu'on décide de pouvoir se déplacer avec une vitesse de 1/8eme de pixel par VBL (50Hz ou 60Hz), soit 1 pixel toutes les 8 VBL.
Si nous partons sur 1/8eme de pixel de résolution (3 bits), des coordonnées 16 bits pour se localiser sur le plan, des écrans de 256 pixels de coté.
Nous obtenons:
nombre de bits total - nombre de bits après la virgule -> 16 - 3 = 13 bits d'entier pour la position sur le plan
nombre d'écran = nombre de bit de position - nombre de bits pour pour la taille d'un écran -> 5bits = 13bits - 8bits = 32 écrans de 256 pixels de large (et/ou de haut ;) )

Petite représentation de nos 16bits de coordonnées pour les objets (héros, ennemis etc..)
Position_x -> AAAAAXXXXXXXX,xxx
Position_y -> BBBBBYYYYYYYY,yyy

AAAAA -> position x dans le plan
XXXXXXXX -> position x à l'écran
xxx -> nombre de 8eme de pixel
BBBBB -> position x dans le plan
YYYYYYYY -> position x à l'écran
yyy -> nombre de 8eme de pixel

Dans un premier temps on va se limiter à faire bouger l'objet dans un écran, on va oublier AAAAA et BBBBB

C'est bien beau tout ça! Mais comment le personnage se déplace à l'écran?
Simple! :)
On va dire dans un premier temps que notre objet (héro, ennemis) accélère/ralenti de façon linéaire, à une vitesse de 2/8eme de pixel par VBL -> Hero_Acc = 00002h.
On va dire que la vitesse sera limitée pour ne pas allé trop vite -> Hero_SpdLim = 010h (en 1/8eme de pixel par VBL, soit 16/8 = 2 pixel/VBL maximum).
Que notre vitesse initiale est nulle vu qu'on ne touche pas au touche de direction -> Hero_Spd = 0000h.
Que sa position est en x=128 (080h), y=128 (080h), soit transposé dans notre notation à 3 bits après virgules -> 0400h en x et y, Hero_x = 0400h et Hero_y = 0400h
Il nous faut aussi connaitre l'état de l'objet, il est arrêté, il va à droite, il va à gauche, etc... On a une variable d'état Hero_Stat = 0 (0 = arrêt, 1 marche vers droite, 2 marche vers gauche, etc..

On appel la routine de lecture du Joystick.
Si appui sur la touche droite:
  • Hero_Stat = 1
  • Hero_Spd = Hero_Spd + Hero_Acc
  • If Hero_Spd > Hero_SpdLim Then Hero_Spd => Hero_SpdLim
  • Hero_x = Hero_x + Hero_Spd
  • If Hero_x > 07F8h Then Hero_x = 07F8h
  • If Hero_x < 0007h Then Hero_x = 0007h
  • AfficheSpriteHero (Hero_x,Hero_y)

Je vois la question surgir dans vos esprits: "Mais comment on affiche un sprite avec des coordonées à virgules fixes?"

Simple, voila comment:
Code ASM :
 
ldhl,[Hero_x];on récupère la position x du Hero (AAAAAXXXXXXXX,xxx)
lda,07h;on masque les 5 bits supérieurs pour s'assurer que AAAAA = 0
andh;on lui soustrait 50
ldh,a;maintenant HL = 00000XXXXXXXX,xxx. Reste à suprimer ",xxx" pour obtenir la valeur entière de Hero_x 
; pour ça ondivise par 8 ce qui ce fait facilement par un décalage de 3 bits vers la droite de HL
srlh; décalage de H de 1 bit vers la droite le bit 0 de H va dans le CARRY (C) et on rempli le bit 7 avec 0
rrl; décalage de H de 1 bit vers la droite et le CARRY va dans le bit 7 donc on fini avec le bit 0 de H qui se retrouve dans le bit 7 de L
; à cette instant HL = 000000XXXXXXXX,xx
srlh; décalage de H de 1 bit vers la droite le bit 0 de H va dans le CARRY (C) et on rempli le bit 7 avec 0
rrl; décalage de H de 1 bit vers la droite et le CARRY va dans le bit 7 donc on fini avec le bit 0 de H qui se retrouve dans le bit 7 de L
; à cette instant HL = 0000000XXXXXXXX,x
srlh; décalage de H de 1 bit vers la droite le bit 0 de H va dans le CARRY (C) et on rempli le bit 7 avec 0
rrl; décalage de H de 1 bit vers la droite et le CARRY va dans le bit 7 donc on fini avec le bit 0 de H qui se retrouve dans le bit 7 de L
; à cette instant HL = 00000000XXXXXXXX
lda,l; A = XXXXXXXX
ld [VAR_SPRITES+(0*4)+1],a; X 1er sprite heros (plan0)
ld [VAR_SPRITES+(1*4)+1],a  ; X 2nd sprite heros(plan1)
 


Voilà, je m'attends à ce que ce ne soit pas limpide pour tout le monde, mais je suis disposé à vous apporter les éclaircissements nécessaires.
Je suis contiens que je ne vous ai pas fourni un soft complet, mais c'est un peut compliqué en ce moment pour moi de faire du MSX. Pas super le temps de mettre devant l'écran. Avec un peu plus de temps je pourrais vous expliquer pourquoi j'ai introduit une notion d'état pour l'objet, pourquoi je ne fait pas évoluer directement les coordonnées de la table des sprites .
Pourquoi il est plus judicieux de traiter le héro et tous les ennemies comme des objets (identiques). En effet si on prend du recule on se rend vite compte qu'un héros et un ennemis ne se distinguent que par celui qui les dirige.
Bonne lecture à tous. Edité par z80 Le 20/10/2014 à 15h08


TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours) :top
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,... :\'(
   
granced Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 09/10/2009 à 09h18

Messages: 1512

Le 20/10/2014 à 15h17
Je vais sans doute digresser, mais cette routine de "temporisation" ou de métronomie me rappelle furieusement ce que j'envisageais de faire au niveau musique (approvisionner les registres du PSG tous les N*50Hz en fonction du tempo de ma mélodie.

EDIT : le dernier edit de z80 a l'air de confirmer ^^


MSX un jour, MSX toujours ! :D
Site web    
z80 Membre non connecté

Villageois

Rang

Avatar

Inscrit le : 17/05/2013 à 22h52

Messages: 987

Le 20/10/2014 à 15h38
granced :
Je vais sans doute digresser, mais cette routine de "temporisation" ou de métronomie me rappelle furieusement ce que j'envisageais de faire au niveau musique (approvisionner les registres du PSG tous les N*50Hz en fonction du tempo de ma mélodie.



EDIT : le dernier edit de z80 a l'air de confirmer ^^




C'est ce que fait un sound traker :)

C'est simple les sound traker (musicalement s'entend) mais c'est aussi cette simplicité qui fait leur faiblesse. Pour faire simple, ils ne jouent qu'un type de note, des croches je crois de mémoire...

A la différence des musiques faites avec SME3, Musica etc... qui sont en MML (petite subtilité, je crois me souvenir que SME3 gère les deux modes: MML et sound traker, à vérifier avec nos amis musiciens :) )


TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours) :top
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,... :\'(
   
granced Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 09/10/2009 à 09h18

Messages: 1512

Le 20/10/2014 à 15h49
Pas forcément une faiblesse, si on prend comme division de travail la plus petite en durée ! Comme les notes sont des multiples les unes des autres il est assez facile d'obtenir les durées standard je pense :hum


MSX un jour, MSX toujours ! :D
Site web    
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1503

Le 20/10/2014 à 19h33
z80 :
La méthode que je propose est semblable à la méthode "Konami" dans le sens ou je fais les appel au routines à chaque VBL


Effectivement, ce sont deux méthodes très similaires : dans l'une on incrémente à chaque frame une partie du déplacement du sprite, et dans l'autre on attends un certain nombre de frames pour incrémenter une unité complète.



PS : C'est marrant parce que les nombres à virgule fixe codés sur 16 bits en base binaire, j'y avais déjà pensé dans le cadre d'un moteur 3D filaire. J'avais déjà codé toute une routine pour récupérer la valeur de SIN(X) en utilisant ce codage ... :fou


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
z80 Membre non connecté

Villageois

Rang

Avatar

Inscrit le : 17/05/2013 à 22h52

Messages: 987

Le 20/10/2014 à 21h03
granced :
Pas forcément une faiblesse, si on prend comme division de travail la plus petite en durée ! Comme les notes sont des multiples les unes des autres il est assez facile d'obtenir les durées standard je pense :hum


Oui mais cela t'oblige à avoir un DEcompteur de VBL pour chacune des voies, tu charges le DEcompteur avec le nombre de VBL qui va bien pour la note et le tempo que tu veux (disons une noire à T150) quand ton DEcompteur atteind zéro alors tu passe à la note suivante dans la voie considérée. Etc.

Sur un sound traker les voies ont toutes le même tempo et une seul action possible à chaque step, en MML tu peut en une action changer le volume le tempo etc. Edité par z80 Le 20/10/2014 à 21h05


TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours) :top
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,... :\'(
   
MSXosaure Membre non connecté

Maire-adjoint

Rang

Avatar

Association

Inscrit le : 03/10/2009 à 00h09

Messages: 781

Le 20/10/2014 à 21h42
Merci à Metalion et Z80 pour leurs interventions.

J'ai intégré le système de Metalion dans mon programme, ça marche bien sûr on va le garder pour la suite.

Pour ce qu'à posté Z80 des déplacements avec accélération c'est du meilleur effet et ta solution (partielle) semble très intéressante mais je crains de ne pas en être encore là...

Pour l'instant je réussis à contrôler un sprite à l'écran en l'empêchant d'en sortir, c'est déjà un bon début pour moi! :oups

La prochaine étape sera l'orientation et l'animation du sprite (que j'ai déjà intégrée) au programme. J'avoue faire au feeling selon ma logique sans trop regarder ce qui se fait ailleurs (en dehors des exemples proposés par asmsx) alors n'hésitez pas à me fouetter corriger sur le prochain post, ça me fera plaisir. :D


Le MSXien le plus à l'ouest :fou ... ou presque :D
osaurer
   
ericb59 Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : compte ++ Groupe : Shoutbox

Inscrit le : 17/04/2012 à 10h25

Messages: 5566

Le 22/12/2018 à 12h29
Yo !

Vous allez me dire que c'est hors sujet dans un topic dédié assembleur, mais c'est pour illustrer, et c'est en lien avec l'autre topic assembleur plus récent...

J'ai implémenté la technique de Metallion en C (Fusion-c) avec un exemple concret.

Le programme incrémente 3 compteurs à différents intervalles, le tout synchronisé par le Vblank



Le programme en .com
testVblank.zip

Le listing:
Code C :
 
#include <stdio.h>
#include "fusion-c/header/msx_fusion.h"
int cpt_test1;
int cpt_test2;
int cpt_test3;
// Affihage des 3 compteurs à l'écran
//
void FT_Print(void)
{
  Locate(7,4);
  printf("%d",cpt_test1);
  Locate(7,6);
  printf("%d",cpt_test2);
  Locate(7,8);
  printf("%d",cpt_test3);
  return;
}
// Routine de tests 
//
void FT_DoSomething(int compteur)
{
  int trigger;
  trigger=1;
    // Every Frame
    cpt_test1++;
    // Every 2 frames
    trigger=compteur & 1;
    if (trigger == 0)
    {
      cpt_test2++;
    }
    // Every 4 frames
    trigger=compteur & 3;
    if (trigger == 0)
    {
      cpt_test3++;
    }
    FT_Print();   // On appel la routine d'affichage
    return;
}
void main (void)
{
  int cpt;
  cpt=0;
  cpt_test1=0;
  cpt_test2=0;
  cpt_test3=0;
  // On prépare l'écran
  Screen(0);
  Locate(1,4);
  printf("CPT1:");
  Locate(1,6);
  printf("CPT2:");
  Locate(1,8);
  printf("CPT3:");
  // Boucle infinie
  while (1)
  {
    if (IsVsync())  // Test Vsync / Vlank
    {
 
      cpt++;
      if (cpt>=100)
      {
        cpt=0;
      }
      FT_DoSomething(cpt);
    }
 
  }
}
 
Edité par ericb59 Le 22/12/2018 à 12h39


banniere-ericb59e
Site web    
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie