|
L'équipe progG de Ti-Fr
|
Voici les nicks de vos serviteurs ;-)
chickensaver_john
Kevin Kofler
Thibaut
janjan2
TiMad
Iceman89
fréka
Zewoo
Squale92
Verstand
ZdRUbAl
UtOpIaH
et nEUrOne ...
|
|
Une idée ?
|
Une idée pour améliorez cette partie?
ou tout simplement vous souhaitez participer à l'élaborations
des tutos.
Mailez-nous ici
|
| |
Chapitre
XVIII
Jusqu'à maintenant, nous avons utilisé la fonction ngetchx()
pour lire le clavier. mais, cette fonction est très lente, car elle lit aussi
les port de communication I/O. De plus, le problème de cette fonction est
qu'elle met en pause l'exécution du programme, jusqu'à ce qu'une touche soit
pressée. Il est donc impossible (ou presque) de gérer le clavier avec cette
fonction si l'on veut, en même temps afficher des animations à l'écran, ou
effectuer quoi que ce soit d'autre...
Certes, il existe la fonction kbhit,
qui permet de lire au clavier sans déclencher de pause, ce qui permet
d'utiliser des animations, mais cette fonction n'est pas aussi rapide que _rowread...
En conclusion, si vous souhaitez créer un programme
affichant des animations, et acceptant des pressions au clavier, comme pour un
jeux d'action, par exemple, il vous faudra utiliser _rowread
pour obtenir quelque chose de rapide...
Cette fonction, qui semble assez complexe à utiliser ne
l'est en fait pas tant que cela : le tout est d'en comprendre les bases, afin de
pouvoir les ré-appliquer... C'est ce que va (j'espère !) vous permettre de
faire ce chapitre...
I:\ Manipulations
préliminaires :
La fonction _rowread
lit le clavier, mais à bas niveau. En fait, la lecture du clavier par cette
fonction est basée sur l'AUTO_INT_1.
(Il s'agit d'une sorte de compteur à rebours quasi-permanent de la TI.). Si le
"compteur à rebours" arrive à 0, cela déclenche des
"évènements", qui peuvent interférer avec cette fonction. Donc, il
est particulièrement recommandé de désactiver l'AUTO_INT_1.
Cependant, les niveaux de gris sont basés sur cet AUTO_INT
(voir la page qui traite de la gestion
des niveaux de gris).!!! Quel ennui pour les jeux, n'est-ce pas ?!?
Pour éviter ce problème, nous utiliserons une voie
détournée : nous ne désactiverons pas l'AUTO_INT_1,
mais nous le "remplacerons".... Ainsi, il n'y aura pas d'interférence
avec _rowread, et, oh miracle, les
niveaux de gris fonctionneront ! De plus, les indicateurs de la Status Line
(2nd, <>, @, ...) n'apparaîtront plus à l'écran, ce qui permettra
d'utiliser les touches HAND (sur 92+) ou 2nd (Sur 89) pour le déclenchement des
tirs, par exemple dans le cas d'un jeu d'action, sans que l'affichage soit
perturbé par ceux-ci.
Pour rediriger l'AUTO_INT_1,
nous utiliserons l'Interrupt qui a été inclut dans ce but dans TIGCC, le DUMMY_HANDLER.
Au début de notre programme, il faudra ainsi inclure la
ligne de code suivante, qui permettra de déclarer la sauvegarde de l'AUTO_INT_1,
afin de le restaurer avant la fin du programme :
INT_HANDLER save_int_1;
Ensuite, au moment ou vous souhaiterez commencer à
utiliser _rowread, il vous faudra
inclure les lignes de code suivantes :
save_int_1 = GetIntVec (AUTO_INT_1);
SetIntVec (AUTO_INT_1, DUMMY_HANDLER);
Ces fonctions vous permettront de sauvegarde l'AUTO_INT_1,
puis d'installer le votre (en l'occurrence, DUMMY_HANDLER)
à la place.
Attention, l'utilisation de fonction de lecture du clavier à
Haut Niveau, telles ngetchx()
ré-activerons l'AUTO_INT_1, ou
pourront être à l'origine d'un plantage s'il n'est pas activé...
Enfin, à la fin de votre programme, il vous faudra
impérativement penser à ré-activer l'AUTO_INT_1,
afin d'éviter toute "barre noire" assez désagréable lorsqu'on vient
de passer un bon moment sur un jeu ! pour cela, il vous faut utiliser la
fonction suivante :
SetIntVec (AUTO_INT_1, save_int_1);
II:\ La
lecture du clavier avec _rowread :
Cette fonction a un mode de fonctionnement assez exotique,
car elle lit la "Matrice Clavier", qui est différente sur TI-89 et
Ti-92plus, puisque les claviers eux-même sont différents...
Voilà comment la matrice clavier est organisée, sur
TI-89 puis sur TI-92plus :
TI-89:
|
Colonne |
Ligne |
|
Bit 7
|
Bit 6
|
Bit 5
|
Bit 4
|
Bit 3
|
Bit 2
|
Bit 1
|
Bit 0
|
Bit 0
|
Alpha
|
Diamant
|
Shift
|
2nd
|
Droite
|
Bas
|
Gauche
|
Haut
|
Bit 1
|
F5
|
CLEAR
|
^
|
/
|
*
|
-
|
+
|
ENTER
|
Bit 2
|
F4
|
Delete
|
T
|
,
|
9
|
6
|
3
|
(-)
|
Bit 3
|
F3
|
CATLG
|
Z
|
)
|
8
|
5
|
2
|
.
|
Bit 4
|
F2
|
MODE
|
Y
|
(
|
7
|
4
|
1
|
0
|
Bit 5
|
F1
|
HOME
|
X
|
=
|
|
|
EE
|
STO->
|
APPS
|
Bit 6
|
NON AFFECTÉES !!!
|
ESC
|
|
TI-92plus:
|
Colonne |
Ligne |
|
Bit 7
|
Bit 6
|
Bit 5
|
Bit 4
|
Bit 3
|
Bit 2
|
Bit 1
|
Bit 0
|
Bit 0
|
Bas
|
Droite
|
Haut
|
Gauche
|
HAND
|
Shift
|
Diamant
|
2nd
|
Bit 1
|
3
|
2
|
1
|
F8
|
W
|
S
|
Z
|
Non
affectées
|
Bit 2
|
6
|
5
|
4
|
F3
|
E
|
D
|
X
|
Bit 3
|
9
|
8
|
7
|
F7
|
R
|
F
|
C
|
STO->
|
Bit 4
|
,
|
)
|
(
|
F2
|
T
|
G
|
V
|
Espace
|
Bit 5
|
TAN
|
COS
|
SIN
|
F6
|
Y
|
H
|
B
|
/
|
Bit 6
|
P
|
ENTER2
|
LN
|
F1
|
U
|
J
|
N
|
^
|
Bit 7
|
*
|
APPS
|
CLEAR
|
F5
|
I
|
K
|
M
|
=
|
Bit 8
|
|
ESC
|
MODE
|
+
|
O
|
L
|
Thêta
|
Delete
|
Bit 9
|
(-)
|
.
|
0
|
F4
|
Q
|
A
|
ENTER1
|
-
|
|
Pour TI-92plus, ENTER1 correspond aux deux touches ENTER du
clavier alphanumérique, et ENTER2 correspond à la touche ENTER localisée sous
le pavé multidirectionnel.
Utilisation de _rowread
avec la matrice clavier :
En fait, _rowread
prend en argument une valeur de type short,
qui correspond à la transcription en Hexadécimal de la valeur en binaire de la
colonne... C'est compliqué, n'est-ce pas ? Eh bien, NON : c'est une simple
impression sur le papier : quand vous aurez utilisé cette fonction deux ou
trois fois, vous vous direz que c'était vraiment simple !
Ensuite, elle renvoie la valeur de la ligne correspondant au
test ...
Je penses que le mieux pour que vous compreniez ce que je
veux dire est que je fournisse un exemple :
Partons de l'exemple de la lecture de la Touche MODE.
Sur TI-89 : La
touche MODE est sur cette calculatrice la troisième de sa colonne, en partant
du bas. La colonne, si on ne veut conserver que cette touche, aura donc, en
binaire, comme valeur : 1101111. Il convient à présent de convertir cette valeur
en hexadécimal (ce que votre TI sait faire !), et qui donne, dans ce cas : 0x10.
(Rappel : Depuis la version 0.91
de TIGCC, il est possible d'utiliser des valeurs en binaire, mais, pour raison
de compatibilité avec les anciennes versions, je vous conseille de les transcrire
tout de même en hexadécimal).
Donc, pour tester la ligne qui
correspond à la touche MODE, il faudra utiliser _rowread(0x6F)...
Cette fonction renvoie la valeur (en hexadécimal,
correspondant à la valeur en binaire) de la ligne correspondant à celle qui a
été marquée par un "0" dans l'argument de la fonction. Ainsi, la
ligne correspondant à la touche MODE aura pour valeur, si celle-ci a été
pressée : 01000000 (puisque la touche MODE est la seconde en partant de la
gauche). Cela correspond à 0x40 en hexadécimal.
Donc, pour tester le fait que la touche MODE ait été
pressée, il faudra faire :
if(_rowread(0x6F)&0x40)
{
//
instructions à exécuter si MODE a été pressé...
}
Sur TI-92plus : La touche MODE est sur cette calculatrice
la seconde de sa colonne, en partant du bas. La colonne, si on ne veut conserver
que cette touche, aura donc, en binaire, comme valeur : 1011111111. Il convient
à présent de convertir cette valeur en hexadécimal (ce que votre TI sait faire
!), et qui donne, dans ce cas : 0x2FF. (Rappel
: Depuis la version 0.91 de TIGCC, il est possible d'utiliser
des valeurs en binaire, mais, pour raison de compatibilité avec les anciennes
versions, je vous conseille de les transcrire tout de même en hexadécimal).
Donc, pour tester la ligne qui
correspond à la touche MODE, il faudra utiliser _rowread(0x2FF)...
Cette fonction renvoie la valeur (en hexadécimal,
correspondant à la valeur en binaire) de la ligne correspondant à celle qui a
été marquée par un "0" dans l'argument de la fonction. Ainsi, la
ligne correspondant à la touche MODE aura pour valeur, si celle-ci a été
pressée : 00100000 (puisque la touche MODE est la seconde en partant de la
gauche). Cela correspond à 0x20 en hexadécimal.
Donc, pour tester le fait que la touche MODE ait été
pressée, il faudra faire :
if(_rowread(0x2FF)&0x20)
{
//
instructions à exécuter si MODE a été pressé...
}
Quelques valeurs les plus couramment
utilisées :
Maintenant que je vous ai expliqué le fonctionnement
général, je crois qu'il serait bon que je vous fournisse quelques cas précis.
En effet, je ne suis pas sûr que mes explications aient été très claire :-).
Sur TI-92plus :
Touche de la TI
|
Valeur binaire
|
Valeur hexadécimale
|
Instruction de test : if(....)
|
Colonne
|
Ligne
|
Colonne
|
Ligne
|
Gauche
|
1111111110
|
00010000
|
0x3FE
|
0x10
|
_rowread(0x3FE)&0x10
|
Droite
|
1111111110
|
01000000
|
0x3FE
|
0x40
|
_rowread(0x3FE)&0x40
|
Haut
|
1111111110
|
00100000
|
0x3FE
|
0x20
|
_rowread(0x3FE)&0x20
|
Bas
|
1111111110
|
10000000
|
0x3FE
|
0x80
|
_rowread(0x3FE)&0x80
|
HAND
|
1111111110
|
00001000
|
0x3FE
|
0x8
|
_rowread(0x3FE)&0x8
|
2nd
|
1111111110
|
00000001
|
0x3FE
|
0x1
|
_rowread(0x3FE)&0x1
|
F1
|
1110111111
|
00010000
|
0x3BF
|
0x10
|
_rowread(0x3BF)&0x10
|
ESC
|
1011111111
|
01000000
|
0x2FF
|
0x40
|
_rowread(0x2FF)&0x40
|
Sur la TI-89 :
Touche de la TI
|
Valeur binaire
|
Valeur hexadécimale
|
Instruction de test : if(....)
|
Colonne
|
Ligne
|
Colonne
|
Ligne
|
Gauche
|
1111110
|
00000010
|
0x7E
|
0x2
|
_rowread(0x7E)&0x2
|
Droite
|
1111110
|
00001000
|
0x7E
|
0x8
|
_rowread(0x7E)&0x8
|
Haut
|
1111110
|
00000001
|
0x7E
|
0x1
|
_rowread(0x7E)&0x1
|
Bas
|
1111110
|
00000100
|
0x7E
|
0x4
|
_rowread(0x7E)&0x4
|
Alpha
|
1111110
|
10000000
|
0x7E
|
0x80
|
_rowread(0x7E)&0x80
|
2nd
|
1111110
|
00010000
|
0x7E
|
0x10
|
_rowread(0x7E)&0x10
|
F1
|
1011111
|
10000000
|
0x5F
|
0x80
|
_rowread(0x5F)&0x80
|
ESC
|
0111111
|
00000001
|
0x3F
|
0x1
|
_rowread(0x3F)&0x1
|
Si vous vous rendez compte qu'une des valeurs que je donne ici
ne fonctionne pas, merci de me
le signaler immédiatement, afin que je puisse corriger cette erreur au plus
vite ! (En précisant dans quel tableau se trouve l'erreur.). Merci.
III:\ Exemple
de source utilisant _rowread :
Ce petit programme va afficher un sprite en mouvement
automatique en bas de l'écran, à la vitesse maximale qui lui sera autorisée,
et un autre, plus gros, que vous pourrez déplacer à votre guise dans la zone
qui lui est assignée.
Étant donné que la fonction _rowread
prend en argument des valeurs différentes sur TI-89 est sur TI-92plus, ce
programme comporte une boucle conditionnelle qui s'exécute si la largeur de
l'écran est égale à 160 (=> TI-89), et une autre si elle est différente
de 160 (=> TI-92plus). Dans un jeu, par exemple, il vaudrait mieux créer
deux sources spécifiques, l'un pour TI-89, et l'autre pour TI-92plus, ce qui
permettrait d'économiser de l'espace mémoire. Par contre, le programme ne
serait plus utilisable à la fois sur TI-89 et sur TI-92plus.
#define
OPTIMIZE_ROM_CALLS
#define SAVE_SCREEN
#include <tigcclib.h>
short _ti92plus,
_ti89;
void _main(void)
{
// Déclaration des sprites qui seront utilisés
pour les animations. sprite_TI et sprite_TI_vide correspondent à deux sprites
de 32x32 pixels, qui seront animés par l'utilisateur du programme, et
sprite_comic et sprite_comic_vide correspondent aux sprites qui seront utilisés
pour l'animation automatique.
static
unsigned long sprite_TI[] = {0xFF000,
0x700E00, 0x1800180,
0x2000040, 0x4000020,
0x87C3E10, 0x10824108,
0x20442204, 0x20381C04,
0x40018002, 0x40018002,
0x40018002, 0x8003C001,
0x8007E001, 0x8007E001,
0x8005A001, 0x80000001,
0x80000001, 0x80000001,
0x800FF001, 0x4115A882,
0x41E00782, 0x41400282,
0x21400284, 0x20200404,
0x1015A808, 0x80FF010,
0x4000020, 0x2000040,
0x1800180, 0x700E00,
0xFF000};
static
unsigned long sprite_TI_vide[] = {0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0};
static
unsigned short sprite_animation[] = {0x180,
0x660, 0x1818,
0x2004, 0x2664,
0x4002, 0x4182,
0x8181, 0x8181,
0x4812, 0x4422,
0x23C4, 0x2004,
0x1818, 0x660,
0x180};
static
unsigned short sprite_animation_vide[] = {0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x0};
/*
Déclaration des variables qui seront utilisées dans le programme :
pos_x_comic correspond à la position en X du sprite
auto-animé (il ne se déplace que horizontalement).
pos_x_TI et pos_y_TI correspondent à la position en X et en
Y du sprite qui sera animé par l'utilisateur du programme.
aller_retour aura pour valeur 1 si le sprite auto-animé se
déplace de la gauche vers la droite, et 0 dans le sens contraire.
quitter aura pour valeur 0 tant que l'utilisateur n'aura pas
appuyé sur ESC, dans le but de quitter le programme.
Enfin, save_int_1 correspond à la sauvegarde de
l'AUTO_INT_1.
*/
short pos_x_comic =
0;
short pos_x_TI =
0, pos_y_TI =
0;
short quitter =
0;
short aller_retour =
0;
INT_HANDLER save_int_1;
// Initialisation des variables qui doivent
l'être, ainsi que sauvegarde de l'AUTO_INT_1, et effacement de l'écran.
pos_x_TI =
0;
pos_y_TI = 18;
save_int_1 = GetIntVec(AUTO_INT_1);
SetIntVec(AUTO_INT_1,
DUMMY_HANDLER);
ClrScr();
// Affichage de l'écran de départ, avant
l'animation. Toutes les fonctions utilisées ici ont déjà été étudiées
dans ce tutorial.
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
DrawLine(0,
16, LCD_WIDTH,
16, A_THICK1);
FontSetSys(F_8x10);
DrawStrXY((LCD_WIDTH-DrawStrWidth("_rowread
DEMO", F_8x10))/2,
2, "_rowread
DEMO", A_SHADED);
Sprite16(0,
0, 16,
sprite_animation, LCD_MEM,
A_OR);
Sprite16(LCD_WIDTH-16,
0, 16,
sprite_animation, LCD_MEM,
A_OR);
do
{
// gestion du sprite automatique : Au début, il
est effacé (grâce à l'affichage d'un sprite vide), puis, sa position est
modifiée en fonction de sa position actuelle, et, enfin, il est redessiné à
sa nouvelle position.
Sprite16(LCD_WIDTH-pos_x_comic-16,
LCD_HEIGHT-16,
16, sprite_animation_vide,
LCD_MEM, A_XOR);
if(pos_x_comic<LCD_WIDTH-16
&& aller_retour==1)
{
pos_x_comic++;
}
else
if(pos_x_comic>0
&& aller_retour==0)
{
pos_x_comic--;
}
if(pos_x_comic==LCD_WIDTH-16
&& aller_retour==1)
{
aller_retour =
0;
}
if(pos_x_comic==0
&& aller_retour==0)
{
aller_retour =
1;
}
Sprite16(LCD_WIDTH-pos_x_comic-16,
LCD_HEIGHT-16,
16, sprite_animation,
LCD_MEM, A_OR);
// Cette partie correspond à la TI-92plus :
if(LCD_WIDTH
!= 160)
{
if(_rowread(0x3FE)&0x10
&& pos_x_TI>0)
//Gauche
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_x_TI--;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x3FE)&0x40
&& pos_x_TI<LCD_WIDTH-32)
//Droite
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_x_TI++;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x3FE)&0x80
&& pos_y_TI<LCD_HEIGHT-32-16)
//Bas
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_y_TI++;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x3FE)&0x20
&& pos_y_TI>18)
//Haut
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_y_TI--;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x2FF)&0x40)
// Esc
{
quitter =
1;
}
}
// Et cette partie est detinée à la TI-89 :
if(LCD_WIDTH
== 160)
{
if(_rowread(0x7E)&0x2
&& pos_x_TI>0)
//Gauche
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_x_TI--;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x7E)&0x8
&& pos_x_TI<LCD_WIDTH-32)
//Droite
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_x_TI++;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x7E)&0x4
&& pos_y_TI<LCD_HEIGHT-32-16)
//Bas
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_y_TI++;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x7E)&0x1
&& pos_y_TI>18)
//Haut
{
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI_vide, LCD_MEM,
A_XOR);
pos_y_TI--;
Sprite32(pos_x_TI,
pos_y_TI, 32,
sprite_TI, LCD_MEM, A_OR);
}
if(_rowread(0x23F)&0x1)
// Esc
{
quitter =
1;
}
}
}while(quitter
!= 1);
// répète la boucle Do tant que quitter est
différent de 1, c'est-à-dire tant que l'utilisateur n'a pas appuyé sur ESC.
SetIntVec(AUTO_INT_1,
save_int_1); //
Restaure l'AUTO_INT_1
}
IV:\ Lecture
de plusieurs touches :
La fonction _rowread
permet, comme nous venons de le voir, de lire les touches pressées au clavier
une par une. mais cette fonction permet aussi de lire des pressions
simultanées.
Pour cela, il vous suffit de masquer plusieurs colonne, ou
d'analyser les résultats de plusieurs bits d'une ligne.
Pour lire plusieurs colonnes, il faudra placer plusieurs
"0" dans la définition binaire de l'argument, et, pour lire plusieurs
touches sur une même ligne, il suffira de lire si, dans la réponse
hexadécimale traduite en binaire, plusieurs bits sont sur "1".
Juste un petit avertissement : si trois touches formant
trois angles d'un rectangle (au niveau de la matrice clavier) sont pressées en
même temps, la calculatrice considérera que la touche formant le quatrième
angle de ce rectangle l'est aussi. Cela est du à la gestion du clavier par la
TI... Mais, je doute que ceci vous gène particulièrement : il est souvent plus
simple de lire les touches unes par unes, sauf dans le cas où vous voulez
obtenir 2nd+haut, ou quelque chose de ce type...
V:\ Conclusion de ce
chapitre :
Et voilà, j'espère que vous avez compris ce que j'ai
tenté de vous expliquer dans ce chapitre. Si tel n'est pas le cas,
persévérez, car cette fonction vaut vraiment la peine de se fatiguer à
étudier son fonctionnement.
Ce que vous pouvez faire pour vous rendre compte de vos nouvelles
capacités, c'est essayer de développer un jeu, à partir de maintenant : avec
tous ce que nous avons à présent vu (Niveaux
de gris, Sprites,
Graphismes, _rowread, ...), cela devrait
vous être possible...
Pour ce chapitre, je tiens à remercier tout particulièrement
Liquid (alias Psigames) et
Otheos pour leurs nombreux reports
d'erreurs.
Retour au menu général
Chapitre
XIX
|
|