En mode SCREEN 2 pour PONG, vous pouvez vous inspirer de l'exemple pour PUT (graphique) donné dans l'aide de QuickBASIC 4.5. Il s'agit d'afficher une image plus grosse que l'objet à représenter afin de recouvrir le dessin précédent. Cela évite d'effacer, rend l'animation rapide, sans clignotement et l'image est presque stable. Cependant, il faut utiliser un timer pour cadencer l'animation sinon la vitesse sera proportionnelle à celle du processeur.
Si vous voulez allez plus loin, je peux vous présenter une méthode d'animation sans contrainte de palette mais plus gourmande en mémoire.
Une animation consiste à afficher une image un certain laps de temps puis à l'effacer avant de l'afficher ailleurs mais à proximité, ce qui crée l'illusion du mouvement. L'organisation de la mémoire vidéo fait qu'on manipule le rectangle capable de l'image à l'écran. Les pixels non significatifs ont alors une valeur nulle.
C'est pourquoi l'affichage d'une image avec XOU impose un fond uni, c'est-à-dire, constitué de pixels nuls aussi. Cependant, une carte EGA dispose de 16 registres de couleur programmables, celui numéroté 0 déterminant la couleur de fond. Pour pouvoir ajouter des pixels blancs (étoiles), on attribue la couleur blanche au registre 1 et on regroupe les 14 registres de couleur suivants deux à deux ; il n'y a plus que 8 couleurs sur 16 affichées à l'écran : celle du fond, le blanc brillant et les 7 couleurs correspondant aux 14 derniers registres. Le principal avantage de XOU (OU EXCLUSIF) est qu'il est réversible, deux mêmes copies s'annulent ce qui facilite l'effacement.
Pour afficher une image devant un arrière-plan sans restriction de couleurs, il faut mettre à zéro les pixels de l'arrière-plan à remplacer par ceux de l'image avant la copie avec OU -- INCLUSIF, EXCLUSIF peu importe.
Pour cela, on applique un masque grâce à l'opérateur ET logique. Vu qu'on travaille en mode 16 couleurs, il sera constitué de deux attributs : 15 et 0. Le premier préserve, le second annule.
Code : Tout sélectionner xxxxxxxxb (val. orig.) xxxxxxxxb (val. orig.) ET 11111111b (15 ou Fh) ET 00000000b (0) ----------- ----------- = xxxxxxxxb (val. orig.) = 00000000b (0) |
En conclusion, au lieu de travailler avec une seule image comme précédemment, on manipule aussi son masque et une copie de l'arrière-plan modifié, tous trois nécessitant la même quantité de mémoire. Le masque utilise la possibilité du ET logique de forcer un bit à zéro, le sprite, la possibilité contraire du OU logique.
En pratique, toutes ces copies sont longues à effectuer et il faut travailler en dehors de la mémoire vidéo avant d'afficher. Surtout que la mémoire vidéo des vieilles cartes sur connecteur ISA est lente. Malheureusement sous BASIC, il est plus facile de travailler en mémoire vidéo. En revanche, on peut avoir recours à deux pages vidéos, une sur laquelle on travaille les sorties et une utilisée pour afficher à l'écran.
Voici quelques informations à détenir :
Code : Tout sélectionner SCREEN 7 SCREEN 8 SCREEN 9 SCREEN 10
(MODE MONO)
EGA 64 Ko : 2 pages 1 page 1 page N/A
16 coul./16 16 coul./16 4 coul./64
EGA 128 Ko : 4 pages 2 pages 1 page 1 page
16 coul./16 16 coul./16 16 coul./64 4 attributs/9
EGA 256 Ko : 8 pages 4 pages 2 pages 2 pages
16 coul./16 16 coul./16 16 coul./64 4 attributs/9
|
Code : Tout sélectionner 1 ' Animation dirigée au clavier en mode EGA 320 x 200 16 couleurs. 2 ' Utilise un masque ET logique avant copie par OU INCLUSIF et 3 ' deux pages : une à l'écran et une de sortie échangeables. 4 ' Requiert : - GW-BASIC 3.2x supportant les codes BREAK du clavier et les 5 ' modes EGA ou IBM BASICA 3.20 minimum de préférence ; 6 ' - carte vidéo compatible EGA ; 7 ' - écran couleur. 8 ' Compilation : QuickBASIC 2.0 (/E/W) ou 4.5 de préférence. 9 : 100 ON ERROR GOTO 1000 ' Aller à TRAITEMENT D'ERREUR si erreur 110 PRINT "Animation graphique dirigée au clavier--touches fléchées du pavé numérique." 120 PRINT "Appuyez sur une touche pour commencer..." 130 WHILE INKEY$ = "": WEND 200 GOSUB 2000 ' Appeler DEBUT 300 GOSUB 3000 ' Appeler BOUCLE 399 ' ----- QUITTER ----- 400 ' Mode texte avec menu des touches de fonction. 410 WIDTH 80: SCREEN 0: KEY ON 420 ' Restaurer l'état du clavier. 430 DEF SEG = &H40 440 POKE &H17, PEEK(&H17) OR DRAPEAUX% 450 DEF SEG 460 ' Afficher message d'erreur s'il y a lieu. 470 PRINT MSG.ERR$ 480 ' Arrêter l'interception d'erreur. 490 IF MSG.ERR$ = "" THEN CLEAR ELSE ON ERROR GOTO 0 900 END ' Ou SYSTEM pour quitter aussi l'interpréteur. 990 : 999 ' ===== T R A I T E M E N T D ' E R R E U R ===== 1000 IF ERL = 31060 THEN 10000 ' Dessin hors limites 1010 ' Mode d'écran invalide 1020 IF ERL = 23000 OR ERR = 73 THEN MSG.ERR$ = "Carte vidéo non compatible EGA ou version de BASICA antérieure à la 3.20 !" ELSE MSG.ERR$ = "Erreur" + STR$(ERR) + " à la ligne" + STR$(ERL) + " : avertir l'auteur du programme." 1030 RESUME 400 ' Aller à QUITTER (on ne s'embête pas) 1990 : 1999 ' ===== D E B U T ===== 2000 ' Préparer les données, l'écran et l'interception des touches du curseur. 2100 GOSUB 21000 ' Initialisation variables 2200 GOSUB 22000 ' Sauvegarde état clavier 2300 GOSUB 23000 ' Initialisation écran, base tableaux, hasard 2400 GOSUB 24000 ' Fond 2500 GOSUB 25000 ' Création sprite et masque 2600 GOSUB 26000 ' Make et break touches fléchées 2700 GOSUB 27000 ' Surveillance touches fléchées 2710 PCOPY 0, 1 ' Forcément erreur si GW-BASIC Olivetti 3.11 ! 2720 PAGE.S% = 0: PAGE.E% = 1 ' Les deux pages partagent le même fond. 2900 RETURN 2990 : 2999 ' ===== B O U C L E ===== 3000 ' La boucle principale est celle qui gère l'affichage. 3010 WHILE TOUCHE$ <> CHR$(27) 3100 GOSUB 31000 ' Animer dessin 3110 SWAP PAGE.S%, PAGE.E% 3120 SCREEN , , PAGE.S%, PAGE.E% 3130 WAIT &H3DA, 8 ' Synchronisation verticale pour QBasic/BASICA. 3800 TOUCHE$ = INKEY$ 3810 WEND 3900 RETURN 9990 : 9997 ' ------------------- 9998 ' Dessin hors limites 9999 ' ------------------- 10000 IF DESSIN.X1% < 0 OR DESSIN.X1% > DESSIN.XMAX% THEN DESSIN.X1% = DESSIN.X% 10010 IF DESSIN.Y1% < 0 OR DESSIN.Y1% > DESSIN.YMAX% THEN DESSIN.Y1% = DESSIN.Y% 10900 RESUME 31060 ' Les BASIC 3.x continuent toute interception. 20900 : 20997 ' ---------------------- 20998 ' Initialisation valeurs 20999 ' ---------------------- 21000 ' Adressage d'écran. 21010 ECRAN.X% = 319: ECRAN.Y% = 199 21020 ' 21030 ' Variables de boucle et flags. 21040 I% = 0: J% = 0: 21050 FLAG% = 0: TOUCHE$ = "": DRAPEAUX% = 0 21060 ' 21070 ' Paramètres de l'animation. 21080 DESSIN.PAS.X% = 1: DESSIN.PAS.Y% = 1 ' Pixel par pixel. 21090 PAGE.S% = 0: PAGE.E% = 0 ' Pages : sortie et écran. 21100 ' 21110 ' Dimensions, vecteurs, coordonnées et taille du dessin à déplacer. 21120 DESSIN.LARGEUR% = 20: DESSIN.HAUTEUR% = 20 21130 DESSIN.VX% = 0: DESSIN.VY% = 0 21140 DESSIN.X% = 0: DESSIN.Y% = 0 21150 DESSIN.X1% = DESSIN.X%: DESSIN.Y1% = DESSIN.X% 21160 DESSIN.X2% = DESSIN.X1% + DESSIN.LARGEUR% - 1 21170 DESSIN.Y2% = DESSIN.Y1% + DESSIN.HAUTEUR% - 1 21180 DESSIN.XMAX% = ECRAN.X% - DESSIN.LARGEUR% + 1 21190 DESSIN.YMAX% = ECRAN.Y% - DESSIN.HAUTEUR% + 1 21200 DESSIN.TAILLE% = (4 + INT((DESSIN.LARGEUR% + 7) / 8) * DESSIN.HAUTEUR% * 4) / 2 21210 ' 21220 ' Tableaux où sont stockés le dessin, son masque et son arrière-plan. 21230 OPTION BASE 1 ' Les tableaux commencent par 1 au lieu de 0. 21240 DIM DESSIN.FOND%(DESSIN.TAILLE%) 21250 DIM DESSIN.SPRITE%(DESSIN.TAILLE%) 21260 DIM DESSIN.MASQUE%(DESSIN.TAILLE%) 21270 ' 21280 ' Message d'erreur. 21290 MSG.ERR$ = "" 21900 RETURN 21910 ' ********************************************************************** 21920 ' Le mode 320 x 200 16 couleurs comporte 4 plans et 4 bits par pixel. 21930 ' 4 + INT((largeur * bit par pixel par plan + 7) / 8) * hauteur * plan 21940 ' = taille du tableau en octets (un entier comporte deux octets) 21950 ' ********************************************************************** 21997 ' ----------------------- 21998 ' Sauvegarde état clavier 21999 ' ----------------------- 22000 ' On manipule la mémoire à partir du segment 0040h. 22010 DEF SEG = &H40 22020 ' On ignore les touches Ctrl, Alt ou Maj (poids faible) avant de sauver. 22030 DRAPEAUX% = PEEK(&H17) AND &HF0 22040 ' Désactiver le pavé numérique et le verrouillage majuscule (bits 5 & 6). 22050 POKE &H17, PEEK(&H17) AND &H9F 22060 ' On restitue absolument le segment BASIC par défaut. 22070 DEF SEG 22900 RETURN 22997 ' ------------------------------ 22998 ' Initialisation écran et hasard 22999 ' ------------------------------ 23000 SCREEN 7 ' Erreur si GW-BASIC IBM 3.21 mais pas Olivetti 3.11 ! 23010 CLS : KEY OFF 23020 COLOR , 1 ' GW-BASIC 3.2x perdra la palette au prochain SCREEN ! 23030 RANDOMIZE TIMER ' On initialise la liste des nombres pseudo-aléatoires 23900 RETURN ' grâce à l'horloge. 23997 ' ---- 23998 ' Fond 23999 ' ---- 24000 ' Ciel étoilé de confettis (16 couleurs). 24010 FOR I% = 1 TO 2000 24020 PRESET ((ECRAN.X% + 1) * RND, (ECRAN.Y% + 1) * RND), 15 * RND + 1 24030 NEXT I% 24900 RETURN 24997 '-------------------------- 24998 ' Création sprite et masque 24999 '-------------------------- 25000 GET (DESSIN.X1%, DESSIN.Y1%)-(DESSIN.X2%, DESSIN.Y2%), DESSIN.FOND% 25010 ' 25020 FLAG% = 0 ' 0 : flag pour dessin. 25030 GOSUB 53000 ' Afficher soit dessin soit masque 25040 GET (DESSIN.X1%, DESSIN.Y1%)-(DESSIN.X2%, DESSIN.Y2%), DESSIN.SPRITE% 25050 LOCATE 25, 1 ' Erreur si Compaq GW-BASIC 3.20 ! 25060 PRINT "Dessin utilisé..."; 25070 WHILE INKEY$ = "": WEND 25080 ' 25090 RESTORE 25100 FLAG% = NOT FLAG% ' -1 : flag pour masque. 25110 GOSUB 53000 ' Afficher soit dessin soit masque 25120 GET (DESSIN.X1%, DESSIN.Y1%)-(DESSIN.X2%, DESSIN.Y2%), DESSIN.MASQUE% 25130 LOCATE 25, 1 25140 PRINT "Masque utilisé..."; 25150 WHILE INKEY$ = "": WEND 25160 ' 25170 PUT (DESSIN.X1%, DESSIN.Y1%), DESSIN.FOND%, AND 25180 PUT (DESSIN.X1%, DESSIN.Y1%), DESSIN.SPRITE%, OR 25190 LOCATE 25, 1 25200 PRINT "Animation avec masque AND et sprite OR."; 25900 RETURN 25997 ' ------------------------------ 25998 ' Make et break touches fléchées 25999 ' ------------------------------ 26000 ' CHR$(0) signifie pavé numérique et verrouillage majuscule désactivés. 26010 ' ... + CHR$(&H80 + scancode) : code de relâchement d'une touche (BREAK). 26020 KEY 15, CHR$(0) + CHR$(128 + 72) ' GW-BASIC Olivetti 3.20 ignore BREAK ! 26030 KEY 16, CHR$(0) + CHR$(128 + 75) 26040 KEY 17, CHR$(0) + CHR$(128 + 77) 26050 KEY 18, CHR$(0) + CHR$(128 + 80) 26060 ON KEY(11) GOSUB 51000 ' Aller à MAKE HAUT 26070 ON KEY(12) GOSUB 51200 ' Aller à MAKE GAUCHE 26080 ON KEY(13) GOSUB 51400 ' Aller à MAKE DROITE 26090 ON KEY(14) GOSUB 51600 ' Aller à MAKE BAS 26100 ON KEY(15) GOSUB 52000 ' Aller à BREAK HAUT 26110 ON KEY(16) GOSUB 52200 ' Aller à BREAK GAUCHE 26120 ON KEY(17) GOSUB 52400 ' Aller à BREAK DROITE 26130 ON KEY(18) GOSUB 52600 ' Aller à BREAK BAS 26900 RETURN 26997 ' ----------------------------- 26998 ' Surveillance touches fléchées 26999 ' ----------------------------- 27000 FOR I% = 11 TO 18 27010 KEY(I%) ON 27020 NEXT I% 27900 RETURN 30990 : 30997 ' ------------- 30998 ' Animer dessin 30999 ' ------------- 31000 PUT (DESSIN.X%, DESSIN.Y%), DESSIN.FOND%, PSET ' Efface avant-dernier. 31010 GET (DESSIN.X1%, DESSIN.Y1%)-(DESSIN.X2%, DESSIN.Y2%), DESSIN.FOND% 31020 DESSIN.X% = DESSIN.X1% 31030 DESSIN.Y% = DESSIN.Y1% 31040 LET DESSIN.X1% = DESSIN.X1% + DESSIN.VX% 31050 LET DESSIN.Y1% = DESSIN.Y1% + DESSIN.VY% 31060 PUT (DESSIN.X1%, DESSIN.Y1%), DESSIN.MASQUE%, AND ' Risque hors limite. 31070 PUT (DESSIN.X1%, DESSIN.Y1%), DESSIN.SPRITE%, OR 31080 DESSIN.X2% = DESSIN.X1% + DESSIN.LARGEUR% - 1 31090 DESSIN.Y2% = DESSIN.Y1% + DESSIN.HAUTEUR% - 1 31900 RETURN 49990 : 50000 ' Pas de REM (commentaires) dans les routines MAKE : pas de diagonales. 50997 ' --------- 50998 ' Make haut 50999 ' --------- 51000 REM DESSIN.VX% = 0 51010 DESSIN.VY% = -DESSIN.PAS.Y% 51090 RETURN 51197 ' ----------- 51198 ' Make gauche 51199 ' ----------- 51200 DESSIN.VX% = -DESSIN.PAS.X% 51210 REM DESSIN.VY% = 0 51290 RETURN 51397 ' ----------- 51398 ' Make droite 51399 ' ----------- 51400 DESSIN.VX% = DESSIN.PAS.X% 51410 REM DESSIN.VY% = 0 51490 RETURN 51597 ' -------- 51598 ' Make bas 51599 ' -------- 51600 REM DESSIN.VX% = 0 51610 DESSIN.VY% = DESSIN.PAS.Y% 51690 RETURN 51997 ' ---------- 51998 ' Break haut 51999 ' ---------- 52000 IF DESSIN.VY% < 0 THEN DESSIN.VY% = 0 52090 RETURN 52197 ' ------------ 52198 ' Break gauche 52199 ' ------------ 52200 IF DESSIN.VX% < 0 THEN DESSIN.VX% = 0 52290 RETURN 52397 ' ------------ 52398 ' Break droite 52399 ' ------------ 52400 IF DESSIN.VX% > 0 THEN DESSIN.VX% = 0 52490 RETURN 52597 ' --------- 52598 ' Break bas 52599 ' --------- 52600 IF DESSIN.VY% > 0 THEN DESSIN.VY% = 0 52690 RETURN 52997 ' -------------------------------- 52998 ' Afficher soit dessin soit masque 52999 ' -------------------------------- 53000 ' FLAG% = -1 (var. booléenne non nulle donc VRAIE) : masque sinon dessin. 53010 FOR J% = DESSIN.Y1% TO DESSIN.Y2% 53020 FOR I% = DESSIN.X1% TO DESSIN.X2% 53030 READ COULEUR% 53040 IF FLAG% THEN IF COULEUR% THEN COULEUR% = 0 ELSE COULEUR% = 15 53050 PSET (I%, J%), COULEUR% 53060 NEXT I%, J% 53900 RETURN 60990 : 60999 ' Dessin 20 x 20 pixels pour palette 16 couleurs par défaut. 61000 DATA 00,00,00,00,00,00,00,00,00,02,02,00,00,00,00,00,00,00,00,00 61010 DATA 00,00,00,00,00,00,00,00,02,02,02,02,00,00,00,00,00,00,00,00 61020 DATA 00,00,00,00,00,00,00,00,02,02,02,02,00,00,00,00,00,00,00,00 61030 DATA 00,00,00,00,00,00,00,02,02,02,02,02,02,00,00,00,00,00,00,00 61040 DATA 00,00,00,00,00,00,00,02,02,02,02,02,02,00,00,00,00,00,00,00 61050 DATA 00,00,00,00,00,00,02,02,02,04,04,02,02,02,00,00,00,00,00,00 61060 DATA 00,00,00,00,00,00,02,02,04,10,10,04,02,02,00,00,00,00,00,00 61070 DATA 00,00,00,00,00,00,02,02,02,02,02,02,02,02,00,00,00,00,00,00 61080 DATA 00,00,00,00,00,00,00,02,02,06,06,02,02,00,00,00,00,00,00,00 61090 DATA 00,00,00,00,00,00,00,00,02,02,02,02,00,00,00,00,00,00,00,00 61100 DATA 00,00,00,00,00,00,00,00,00,02,02,00,00,00,00,00,00,00,00,00 61110 DATA 00,00,00,00,00,00,00,00,05,05,05,05,00,00,00,00,00,00,00,00 61120 DATA 00,00,00,00,11,11,11,07,07,07,07,07,07,11,11,11,00,00,00,00 61130 DATA 00,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,00 61140 DATA 07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07,07 61150 DATA 08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08 61160 DATA 00,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,08,00 61170 DATA 00,00,00,00,08,08,08,08,08,08,08,08,08,08,08,08,00,00,00,00 61180 DATA 00,00,00,00,00,00,00,00,08,08,08,08,00,00,00,00,00,00,00,00 61190 DATA 00,00,00,00,00,00,00,00,00,08,08,00,00,00,00,00,00,00,00,00 61200 ' IBM BASICA 3.40 cherche les 5 1ers Ko du BASIC en ROM via INT15h Fct22h. |
Il faut la ligne 3130 pour la synchronisation verticale sous QuickBASIC 4.5, PDS, VB/DOS et sous IBM BASICA.
A noter que le message de la ligne 1110 ne s'applique pas à la version 3.21 d'IBM qui est un GW/BASIC 2, et que le Compaq BASIC 3.20 considère LOCATE 25 comme une erreur, même après KEY OFF.
P.S. : la synchronisation verticale doit s'effectuer après l'échange d'écran et avant les différentes manipulations vidéo afin d'éviter que le dessin animé ne disparaisse à certaines hauteurs d'écran -- phénomène à prendre en compte pour les processeurs les moins rapides capables d'assurer une animation fluide.
16/4/21 : autant d'éditions que de versions BASIC. Ouf !

![[ img ]](http://zupimages.net/up/17/01/de5k.jpg)