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