Créons ensemble un Pacman Partie n°1 - Panoramic

Transcription

Créons ensemble un Pacman Partie n°1 - Panoramic
ART013/ Par Jicehel
Créons ensemble un Pacman
Partie n°1
(Les sources liées à cette article sont disponibles en téléchargement
)
Introduction
Nous allons réaliser un jeu de labyrinthe de type Pacman qui s’inspirera fortement du célèbre jeu
d’arcade Pacman, sorti par Namco en 1979.
Les règles seront donc le plus possible identiques à celles du jeu original.
Le but du jeu consiste à diriger un personnage (Pacman), dans un labyrinthe dont les couloirs sont
remplis de petites pastilles afin qu’il les mange toutes une à une.
Nous allons surtout nous servir de ce jeu pour voir toute une partie des fonctions de Panoramic et
comment les utiliser.
Ce premier article va être découpé en 3 parties :

Dans la première partie nous allons voir les instructions permettant de créer notre premier programme :
Nous allons afficher un sprite de Pacman qui se déplace de manière programmée.
Il n’y a aucune interaction avec l’utilisateur. Le sprite bouge tout seul à l’écran.

Dans la seconde partie nous allons essayer de mettre en place des mécanismes sur ce programme très
simple afin d’en améliorer la maintenance et nous expliquerons pourquoi nous complexifions le code
pour mettre en place ces mécanismes totalement inutiles lors de la création de programmes simples tel
que notre exemple mais qui facilite énormément la vie lors de la création de codes plus complexes tel
que celui de notre Pacman quand il sera complet.

Dans la troisième partie, nous allons utiliser une planche de sprites simple pour charger notre sprite et
nous laisserons l’utilisateur contrôler les déplacements du Pacman au clavier.
Le sprite du Pacman changera en fonction de sa direction et il devra ne pas pouvoir sortir de la fenêtre
Dans chaque section, un extrait de la documentation expliquera les nouvelles instructions que nous
utiliserons. Ces extraits ne sont pas exhaustifs et si vous voulez plus d’information vous pourrez
vous référer à l’aide intégrée de Panoramic ou à l’aide accessible sur le site de Panoramic dont je
rappelle l’adresse : http://panoramic-language.pagesperso-orange.fr/French/LIST_alpha.htm
Vous pouvez également demander de l’aide sur le forum de Panoramic si besoin à l’adresse :
http://panoramic.free-boards.net/
Partie 1 : Créons un sprite et animons le à l’écran
Commençons par définir ce dont nous allons avoir besoin :

Une fenêtre dans laquelle l’application s’exécutera

Un sprite qui se déplacera dans cette fenêtre

Une image qui va contenir l’image qui va être chargée dans ce sprite

Utiliser les sprites avec Panoramic nécessite un autre objet : le SCENE2D que nous verrons
plus tard
Maintenant passons en revue dont nous allons avoir besoin :
Commandes « Taille » des objets (WIDTH / HEIGHT)
Afin de définir la taille de notre fenêtre principale (la FORM 0 qui est créée par Panoramic au
lancement du programme) et celle de notre SCENE2D (nous expliquerons plus tard dans l’article à
quoi cet objet sert), nous allons utiliser les commandes ci-dessous
WIDTH N, V
HEIGHT N, V
Met la largeur de l'objet numéro N à V pixels.
Met la hauteur de l'objet numéro N à V pixels.
Exemple de code utilisé : HEIGHT 0,600 : WIDTH 0,800
Explications : En saisissant cette ligne nous indiquons que nous voulons que la
fenêtre principale (l’objet 0) ait une hauteur de 600 pixels (unité élémentaire de taille
des écrans) et une largeur de 800 pixels
Pour connaître les dimensions de ces 2 objets, nous utiliserons le 2 commandes ci dessous
WIDTH(N)
HEIGHT(N)
Retourne la largeur de l'objet numéro N en pixels.
Retourne la hauteur de l'objet numéro N en pixels.
Exemple de code utilisé : HEIGHT 1, HEIGHT(0)-38 : WIDTH 1,WIDTH(0)-16
Explications : En saisissant cette ligne nous indiquons que nous voulons que l’objet 1
(un SCENE2D que nous devons avoir déclaré avant) ait la même hauteur que la
fenêtre principale (l’objet 0) moins 38 pixels (la taille de la bordure (16) et de la barre
de titre (22)) et qu’il ait également une largeur équivalente à celle de la fenêtre
principale moins 16 pixels (taille cumulée des bords de la fenêtre)
SCENE2D
SCENE2D N Crée un objet SCENE2D et lui affecte le numéro N qui servira à le désigner.
N doit être un entier positif non utilisé pour définir un autre objet.
Un SCENE2D est utilisé pour créer un univers 2D dans lequel on peut visualiser une image de fond
(un arrière plan) et afficher des SPRITEs. Ce sont les bases d'un jeu vidéo en 2D.
Les SPRITES peuvent être déplacés dans cet univers, cachés, visualisés sans perturber l'image de fond
du SCENE2D. De plus les sprites possèdent une couleur "transparente", non visualisée qui laisse
apparaître l’arrière plan
Le SCENE2D est créé à la position (0,0) : c'est-à-dire que par défaut, il utilise TOP = 0 et LEFT = 0,
avec les dimensions WIDTH = 200 et HEIGHT = 200
Le SCENE2D créé par défaut est donc un carré créé sur le FORM numéro 0 de 200 pixels dont le coin
supérieur gauche est situé en 0,0. Il y a des moyens de changer tous ces paramètres. Nous l’avons vu
avec les commandes WIDTH et HEIGHT, mais il y a d’autres possibilités de modification sur
lesquelles nous ne nous attarderons par pour le moment afin de pouvoir rapidement illustrer tout ça.
SPRITE
SPRITE N
Crée un sprite dans le SCENE2D "cible" et lui affecte le numéro N qui servira à le
désigner. N doit être un entier positif et non pour définir un autre sprite.
Un SPRITE est une image qui peut se déplacer sur l'image de fond d'un SCENE2D sans le perturber.
Un sprite est positionné par défaut en (0,0) du SCENE2D. Il faut donc faire attention lors du
chargement du sprite afin d’éviter les effets visuels indésirable.
La taille maximale d'un SPRITE est 200x200 pixels.
SPRITE_FILE_LOAD / SPRITE_IMAGE_LOAD
Un SPRITE doit être créé et peut alors recevoir une image depuis un fichier au format BMP par la
commande SPRITE_FILE_LOAD ou par copie depuis une image en mémoire grace à la commande
SPRITE_IMAGE_LOAD. Le sprite peut être déplacé, agrandi, caché, visualisé à nouveau ou détruit
en utilisant les commandes appropriées.
SPRITE_FILE_LOAD N, F
SPRITE_IMAGE_LOAD N1, N2
Charge dans le SPRITE numéro N l'image (BMP) contenue dans le fichier F
Charge dans le SPRITE numéro N1 l'image contenue dans l'objet système de numéro N2.
Exemple de code utilisé : SPRITE_FILE_LOAD 1,"Source1_Pacman.BMP"
Explications : Nous indiquons que nous voulons charger l’image Source1_Pacman.BMP
dans le sprite 1
SPRITE_POSITION
SPRITE_POSITION N,X,Y modifie les coordonnée (X,Y) du SPRITE numéro N et le place à la
position (X,Y).
Les coordonnées d'un SPRITE sont des coordonnées "sur l'écran" dans le SCENE2D :


La première valeur est la position horizontale sur le SCENE2D comptée de gauche à droite.
La seconde coordonnée est la position verticale sur le SCENE2D comptée du haut vers le bas.
Les coordonnées (0,0) sont celles du coin en haut à gauche du SCENE2D.
SPRITE_X_POSITION N, X
Positionne en X le SPRITE numéro N.
SPRITE_Y_POSITION N, Y
Positionne en Y le SPRITE numéro N.
SPRITE_POSITION N, X, Y
Positionne en X et Y le SPRITE numéro N.
Gestion des intitulés (CAPTION)
Nous allons un peu jouer avec le titre de la fenêtre principale. Pour cela nous utiliserons les 2
commandes ce dessous :
CAPTION N, T
Définit le texte T comme l'intitulé de l'objet numéro N (N étant un objet de type
BUTTON, ALPHA, FORM, CHECK, OPTION ou SUB_MENU
CAPTION$(N)
Retourne l'intitulé de l'objet numéro N.
Exemple de code utilisé : CAPTION 0, "Source n°1 : Déplaçons un sprite de Pacman à l'écran"
Explications : Nous indiquons que nous voulons que le titre (l’intitulé) de la fenêtre principale
(toujours ce fameux FORM 0) soit "Source n°1 : Déplaçons un sprite de Pacman à l'écran"
Exemple de code utilisé : CAPTION 0, CAPTION$(0) + " - Exécution terminée"
Explications : Nous indiquons que nous voulons que le titre de la fenêtre principale (toujours ce
fameux FORM 0) soit son intitulé actuel (que nous récupérons grâce à CAPTION$(0)) suivi de la
chaîne de caractères «- Exécution terminée»
Boucle FOR…TO… / NEXT
Je ne fais que redonner la syntaxe ici, pour plus d’informations sur les boucles vous pouvez vous
référer à l’excellent article de Papydall sur les structures
FOR variable = Expression1 TO Expression2
Groupe d'Instructions
NEXT variable
Exécute "Groupe d'Instructions" pour variable variant de la valeur
Expression1 à la valeur Expression2
Un STEP est disponible pour la boucle FOR / NEXT: il définit
l'incrément de la variable.
Exemple de code utilisé : FOR I=-16 TO 16 STEP 0.02
NEXT I
Explications : Nous indiquons que nous voulons exécuter la boucle en utilisant la
variable I (qui doit avoir était créée (déclarée) avant) variant de la valeur -16 (valeur
de I lors du premier lancement) jusqu’à ce que I ait une valeur supérieure à 16 en
incrémentant I de 0.02 à chaque fois que l’on relance la boucle (après le NEXT I)
Les commandes d’attente (WAIT / PAUSE)
WAIT N
Pause de N millisecondes (0 < =N < =30000). Le programme est arrêté jusqu'à ce que le temps soit
écoulé. Aucun événement n'est pris en compte.
PAUSE N
Pause de N millisecondes (0 < =N < =30000). Le programme est arrêté jusqu'à ce que le temps soit
écoulé. Cependant, tous les traitements en attente (événements) sont effectués.
Code :
' Tutorial pour créer un Pacman
' Source n°1 : Piloter le Pacman à l'écran
DIM I
: ' Variable temporaire (compteur pour la boucle de déplacement)
HEIGHT 0,600 : WIDTH 0,800 : ' Définition de la hauteur et de la largeur de la fenêtre principale
CAPTION 0, "Source n°1 : Déplaçons un sprite de Pacman à l'écran"
SCENE2D 1
: ' Création d'un scene 2d
HEIGHT 1, HEIGHT(0)-38 : WIDTH 1,WIDTH(0)-16 : ' Le scene2D occupe toute la fenêtre
SPRITE 1
: ' Création du sprite (notez que la numérotation des sprites est indépendante)
DIM x,y : x=(WIDTH(1)-10)/2 : ' Définition de la position initiale du sprite au centre du SCENE2D
y=(HEIGHT(1)-10)/2 : SPRITE_POSITION 1,x,y
SPRITE_FILE_LOAD 1,"Source1_Pacman.BMP" : ' Chargement de l'image du pacman dans le sprite
FOR I=-16 TO 16 STEP 0.02 : ' Boucle générant un déplacement de sprite arbitraire pour la démo
x = x + COS(I)*(I/8) : y = y + SIN(I)*(I/8): SPRITE_POSITION 1,x,y : ' On calcule la nouvelle position
WAIT 10
: ' Après avoir affiché le sprite, on attend un peu
NEXT I
: ' Retourner en début de boucle pour faire la prochaine occurrence
CAPTION 0, CAPTION$(0) + " - Exécution terminée" : WAIT 800 : ' On affiche c’est terminé
CAPTION 0, "Au revoir !" : WAIT 1600 : ' On dit au revoir à l'utilisateur dans la barre de titre
TERMINATE
: ' FIN, on ferme le programme et la fenêtre
Partie 2 : Mise en place de quelques mécanismes supplémentaires
Nous n’allons pas utiliser beaucoup de nouvelles instructions dans cette seconde partie, nous pourrions
n’en voir aucune. Mais pour ne pas tout voir d’un coup, j’en ai quand même mis quelques une.
La taille de l’écran (SCREEN_X / SCREEN_Y)
Des variables système donnent les dimensions de l'écran en pixels:
SCREEN_X
SCREEN_Y
Retourne la largeur de l'écran en pixels.
Retourne la hauteur de l'écran en pixels.
MESSAGE
MESSAGE T
Cette commande permet de visualiser un texte dans une fenêtre à valider.
Remarque : le programme est arrêté pendant l'affichage de la fenêtre (il attend la réponse) et reprend
aussitôt que l'utilisateur ferme la fenêtre-message.
MESSAGE T
Visualise la ligne de texte T dans une fenêtre.
Exemple de code utilisé : MESSAGE "Démonstration terminée"+CHR$(10)+"Au revoir"
Explications : Nous demandons l’affichage d’une fenêtre dans laquelle sera écrit "Démonstration
terminée" sur la première ligne et « Au revoir » sur la seconde.
STR$
STR$(V)
retourne le string correspondant au nombre V
Exemple de code utilisé : MESSAGE$ = "Les dimensions sont : (" + STR$(Min_X%) + ";" + STR$(Min_Y%) + ")"
Explications : Nous demandons ici que la variable MESSAGE$ contienne la chaîne de caractères
composée des 5 éléments suivants :
 « Les dimensions sont : (»
 La conversion en chaîne de caractères de la valeur de la variable Min_X%
 «;»
 La conversion en chaîne de caractères de la valeur de la variable Min_X%
 «)»
Maintenant que nous avons vu quelques commandes complémentaires, intéressons nous à l’objet de
cette 2ème partie : adoptons quelques méthodes pour faciliter la réutilisation des sources, leur
compréhension et leur maintenance
Dans la première partie de ce tutorial, nous avons attribué directement des numéros aux objets.
C’est très simple et très facile à lire dans un petit programme.
Maintenant imaginons que le programme fasse 5000 lignes.
Vous avez déclaré beaucoup d’objets et vous les utilisez à différent endroit de votre programme.
Quand vous créez l’objet 5 par exemple, vous savez qu’il s’agit d’un objet de type EDIT, vous
l’utilisez sans problème. Plusieurs semaines après, vous reprenez votre programme et vous voulez
ajouter une fonction. Vous tombez sur une ligne ressemblant à MESSAGE$ = TEXT$(5).
A moins que vous ayez très bien commenté votre programme, il ne sera pas évident de savoir à quoi 5
fait référence.
De même si vous supprimez et rajoutez des objets, il vous faudra vite tenir un inventaire des objets
utilisés. Ceci est faisable, mais on peut se faciliter la vie en adoptant quelques petits « trucs »
Nous allons utiliser un mécanisme qui va numéroter les objets automatiquement et nous stockerons les
numéros d’objets dans des variables ayant des noms parlants.
On comprendra normalement par une simple lecture ce à quoi fait référence une ligne telle que celleci : MESSAGE$=TEXT$(SAISIE_NOM%)
Pour gérer les objets, nous avons besoin :
De créer un compteur d'objets :
DIM Num_Obj%
Au départ, il n'y a qu’un seul objet : la fenêtre principale qui porte le numéro d’objet 0. On initialise
donc notre compteur d’objet à 0 (C’est inutile normalement puisqu’une variable vaut 0 à sa création) :
Num_Obj% = 0
On créé une procédure que l’on appelle ici INC_OBJ qui va servir à incrémente le nombre d'objets
Num_Obj% créés :
SUB INC_OBJ()
Num_Obj% = Num_Obj%+1
END_SUB
Quand on créé un objet, on demande à incrémenter le compteur d’objet en appelant la procédure
INC_OBJ() et on lui affecte le compteur à une variable réservée à cet objet (Num_Scene2D% dans
l’exemple ci-dessous)
DIM Num_Scene2D% : INC_OBJ() : Num_Scene2D% = Num_Obj%
Après quand on veut utiliser l’objet on utilise la variable Num_Scene2D%, par exemple pour déclarer
l’objet, on utilisera : SCENE2D Num_Scene2D%
Dans le programme ci-dessous on utilise également cette méthode pour numéroter les sprites.
On est d’accord, dans cet exemple ça n’a pas de sens. C’est se compliquer la vie pour un sprite, mais
vous vous rendrez vite compte qu’on peut en utiliser beaucoup plus dans un programme…
Code :
' Tutorial pour créer un Pacman
' Source n°2 : Piloter le Pacman à l'écran + mécanismes de numérotation
DIM I : ' variable temporaire (compteur pour la boucle)
DIM MESSAGE$ : ' variable chaîne pour y stocker les messages
DIM X%, Y% : ' variable mémorisant les coordonnées du pacman
DIM BORDS_V%,BORDS_H% : BORDS_V% = 38 : BORDS_H% = 16 : ' Taille des bords de la fenêtre
' On créé 4 variables qui définiront les limites de déplacement de notre sprite
DIM Min_X%, Min_Y% : Min_X% = 0 : Min_Y%=0
DIM Max_X%, Max_Y% : Max_X% = WIDTH(0) : Max_Y% = HEIGHT(0)
CAPTION 0, "Source n°2 : Mise en place de quelques mécanismes de programmation"
MESSAGE$ = "Les dimensions de la fenêtre principale sont : (" + STR$(Min_X%) + ";" + STR$(Min_Y%) + ")"
MESSAGE$ = MESSAGE$ + " ; (" + STR$(Max_X%) + ";" + STR$(Max_Y%) + ")"
MESSAGE MESSAGE$
' On créé un compteur d'objets qui sera incrémenté par la procédure INC_OBJ
DIM Num_Obj% : Num_Obj% = 0 : ' Au départ, il n'y a que la fenêtre principale
' On créé un monde 2D et on lui affecte un numéro
DIM Num_Scene2D% : INC_OBJ() : Num_Scene2D% = Num_Obj%
SCENE2D Num_Scene2D% : WIDTH Num_Scene2D%,WIDTH(0)- BORDS_H% : HEIGHT Num_Scene2D
%,HEIGHT(0)- BORDS_V%
' Si l'on voulait charger une image de fond, on écrirait: FILE_LOAD Num_Scene2D%,"NomImage"
' On créé un compteur de sprites qui sera incrémenté par N_SPRITE
DIM Num_Sprite% : Num_Sprite% = 0 : ' Au départ, il n'y a pas de sprite
' On créé un sprite pour notre Pacman
DIM Num_Pacman%:N_SPRITE(): Num_Pacman% = Num_Sprite%
' On place le sprite au centre de l'écran et on le charge avec l'image
X% = Max_X%/2 : Y% = Max_Y%/2 : SPRITE_POSITION Num_Pacman%,X%,Y%
SPRITE_FILE_LOAD Num_Pacman%,"Source2_Pacman.BMP"
' Boucle de déplacement du sprite selon une courbe arbitraire
FOR I=-16 TO 16 STEP 0.04
X% = X% + COS(I)*(I/12) : Y% = Y% + SIN(I)*(I/12): SPRITE_POSITION 1,X%,Y%
WAIT 10
NEXT I
MESSAGE "Démonstration terminée"+CHR$(10)+"Au revoir"
WAIT 200
TERMINATE : ' Fin du programme principal
' -----------------------------------------------' PROCEDURES
' -----------------------------------------------' INC_OBJ incrémente le nombre d'objets Num_Obj% créés
SUB INC_OBJ()
Num_Obj% = Num_Obj%+1
END_SUB
' N_SPRITE incrémente le nombre d'objets Num_Sprite% créés
SUB N_SPRITE()
Num_Sprite% = Num_Sprite% + 1
SPRITE Num_Sprite%
END_SUB
Partie 3 : Utilisation d’une planche de sprites et contrôle du pacman au clavier
Cette troisième et dernière section de ce premier tutorial sur la création d’un Pacman va nous
permettre 2 choses :

Charger le sprite de Pacman depuis une image contenant ces différentes positions en fonction
de la direction dans laquelle il va.

Contrôler Pacman à l’aide du clavier
Charger le sprite de Pacman depuis une planche de sprites
On créé un objet PICTURE où l'on va charger l’image contenant les différentes tuiles (Tiles en
anglais). On peu appeler les différents sprites différemment, mais c’est une dénomination usuelle.
PICTURE N
Crée un objet PICTURE et lui affecte le numéro N. Un objet PICTURE est utilisé pour visualiser un
fichier bitmap BMP ou JPG (avec la commande FILE_LOAD).
Dans notre programme, on l’utilise pour charger l’image contenant les 4 positions que peut prendre le
Pacman en fonction de la direction dans laquelle il va.
PICTURE Num_Tuiles% : FILE_LOAD Num_Tuiles%,"Source2_Pacman.BMP"
Dans l’image, il y a une bordure de couleur d’1 pixel de large et les 4 tuiles font 20 pixels de haut et de
large.
Pour copier la tuile que l’on souhaite prendre pour le sprite, on créé une image temporaire
IMAGE Tuile
2D_IMAGE_COPY N, X1, Y1, X2, Y2
Capture la partie d'écran définie par les 2 points (X1,Y1) et (X2,Y2) dans
l'objet système IMAGE numéro N.
2D_IMAGE_PASTE N, X, Y
Recopie l'image contenue dans l'objet système IMAGE numéro N vers le
point (X,Y).
' On va copier le sprite de Pacman depuis la feuille de tuiles en 22,1 vers l'image temporaire
2D_IMAGE_COPY Tuile%,22,1,42,21
‘ Et on copie cette image dans le sprite de Pacman
SPRITE_IMAGE_LOAD Num_Pacman%,Tuile%
On chargera la bonne tuile en fonction de la direction du Pacman à chaque changement de direction
(géré dans la procédure : change_dir())
Contrôler le Pacman à l’aide du clavier
Tout d’abord nous allons réfléchir à ce que nous voulons obtenir : Au départ, Pacman est immobile
puis quand on appuie sur une touche, il part dans une direction jusqu’à ce que l’utilisateur lui donne
une nouvelle direction ou qu’il arrive à un bord de l’écran.
OK, donc on a un utilisateur qui a un moment va appuyer sur une touche et va rester appuyé un certain
temps. Cette action est détectable par Panoramic grâce à l’instruction ON_KEY_DOWN
ON_KEY_DOWN N,L
Exécute le sous programme à partir du libellé (LABEL) L quand l’utilisateur
presse une touche et que l’objet système N a le Focus (autrement dit quand c’est
cet objet qui est sélectionné)
Dans le sous programme de traitement appelé t1 par référence au sous programme de Bignono qui
avait été le premier à utiliser cette méthode, nous mettons juste une variable correspondant à la touche
enfoncée à 1 s’il s’agit d’une des touches qui nous intéresse (esc pour echap, tfg pour la Touche Flèche
Gauche, tfd pour la Touche Flèche droite, …).
Seules 5 touches sont gérées dans ce programme : La touche ‘ESC’ (code : 27) et les 4 flèches du pavé
directionnel.
Plutôt que de retenir tous les codes par cœur, nous allons déclarer une série de constantes cesc
correspondra à « Code de la Touche ESC » ; ctfg correspondra à « Code de la Touche Flèche
Gauche » , ctfd à celui de la touche de droite, etc …
Il faut aussi repasser les variables signalant que les touches sont enfoncées si elles ne le sont plus.
Pour cela, nous allons surveiller l’événement grâce à l’instruction ON_KEY_UP
ON_KEY_UP N,L
le sous programme à partir du libellé (LABEL) L quand l’utilisateur relache une
touche et que l’objet système N a le Focus (autrement dit quand c’est cet objet
qui est sélectionné)
Dans le sous programme de traitement appelé t2. Si l’une des 5 touches surveillées est relâchée alors
on remet sa variable à 0
Bon, c’est bien beau mais ce n’est pas juste en changeant la valeur d’une variable que Pacman va
bouger !!
Non, en effet, le déplacement est géré à l’intérieur du sous programme gérant les tours de jeu.
En effet, que le Pacman bouge ou non, il faut que le jeu ‘tourne’, quand nous aurons des fantômes, ils
n’attendront pas que l’utilisateur appuie sur une touche pour bouger.
On doit donc avoir un événement qui se déclenche à une fréquence définie pour déclencher les
différents mécanismes du jeu et mettre à jour l’affichage en conséquence. Dans Panoramic, cela se
gère en utilisant les TIMER dont voici les premières instructions permettant leur utilisation dans un
programme :
TIMER N
Crée un objet TIMER pour effectuer périodiquement un sous-programme et lui affecte le numéro N.
TIMER_INTERVAL N,T
Change la période de déclenchement de l'objet système TIMER désigné par son numéro N:
le TIMER se déclenchera toutes les T millisecondes.
ON_TIMER N,L Exécute le sous-programme à partir du label L quand le TIMER désigné par son numéro N arrive à
échéance (autrement dit : quand le délai est écoulé)
Dans notre programme on utilisera donc :
TIMER Num_timer% : TIMER_INTERVAL Num_timer%,50 : ON_TIMER Num_timer%,bouge
Dans cette ligne nous créons notre Timer référencé par Num_timer% puis nous luis définissons un
délai de 50 millisecondes et enfin nous lui indiquons que quand ce délai est atteint, il doit exécuter le
sous programme « Bouge »
Bien et que faisons nous dans ce programme « Bouge » et bien on arrête tout de suite le timer !
Curieux direz-vous peut être et bien non, je vous invite à consulter l’article de Klaus sur le sujet mais
si on n’arrête pas le timer et que pour une raison quelconque, le traitement de cet événement dure plus
longtemps que la durée du timer, nous aurions une accumulation de traitement à effectuer.
Je ne rentre pas plus dans le détail puisque l’article de Klaus l’explique très clairement.
Pour bloquer le timer, on utilise : TIMER_OFF Num_timer%
Après on lance une procédure qui va gérer le déplacement
Avant de rendre la main, on remet en route le timer avec la commande : TIMER_ON Num_timer%
Ca c’est typiquement une procédure gérée par un timer. On bloque le timer, on traite, on remet en
route le timer. C’est un mécanisme important. Si vous avez plusieurs timer qui tournent, pensez bien à
les gérer, le plus simple c’est d’en avoir qu’un seul, je trouve et de gérer avec un compteur si certain
événement ne doivent se produire que tout les 2, 3, 10 ou 100 déclenchement de timer, mais bon, ça
c’est mon avis. Tant que vous gérez bien et pensez à l’empilement des demandes en attente comme
l’explique Klaus dans son article, vous n’aurez pas de problème.
Bon et pour terminer, voyons la procédure de traitement (deplace). Que faisons nous dedans ?
D’abord, on regarde si l’utilisateur a appuyé sur <Echap> si tel est le cas, on termine et on ferme la
fenêtre par l’instruction Terminate. C’est violent, pas de confirmation, pas d’écran de fin. On s’en
fout, c’est un tutorial !! On verra ça plus tard…
Après on regarde si les touches sont toujours enfoncées. Si elles ne le sont plus, on efface le marqueur.
Ca sert pour pallier un éventuel raté de détection de « lâché » de touche. De petits mécanismes comme
ça permette de sécuriser les détections sur des événements rapides.
Après on teste si la touche enfoncée correspond à la direction actuelle. Si ce n’est pas le cas, on change
la direction (on en profite alors pour mettre à jour le sprite par celui correspondant à la nouvelle
direction). Ca vous apprendra a être aussi impatient qu’Ygeronimi, non mais !!
Après, on change les coordonnées du Pacman en fonction de sa direction. Quand il y aura les murs,
quand le Pacman sera bloqué par un mur la direction sera vide (« ») et les coordonnées ne seront donc
pas modifiées
On test ensuite si on a atteint les bords de notre fenêtre. Cette partie ne sert que pour notre tutorial.
Dans notre jeu, on utilisera une matrice de cases et on testera donc la valeur de cette case et par
sécurité, on s’assurera bien sûr que l’on ne dépasse pas les limites de cette matrice.
Voilà, on met à jour la position de notre sprite à l’écran et cette partie est finie !!
Voilà le dernier code de cette première partie de tutorial.
Vous trouverez la suite de notre Pacman dans le prochain numéro de
Code :
' Tutorial pour créer un Pacman
' Source n°3 : Piloter le Pacman à l'écran à l'aide du clavier
LABEL t1,t2,bouge
DIM esc,cesc : cesc=27 : ' * TOUCHE "ESC" ==> MET FIN AU PROGRAMME:... CASE 27 *
DIM tfg,ctfg : ctfg=37 : ' * FLÈCHE GAUCHE ==> ALLER À GAUCHE.......... CASE 37 *
DIM tfh,ctfh : ctfh=38 : ' * FLÈCHE HAUTE ==> ALLER EN HAUT............ CASE 38 *
DIM tfd,ctfd : ctfd=39 : ' * FLÈCHE DROITE ==> ALLER À DROITE.......... CASE 39 *
DIM tfb,ctfb : ctfb=40 : ' * FLÈCHE BASSE ==> ALLER EN BAS............. CASE 40 *
DIM DIR$ : ' Mémorise la direction actuelle (laisser vide au départ puisqu'on ne bouge pas)
DIM I : ' variable temporaire (compteur pour la boucle)
DIM X%, Y% : ' variable mémorisant les coordonnées du pacman
DIM Bords_V%,Bords_H% : Bords_V% = 38 : Bords_H% = 16 : ' Taille des bords de la fenêtre
' On créé 4 variables qui définiront les limites de déplacement de notre sprite
DIM Min_X%, Min_Y% : Min_X% = 0 : Min_Y%=0
DIM Max_X%, Max_Y% : Max_X% = WIDTH(0) : Max_Y% = HEIGHT(0)
CAPTION 0, "Source n°3 : Contrôler le pacman au clavier - Appuyez sur <echap> pour quitter"
' On créé un compteur d'objets qui sera incrémenté par la procedure _OBJ
DIM Num_Obj% : Num_Obj% = 0 : ' Au départ, il n'y a que la fenêtre principale
' On créé un monde 2D et on lui affecte un numéro
DIM Num_Scene2D% : INC_OBJ() : Num_Scene2D% = Num_Obj%
SCENE2D Num_Scene2D% : TOP Num_Scene2D%, -20 : LEFT Num_Scene2D%, -20
WIDTH Num_Scene2D%,WIDTH(0)- Bords_H% + 20 : HEIGHT Num_Scene2D%,HEIGHT(0)- Bords_V% + 20
' On créé une image où l'on va charger les tuiles
DIM Num_Tuiles% : INC_OBJ() : Num_Tuiles% = Num_Obj%
PICTURE Num_Tuiles% : FILE_LOAD Num_Tuiles%,"Source2_Pacman.BMP"
' On créé une image temporaire pour stocker une tuile depuis la feuille de tuiles
DIM Tuile% : INC_OBJ() : Tuile% = Num_Obj% : IMAGE Tuile%
' On créé un compteur de sprites qui sera incrémenté par N_SPRITE
DIM Num_Sprite% : Num_Sprite% = 0 : ' Au départ, il n'y a pas de sprite
' On créé un sprite pour notre Pacman
DIM Num_Pacman%:N_SPRITE(): Num_Pacman% = Num_Sprite%
' On place le sprite au centre de l'écran et on le charge avec l'image
X% = Max_X%/2 : Y% = Max_Y%/2 : SPRITE_POSITION Num_Pacman%,X%,Y%
' On va copier le sprite de Pacman depuis la feuille de tuile en (22;1) vers l'image temporaire
2D_TARGET_IS Num_Tuiles% : 2D_IMAGE_COPY Tuile%,22,1,42,21
‘ Et on copie cette image dans le sprite de Pacman
SPRITE_IMAGE_LOAD Num_Pacman%,Tuile%
' On créer un timer qui controlera les 'tours' de jeu
DIM Num_timer% : INC_OBJ() : Num_timer% = Num_Obj%
TIMER Num_timer%
TIMER_INTERVAL Num_timer%,50
ON_TIMER Num_timer%,bouge
' On gère l'événement appuie ou relache une touche
ON_KEY_DOWN 0,t1 : ON_KEY_UP 0,t2
END : ' Fin du programme principal
' PROCEDURES
' INC_OBJ incrémente le nombre d'objets Num_Obj% créés
SUB INC_OBJ()
Num_Obj% = Num_Obj%+1
END_SUB
' N_SPRITE incrémente le nombre d'objets Num_Sprite% créés
SUB N_SPRITE()
Num_Sprite% = Num_Sprite% + 1
SPRITE Num_Sprite%
END_SUB
SUB deplace()
IF esc=1 THEN TERMINATE
' Verifie que la touche est toujours appuyée
IF tfg=1 AND SCANCODE <> ctfg THEN tfg=0
IF tfd=1 AND SCANCODE <> ctfd THEN tfd=0
IF tfh=1 AND SCANCODE <> ctfh THEN tfh=0
IF tfb=1 AND SCANCODE <> ctfb THEN tfb=0
' Test si changement de direction
IF tfg=1 AND DIR$ <> "GAUCHE" THEN DIR$="GAUCHE" : change_dir()
IF tfd=1 AND DIR$ <> "DROITE" THEN DIR$="DROITE" : change_dir()
IF tfh=1 AND DIR$ <> "HAUT" THEN DIR$="HAUT" : change_dir()
IF tfb=1 AND DIR$ <> "BAS" THEN DIR$="BAS" : change_dir()
IF DIR$="GAUCHE" THEN X%=X%-5
IF DIR$="DROITE" THEN X%=X%+5
IF DIR$="HAUT" THEN Y%=Y%-5
IF DIR$="BAS" THEN Y%=Y%+5
IF X% > Max_X% - Bords_H% THEN X%=Max_X% - Bords_H%
IF X% < 20 THEN X%=20
IF Y% > Max_Y% - Bords_V% THEN Y%=Max_Y% - Bords_V%
IF Y% < 20 THEN Y%=20
SPRITE_POSITION 1,X%,Y%
END_SUB
SUB change_dir()
IF DIR$="GAUCHE" THEN 2D_IMAGE_COPY Tuile%,1,1,21,21
IF DIR$="DROITE" THEN 2D_IMAGE_COPY Tuile%,22,1,42,21
IF DIR$="HAUT" THEN 2D_IMAGE_COPY Tuile%,64,1,84,21
IF DIR$="BAS" THEN 2D_IMAGE_COPY Tuile%,43,1,63,21
SPRITE_IMAGE_LOAD Num_Pacman%,Tuile%
END_SUB
' SOUS-PROGRAMMES DE TRAITEMENT DES EVENEMENTS
bouge:
TIMER_OFF Num_timer%
deplace()
TIMER_ON Num_timer%
RETURN
t1:
IF KEY_DOWN_CODE=cesc THEN esc=1
IF KEY_DOWN_CODE=ctfg THEN tfg=1
IF KEY_DOWN_CODE=ctfh THEN tfh=1
IF KEY_DOWN_CODE=ctfd THEN tfd=1
IF KEY_DOWN_CODE=ctfb THEN tfb=1
RETURN
t2:
IF KEY_DOWN_CODE=cesc THEN esc=0
IF KEY_DOWN_CODE=ctfg THEN tfg=0
IF KEY_DOWN_CODE=ctfh THEN tfh=0
IF KEY_DOWN_CODE=ctfd THEN tfd=0
IF KEY_DOWN_CODE=ctfb THEN tfb=0
RETURN