You are on page 1of 480

ActionScript 3.

0 pour les jeux


Gary Rosenzweig

Couvre Flash CS3

L E

P R O G R A M M E U R

ActionScript 3.0
pour les jeux
Gary Rosenzweig

CampusPress a apport le plus grand soin la ralisation de ce livre an de vous fournir une information complte et able. Cependant, CampusPress nassume de responsabilits, ni pour son utilisation, ni pour les contrefaons de brevets ou atteintes aux droits de tierces personnes qui pourraient rsulter de cette utilisation. Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle. CampusPress ne pourra en aucun cas tre tenu pour responsable des prjudices ou dommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou programmes. Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs propritaires respectifs.

Publi par CampusPress 47 bis, rue des Vinaigriers 75010 PARIS Tl. : 01 72 74 90 00

Titre original : ActionScript 3.0 Game Programming University Traduit de lamricain par Patrick Fabre ISBN original : 978-0-7897-3702-1

Ralisation PAO : La B. Copyright 2008 by Que Publishing All rights Reserved. www.quepublishing.com

ISBN : 978-2-7440-4013-9 Copyright 2009 Pearson Education France Tous droits rservs

Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans le respect des modalits prvues larticle L. 122-10 dudit code. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.

Table des matires


Introduction . . . . . . . . . . . . . . . . . . . . .
Flash et le dveloppement de jeux . . . . . . . qui ce livre est-il destin ? . . . . . . . . . . . Que vous faut-il pour utiliser ce livre ? . . . Utiliser les jeux dexemple dans vos propres projets . . . . . . . . . . . . . . Ce que vous trouverez dans ce livre. . . . . . Le site Web FlashGameU.com . . . . . . . . . . .

1
1 2 3 4 4 5

Accder des donnes externes . . . . . . . . lments de jeu divers . . . . . . . . . . . . . . . .

77 80

CHAPITRE 3. Structure de jeu lmentaire : le Memory . . . . . . . . . . .


Placer les lments interactifs . . . . . . . . . . Jeu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Encapsuler le jeu . . . . . . . . . . . . . . . . . . . . Ajouter un score et un chronomtre . . . . . Ajouter des effets . . . . . . . . . . . . . . . . . . . Modier le jeu . . . . . . . . . . . . . . . . . . . . . .

91
93 104 112 116 123 131

CHAPITRE 1. Utiliser Flash et ActionScript 3.0 . . . . . . . . . . . . . . . .


Quest-ce quActionScript 3.0 ? . . . . . . . . Crer un programme ActionScript simple . . . Travailler avec Flash CS3 . . . . . . . . . . . . . crire et modier du code ActionScript. . . Stratgies de programmation des jeux ActionScript . . . . . . . . . . . . . . . . . . . . . . . Notions lmentaires du langage ActionScript. . . . . . . . . . . . . . . Test et dbogage . . . . . . . . . . . . . . . . . . . . Publier votre jeu . . . . . . . . . . . . . . . . . . . . Chek-list de la programmation de jeux ActionScript . . . . . . . . . . . . . . . . .

7
8 9 17 21 24 28 32 36 40

CHAPITRE 4. Jeux crbraux : Simon et dduction . . . . . . . . . . . . . . . 133


Tableaux et objets de donnes . . . . . . . . . . 134 Jeu de Simon . . . . . . . . . . . . . . . . . . . . . . . 138 Jeu de dduction. . . . . . . . . . . . . . . . . . . . . 151

CHAPITRE 5. Animation de jeu : jeux de tir et de rebond . . . . . . . . . . . . 169


Animation de jeu . . . . . . . . . . . . . . . . . . . . 170 Air Raid . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Casse-brique . . . . . . . . . . . . . . . . . . . . . . . 195

CHAPITRE 2. Composants de jeu ActionScript . . . . . . . . . . . . . . .


Crer des objets visuels . . . . . . . . . . . . . . . Accepter les entres de lutilisateur . . . . . Crer une animation . . . . . . . . . . . . . . . . . Programmer linteraction avec lutilisateur . .

45
46 61 66 72

CHAPITRE 6. Puzzles dimages et puzzles coulissants . . . . . . . . . . . . . . 211


Manipuler des images bitmap . . . . . . . . . . Jeu de puzzle coulissant . . . . . . . . . . . . . . . Puzzle classique . . . . . . . . . . . . . . . . . . . . . Chargement et dcoupage de limage . . . . 212 217 231 234

IV

ActionScript 3.0 pour les jeux

CHAPITRE 7. Direction et mouvement : astrodes . . . . . . . . . . . . . . . . . . . . . . . 245


Utiliser Math pour faire pivoter et dplacer des objets . . . . . . . . . . . . . . . . Utiliser Math pour faire pivoter et dplacer des objets . . . . . . . . . . . . . . . . Air Raid II . . . . . . . . . . . . . . . . . . . . . . . . . Space Rocks . . . . . . . . . . . . . . . . . . . . . . . . Astrodes . . . . . . . . . . . . . . . . . . . . . . . . . 246 249 255 262 279

CHAPITRE 10. Questions et rponses : quiz et jeux de culture gnrale . . . . . 357


Stocker et retrouver des donnes de jeu. . . Quiz de culture gnrale . . . . . . . . . . . . . . Quiz version Deluxe . . . . . . . . . . . . . . . . . Quiz dimages . . . . . . . . . . . . . . . . . . . . . . 358 363 375 385

CHAPITRE 11. Jeux daction : jeux de plate-forme . . . . . . . . . . . . . . . 393


Conception du jeu . . . . . . . . . . . . . . . . . . . 394 Crer la classe . . . . . . . . . . . . . . . . . . . . . . 403 Modier le jeu . . . . . . . . . . . . . . . . . . . . . . 425

CHAPITRE 8. Les casual games : Match Three . . . . . . . . . . . . . . . . . . . . . 291


Classe rutilisable : Point Bursts . . . . . . . . 292 Match Three . . . . . . . . . . . . . . . . . . . . . . . . 301

CHAPITRE 12. Jeux de mondes : jeux de conduite et dexploration . . . . 427


Crer un jeu de conduite en vue arienne . . . . . . . . . . . . . . . . . . . . . 428 Crer un jeu de course . . . . . . . . . . . . . . . . 451

CHAPITRE 9. Jeux de mots : pendu et mots mls . . . . . . . . . . . . . . . 323


Chanes et champs texte . . . . . . . . . . . . . . 324 Pendu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 Mots mls . . . . . . . . . . . . . . . . . . . . . . . . 340

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . 465

Lauteur
Enfant, Gary Rosenzweig est autoris jouer aux jeux vido autant quil le souhaite, pourvu quil ait dabord termin ses devoirs. Il adore jouer Adventure, Asteroids, Pitfall, Raiders of the Lost Ark et mme lpouvantable jeu dE.T. 13 ans, en 1983, il reoit de sa grand-mre un nouveau TRS-80 Model III. Il apprend immdiatement programmer. Puis cre des jeux. Il conoit des jeux daventure et de rle avec du texte, puis des jeux darcade. On lui permet de passer ses nuits crer des jeux, pourvu quil ait dabord fait ses devoirs. Au lyce, Gary samuse presque quand il le veut avec des ordinateurs Apple II, mais il commence toujours par faire ses devoirs. Il cre des simulateurs spatiaux, des programmes de tableur et des jeux. Gary part tudier linformatique luniversit de Drexel. On lui fait savoir quavec ce diplme il peut tre embauch comme programmeur dans nimporte quelle entreprise de logiciels pour entreprises. Mais lui veut crer des jeux, en guise de passe-temps, une fois son travail fait. Aprs un dtour qui lui vaut un diplme de Master en journalisme et en communication de luniversit de Caroline du Nord, Chapel Hill, Gary prend un travail qui lui permet de crer des jeux pour les enfants avec le logiciel Director, de Macromedia. Puis survient Internet. Rapidement aprs apparat Shockwave, qui permet de lire du contenu Director dans des pages Web. Gary commence crer ses propres jeux pour son site Web le soir, une fois son travail fait. En 1996, Gary lance sa propre socit, CleverMedia, an de produire des jeux pour le Web. Il cre rapidement des jeux Shockwave et Flash avec certaines des personnes les plus cratives quil ait jamais rencontres. CleverMedia et ses sites prennent de lampleur au l des ans, jusqu devenir la plus grande collection de jeux Web dune mme entreprise. Gary cre plus de trois cents jeux au cours des douze dernires annes, dont la plupart se trouvent sur le site principal de CleverMedia, www.GameScene.com. Gary aime aussi partager ce quil sait. Ses sites http://FlashGameU.com, www.Director-Online.com et www.DeveloperDispatch.com contiennent des informations pour les autres dveloppeurs. Il crit de nombreux livres, dont Macromedia Flash MX ActionScript for Fun & Games, Special Edition Using Director MX et Advanced Lingo for Games. Gary a crit ce livre en grande partie pendant ses soires et ses week-ends, une fois son travail fait. Gary vit Denver, dans le Colorado, avec sa femme, Debby, et sa lle, Luna. Debby et Gary possdent galement la librairie Attic Bookstore, une choppe incongrue de livres doccasion Englewood, dans le Colorado. Luna na que 5 ans mais joue dj des jeux sur son ordinateur Macintosh. On ly autorise mais, bien sr, une fois ses devoirs faits.

Introduction

Voici un moment bien choisi pour devenir un dveloppeur de jeux Flash. Aujourdhui, il nexiste pas de meilleur outil de dveloppement pour les jeux de petite et de moyenne taille. Flash CS3 Professional (aussi appel Flash 9) est rapide, puissant et trs simple dusage pour les projets de dveloppement. La cl de ce succs tient ActionScript 3.0, lexcellent nouveau langage de programmation livr dans la dernire version de Flash. ActionScript 1.0 et 2.0 se sont souvent rvls frustrants pour les dveloppeurs de jeux. Ils ntaient pas assez rapides pour la ralisation des tches essentielles, et dtranges bogues ou des comportements inattendus venaient souvent compliquer la production. ActionScript 3.0 est dun tout autre acabit. Il permet de dvelopper des programmes rapidement et sans effort. Tout fonctionne et fonctionne bien. La vitesse dActionScript 3.0 permet en outre dimplmenter des solutions exactement comme on les a imagines. Ce livre doit devenir votre guide pour le dveloppement des jeux Flash. Jespre que vous apprcierez autant dapprendre en lisant ces pages que jai pris plaisir les crire.

Flash et le dveloppement de jeux


En octobre 1995, jtais trs excit par mon avenir en tant que dveloppeur de jeux. Macromedia venait de lancer Shockwave et je dcouvrais quil sagissait dun moyen de dvelopper des jeux que je pourrais distribuer moi-mme sur le Web.

ActionScript 3.0 pour les jeux

Je nai retrouv un tel sentiment dexcitation concernant le dveloppement des jeux que deux fois depuis la sortie du premier Shockwave. La premire fut la sortie de Shockwave 3D. La seconde, lors de la sortie dActionScript 3.0. Cela fait un certain temps que les jeux Flash ont fait leur entre sur le devant de la scne, mais ils ny ont jamais gur que comme une sorte de succdan des jeux Shockwave. Shockwave tait plus rapide, plus puissant et proposait mme des fonctionnalits 3D. Avec ActionScript 3.0, Flash atteint la puissance de Shockwave et la dpasse mme sur certains points. Par exemple, le lecteur Flash 9 est dj disponible sur 80 % des ordinateurs qui surfent sur le Web. Dici ce que vous lisiez ce livre, la plupart des lecteurs Flash 8 auront t mis jour avec la version 9 et nous nous rapprocherons dun taux effectif de 100 %. Le fait de savoir que Flash 9 est presque aussi rpandu que les navigateurs Web eux-mmes ouvre une tout autre dimension pour les dveloppeurs de jeux Flash. Flash 9 sexcute mme sur les ordinateurs Linux. Les anciennes versions de Flash sexcutent sur les consoles de TV Web, les consoles de jeu comme la Wii et mme les priphriques portables tels que les smartphones ou la PlayStation Portable. Le lecteur Flash 9 et ActionScript 3.0 niront dailleurs par tre disponibles sur ces types de priphriques galement. Vous pouvez dvelopper des versions autonomes ou des versions Web de vos jeux avec Flash. Des logiciels tiers vous permettent dtendre les jeux autonomes an de les transformer en de vritables applications. Flash constitue avec ActionScript 3.0 un excellent moyen de crer des jeux de petite et de moyenne taille.

qui ce livre est-il destin ?


Ce livre est destin tous ceux qui utilisent Flash pour dvelopper des jeux. Tous les dveloppeurs nutiliseront cependant pas ce livre de la mme manire. Ceux qui dbutent avec Flash et la programmation pourront en faire leur seconde tape aprs une premire familiarisation avec les notions de base de la programmation. Un dbutant motiv peut utiliser ce livre pour apprendre le langage ActionScript 3.0 de toutes pices. Si vous possdez dj une exprience en programmation avec ActionScript 1.0 ou 2.0, vous pourrez utiliser ce livre pour vous mettre la page avec ActionScript 3.0. Il est nanmoins prfrable doublier lessentiel de ce que vous avez appris avec les prcdentes versions du langage. ActionScript 3.0 est considrablement diffrent. Je considre mme pour ma part quil sagit dun langage de programmation entirement nouveau. Bon nombre dutilisateurs Flash connaissent dj les rudiments de lanimation et de la programmation mais souhaitent maintenant dvelopper des jeux. Voici le premier public cibl par ce livre.

Introduction

Si vous tes non pas programmeur mais concepteur, illustrateur ou animateur, vous pourrez utiliser les exemples de ce livre comme structure pour vos propres jeux. Autrement dit, vous pourrez vous contenter de remplacer les graphismes dans les chiers source dexemple. De la mme manire, si vous tes dj un programmeur ActionScript 3.0 averti, vous dcouvrirez dans ce livre une bibliothque de code dans laquelle vous pourrez puiser pour vos propres jeux. Inutile de rinventer la roue.

Que vous faut-il pour utiliser ce livre ?


La plupart des lecteurs devront avoir une exprience pralable dans lutilisation de Flash et en programmation pour tirer le meilleur parti de ce livre. Vous devrez aussi possder les bons outils.

Connaissances requises
Les lecteurs doivent tre familiariss avec lenvironnement de Flash CS3. Si vous dcouvrez Flash, commencez par parcourir le Guide de lutilisateur Flash livr avec le logiciel. Dans Flash, choisissez Aide > Aide Flash ou appuyez sur F1. Il peut aussi tre utile de se procurer un livre pour les dbutants ou de consulter des didacticiels en ligne. Ce livre nest pas destin aux programmeurs dbutants, moins que vous ne cherchiez utiliser les exemples en y insrant vos propres graphismes. Vous devez donc dj avoir une certaine exprience en programmation, que ce soit avec ActionScript 1.0, 2.0 ou 3.0, JavaScript, Java, Lingo, Perl, PHP, C++ ou nimporte quel autre langage de programmation structur. ActionScript 3.0 nest pas difcile comprendre si vous avez lhabitude des boucles, des instructions conditionnelles et des fonctions. Le Chapitre 1 propose mme une introduction la syntaxe de base dActionScript 3.0. Si vous tes programmeur mais que vous nayez jamais utilis Flash auparavant, lisez les parties du Guide de lutilisateur qui concernent linterface Flash et les techniques de dessin et danimation lmentaires.

Applications logicielles
Vous aurez videmment besoin de Flash CS3 Professional ou dune version ultrieure. Flash 8 Studio, la prcdente version de Flash, nutilise pas ActionScript 3.0 et ne peut donc tre utilise avec ce livre. Flash CS3 est virtuellement identique sur Mac et sous Windows. Les captures dcran de ce livre, quelles proviennent de la version Mac ou Windows de Flash, devraient donc ressembler en tous points ce que vous obtiendrez sur votre propre ordinateur. Les futures versions de Flash continueront selon toute vraisemblance utiliser ActionScript 3.0 comme langage de programmation principal. Certains des choix de menu et des raccourcis clavier pourraient changer, mais vous devriez malgr tout pouvoir utiliser ce livre. Il peut tre utile dans ce cas de rgler vos paramtres de publication en slectionnant le lecteur Flash 9 et ActionScript 3.0 pour assurer une compatibilit maximale.

ActionScript 3.0 pour les jeux

Fichiers source
Vous aurez galement besoin des chiers source de ce livre. Consultez la n de lintroduction pour plus dinformations sur la manire de les acqurir.

Utiliser les jeux dexemple dans vos propres projets


Ce livre inclut seize jeux complets, dont de petits bijoux comme Match Three, un jeu de plate-forme dlant et un jeu de mots mls. On me pose souvent la question : "Est-ce que je peux utiliser ces jeux dans mon projet ?" La rponse est oui, pour autant que vous les modiiez an de vous les approprier, par exemple en adaptant les graphismes, en changeant les modalits de jeu ou en modiant dautres lments du contenu. Ne postez pas les jeux en ltat sur votre site Web. Il nest pas non plus tolr que vous publiiez le code source ou les listings du code de ce livre an de les mettre la disposition du public. Lorsque vous utiliserez ces jeux dans vos projets, ne faites pas comme sil sagissait entirement de votre propre travail. Ce ne serait pas professionnel. Merci de mentionner ce livre en proposant un lien vers http://ashgameu.com. En revanche, si vous nutilisez quune petite portion de code ou si vous utilisez un jeu comme structure de base pour llaboration dun jeu compltement diffrent, il nest pas ncessaire dajouter de mention particulire. Tout nest nalement quaffaire de bon sens et de courtoisie. Je vous en remercie davance.

Ce que vous trouverez dans ce livre


Le Chapitre 1, "Utiliser Flash et ActionScript 3.0", introduit ActionScript 3.0 et certains concepts lmentaires comme les stratgies de programmation de jeux et une check-list pour vous aider dvelopper vos jeux avec Flash CS3. Le Chapitre 2, "lments de jeu ActionScript", prsente une srie de courts fragments de code et de fonctions permettant par exemple de crer des champs texte, de dessiner des formes et de lire des sons. Il sagit dune bibliothque de code utile et pratique que nous utiliserons dans le reste du livre et que vous pourrez utiliser dans vos propres projets. Les Chapitres 3 12 contiennent chacun un ou plusieurs jeux complets. Le texte des chapitres vous guide lors du dveloppement du code du jeu, en vous permettant de le reproduire par vous-mme si vous le souhaitez. Vous pouvez aussi utiliser les chiers source et en consulter directement le code nal.

Introduction

Le Chapitre 3, "Structure de jeu lmentaire : un jeu de Memory", est un peu diffrent du reste du livre. Au lieu dexaminer le code dun jeu ni, il construit le jeu en dix tapes, en produisant une animation Flash et un chier de code source chaque tape. Il sagit dun excellent moyen dapprendre construire des jeux Flash. Lessentiel du reste des chapitres introduit un sujet spcial avant de commencer un nouveau jeu. Par exemple, le Chapitre 4 commence par une section "Tableaux et objets de donnes". Le contenu de ce livre ne se limite pas aux pages que vous tenez entre vos mains. Il reste bien des choses dcouvrir en ligne.

Le site Web FlashGameU.com


Le site FlashGameU.com est le site Web daccompagnement de ce livre (en anglais). Vous pouvez vous y rendre pour trouver les chiers source, les mises jour, le nouveau contenu, un forum de dveloppement de jeux Flash et, enn, mon blog et mon podcast consacrs au dveloppement de jeux avec Flash. Les chiers source du livre sont organiss par chapitre puis diviss en archives pour chaque jeu. Un lien est propos pour tlcharger les chiers dans la page principale de FlashGameU.com. Sur le site FlashGameU.com, vous trouverez galement un blog (en anglais) sur lequel je poste le nouveau contenu et tente de rpondre aux questions des lecteurs. Si vous avez une question concernant ce livre ou le dveloppement des jeux Flash en gnral, posez-la sur le forum ou directement sur mon blog. trs bientt !

1
Utiliser Flash et ActionScript 3.0
Au sommaire de ce chapitre

Qu'est-ce qu'ActionScript 3.0 ? Crer un programme ActionScript simple Travailler avec Flash CS3 crire et diter du code ActionScript Stratgies de programmation de jeux ActionScript Concepts ActionScript lmentaires Test et dbogage Publier votre jeu Check-list de programmation des jeux ActionScript

ActionScript 3.0 pour les jeux

ActionScript est un langage de programmation parfaitement adapt la cration de jeux. Il est facile apprendre, rapide dvelopper et trs puissant. Nous commencerons par examiner ActionScript 3.0 et lenvironnement de cration Flash CS3. Ensuite, nous construirons quelques programmes trs simples an de nous familiariser avec cette nouvelle version dActionScript.

Quest-ce quActionScript 3.0 ?


ActionScript 3.0 a t introduit en 2006 la sortie de Flex 2. Comme Flash, Flex permet aux dveloppeurs de crer des applications qui utilisent le lecteur Flash Player. Flash propose cependant pour le dveloppement des applications une interface plus visuelle qui convient particulirement mieux au dveloppement des jeux. ActionScript a t introduit en 1996 la sortie de Flash 4. Le langage ne sappelait pas encore ActionScript et il ntait pas encore possible de taper du code. Il fallait choisir des instructions parmi une srie de menus droulants. En 2000, Flash 5 a considrablement amlior les choses grce lintroduction formelle dActionScript 1.0. Ce langage de script incluait tous les lments dernier cri des autres langages de dveloppement Web, comme le Lingo du logiciel Director de Macromedia et le Java de Sun. Il tait cependant trs limit en termes de vitesse et de puissance. Flash MX 2004, aussi appel Flash 7, introduisit ActionScript 2.0, une version bien plus puissante du langage qui facilitait la cration de programmes orients objet. Cette mouture sapparentait plus ECMA Script, un standard des langages de programmation dvelopp par lEuropean Computer Manufacturers Association. JavaScript, le langage de programmation utilis dans les navigateurs, est galement labor partir dECMA Script.

Le lecteur Flash Player 9 intgre deux interprteurs de code spars. Le premier est destin au contenu plus ancien et interprte le code ActionScript 1.0/2.0. Le second est uninterprteur plus rapide qui fonctionne avec ActionScript 3.0. Vous obtiendrez de meilleures performances dans vos jeux si vous nutilisez que du code ActionScript 3.0.

ActionScript 3.0 est laboutissement de longues annes de dveloppement. chaque nouvelle version du programme Flash, les dveloppeurs lui ont fait atteindre de nouvelles limites. La dernire version ce jour tient compte de lusage que les dveloppeurs font de Flash aujourdhui et corrige les faiblesses de la prcdente variante du langage.

Chapitre 1

Utiliser Flash et ActionScript 3.0

Nous disposons maintenant dun excellent environnement de dveloppement pour la cration des jeux en deux dimensions. Vous verrez que lune de ses principales forces tient sa capacit laborer des jeux parfaitement oprationnels avec trs peu de code.

Flash CS3 Professional correspond en fait Flash 9. Adobe a regroup ensemble les versions de diffrents composants logiciels comme Flash, Photoshop, Illustrator et Dreamweaver dans la solution "CS3". Le numro de version technique de Flash dans CS3 est Flash 9. On peut donc aussi bien faire rfrence Flash 9 qu Flash CS3. Le moteur de lecture qui est galement utilis par Flex est quant lui appel Flash Player 9 uniquement.

Crer un programme ActionScript simple


Codes sources http://ashgameu.com A3GPU01_HelloWorld.zip Lors de lintroduction dun nouveau langage de programmation, la tradition veut que lon commence par des programmes Hello World. Lide consiste crire un programme simple qui se contente dafcher les mots Hello World lcran.

Le programme Hello World remonte 1974, lorsquil fut inclus dans un document didacticiel interne de Bell Labs. Cest le premier programme que jai appris programmer en minstallant devant un terminal PDP-11 lcole la n des annes 1970. Presque tous les livres de programmation pour dbutants commencent par un exemple Hello World.

Utilisation simple de trace


Une version simple du programme Hello World peut tre cre en utilisant la fonction trace dans un script du scnario principal. trace se contente dafcher du texte dans le panneau Sortie de Flash. Pour crer une nouvelle animation Flash, choisissez Fichier > Nouveau dans la barre des menus. La fentre Nouveau document apparat (voir Figure 1.1).

10

ActionScript 3.0 pour les jeux

Figure 1.1
Choisissez Fichier Flash (AS 3.0) pour crer une nouvelle animation Flash.

Lorsque vous cliquez sur le bouton OK, vous accdez une nouvelle animation Flash intitule Sans nom-1. Cette animation safche sous la forme dune fentre Document Flash (voir Figure 1.2).
Figure 1.2
La fentre Document Flash inclut un scnario et une zone de travail de scne.

Chapitre 1

Utiliser Flash et ActionScript 3.0

11

La partie suprieure de la fentre Document inclut un scnario, avec des images dont la premire porte le numro 1 et qui stendent vers la droite. La Figure 1.2 en rvle un peu plus de 65, mais ce nombre dpend de la taille de la fentre. Le nombre dimages peut tre aussi important que le requiert lanimateur mais, pour la programmation de nos jeux, nous nen utiliserons gnralement que quelques-unes. Le scnario peut contenir un ou plusieurs calques. Par dfaut, il nen existe quun, nomm Calque 1 dans la fentre Document. Dans le Calque 1 apparat une unique image-cl reprsente par un rectangle marqu dun petit cercle sous le numro dimage 1.

Le terme image-cl est un terme danimation. Si nous nous occupions danimer des lments dans Flash au lieu de les programmer, nous ne cesserions dutiliser des images-cls. Limagecl dsigne un point du scnario o les positions dun ou de plusieurs des lments anims sont xes de manire spcique. Entre les images-cls, les lments changent de position. Par exemple, si une image-cl limage 1 contient un lment gauche de lcran et une autre limage 9 contient le mme lment droite de lcran, vous verrez llment au milieu de lcran entre ces images-cls, limage 5. Nous nutiliserons pas dimage-cl pour crer des animations mais le ferons pour placer des lments lcran dans diffrents modes : Intro, Jeu ou Fin de partie.

Vous pouvez placer un script dans nimporte quelle image-cl de nimporte quel calque du scnario. Pour cela, slectionnez limage-cl, choisissez le menu Fentre et slectionnez Actions. Le panneau Actions safche (voir Figure 1.3). Il est possible quil possde une autre apparence sur votre cran, car il peut tre personnalis de nombreuses manires, notamment en afchant un ensemble complet de commandes et de fonctions ActionScript dans un menu gauche. Le panneau Actions est une simple fentre de saisie de texte. Il est cependant capable de bien des choses et peut par exemple vous aider formater votre code. Nous nutiliserons pas souvent ce panneau dans ce livre, car lessentiel de notre code sera plac dans des classes externes. Pour crer ce simple programme Hello World, tapez le texte suivant dans le panneau Actions :
trace("Hello World");

Voil tout. Vous venez de crer votre premier programme ActionScript 3.0. Pour le tester, choisissez Contrle > Tester lanimation ou tapez le raccourci Ctrl +Entre. Si vous navez pas vous-mme cr lanimation, ouvrez HelloWorld1.a et utilisez ce chier pour le test. prsent, examinez le panneau Sortie. Celui-ci safche mme sil tait auparavant ferm. Comme il est souvent petit, il se peut toutefois quil apparaisse dans un coin de lcran sans que vous ne le remarquiez. La Figure 1.4 montre quoi il devrait ressembler prsent.

12

ActionScript 3.0 pour les jeux

Figure 1.3
Le panneau Actions peut aussi tre afch laide du raccourci clavier a + 9 (Windows) ou a + 9 (Mac).

Figure 1.4
Le panneau Sortie prsente le rsultat de lappel de la fonction trace.

Si ce programme Hello World a techniquement pour effet dafcher la chane "Hello World", il ne le fait que lorsque vous testez lanimation dans Flash 9. Si vous incorporiez cette animation dans un navigateur, vous ne verriez rien lcran. Quelques efforts supplmentaires sont ainsi ncessaires pour crer un vritable programme Hello World.

Crer une sortie cran


Pour que les mots Hello World safchent lcran, il nous faut plus dune ligne de code. En ralit, il en faut trois. La premire crera une nouvelle zone de texte afcher lcran que lon appelle un champ texte. Il sagit dun conteneur pour du texte. La deuxime ligne placera les mots Hello World dans ce champ texte. La troisime ajoutera ce champ la scne. La scne est la zone dafchage des animations Flash. Vous pouvez disposer les lments dans la scne pendant que vous crez une animation. la lecture de lanimation, cest la scne que voit lutilisateur.

Chapitre 1

Utiliser Flash et ActionScript 3.0

13

Avec ActionScript 3.0, le fait de crer des objets tels quun champ texte ne les ajoute pas la scne. Cette opration doit tre effectue par vos soins. Ce principe de fonctionnement se rvlera utile par la suite lorsque vous souhaiterez regrouper des objets sans les placer tous directement sur la scne.

Dans ActionScript 3.0, tous les lments visuels correspondent des types dobjets dafchage. Il peut sagir de champs texte, dlments graphiques, de boutons ou mme de composants dinterface utilisateur (par exemple des menus droulants). Les objets dafchage peuvent galement tre des collections dautres objets dafchage. Par exemple, un objet dafchage peut contenir toutes les pices dun jeu dchecs et lchiquier, gurer dans un autre objet dafchage situ en dessous. La scne elle-mme est un objet dafchage ; il sagit en fait dun objet dafchage appel clip.

Voici les trois lignes de code de notre nouveau programme Hello World. Elles remplacent la ligne de code de limage 1 du scnario de lexemple prcdent :
var myText:TextField = new TextField(); myText.text = Hello World; addChild(myText);

Le code cre une variable nomme myText de type TextField. Il attribue ensuite la valeur "Hello World" la proprit text de ce champ texte avant de lajouter comme enfant lobjet dafchage qui correspond la scne.

Le mot-cl var avant la premire utilisation de la variable myText indique au compilateur que nous allons crer une variable nomme myText. Le signe deux points et le type TextField indiquent au compilateur le type de valeur que cette variable contiendra (dans le cas prsent, une rfrence un champ texte).

Ce programme produit un tout petit "Hello World" dans la police serif par dfaut tout en haut gauche de lcran. Choisissez Contrle > Tester lanimation pour le vrier par vous-mme. Le chier source est HelloWorld2.a. La Figure 1.5 prsente le champ texte que nous venons de crer. Le texte apparat en haut gauche et safche avec cette police particulire parce que nous navons dni aucune autre proprit du champ texte. Lorsque nous en aurons appris un peu plus, nous pourrons choisir lemplacement du texte, sa taille et sa police.

14

ActionScript 3.0 pour les jeux

Figure 1.5
Lcran afche un petit "Hello World" en haut gauche.

Notre premire classe ActionScript 3.0


Nous nutiliserons pas de script dans le scnario moins que nous nayons quelque chose de spcique raliser dans une image donne du scnario. Pour lessentiel, notre code se trouvera plac dans des chiers de classe ActionScript externe. Recrons donc notre programme Hello World sous forme de classe externe.

Le terme classe est un autre moyen de faire rfrence un objet Flash, que ce soit un lment graphique ou lanimation elle-mme. Nous ferons aussi souvent rfrence des classes pour dsigner la portion de code dun objet. Vous aurez ainsi une animation et la classe de cette animation. Cette dernire dnira les donnes associes lanimation et les fonctions quelle sera susceptible de raliser.

Pour crer un chier ActionScript externe, choisissez Fichier > Nouveau et slectionnez Fichier ActionScript. Une nouvelle fentre Document ActionScript souvre et vient occuper le mme espace que la fentre Document de lanimation Flash. Au lieu dun scnario et dune scne, seule une grande zone ddition de texte apparat (voir Figure 1.6).

Chapitre 1

Utiliser Flash et ActionScript 3.0

15

Figure 1.6
Le document ActionScript contient un programme Hello World trs simple.

Comme vous pouvez le voir la Figure 1.6, ce programme est bien plus long que le programme Hello World de trois lignes que nous avons cr prcdemment. Voyons ce que ralise chacune des parties du code. Le chier de classe commence par dclarer quil sagit dun paquetage contenant une classe. Ensuite, il dnit les parties dActionScript requises dans le programme. Dans le cas prsent, nous devons afcher des objets sur la scne et crer un champ texte. Pour cela, nous devons utiliser les classes ash.display et ash.text :
package { import ash.display.*; import ash.text.*;

Vous apprendrez rapidement quelles classes de bibliothque vous devez importer au dbut de vos programmes. Il ne sagit l que de deux des bibliothques parmi la multitude que nous utiliserons dans ce livre. Pour les fonctions ActionScript plus inhabituelles, vous pourrez toujours examiner lentre de la fonction correspondante dans lAide Flash 9 an de voir quelle bibliothque de classes importer.

16

ActionScript 3.0 pour les jeux

La ligne de code suivante correspond la dnition de la classe. Ici, il doit sagir dune classe publique, ce qui signie quil est possible dy accder depuis lanimation principale. Le nom de la classe sera HelloWorld3, ce qui doit correspondre au nom du chier, qui est HelloWorld3.as. Cette classe tend MovieClip, ce qui signie quelle fonctionnera avec un clip (dans le cas prsent, la scne elle-mme) :
public class HelloWorld3 extends MovieClip {

La classe contient une unique fonction, HelloWorld3, dont le nom correspond prcisment celui de la classe. Lorsquune fonction porte le mme nom que la classe, elle est excute immdiatement quand la classe est initialise. On appelle cette fonction la fonction constructeur. Dans le cas prsent, la classe est attache lanimation, de sorte quelle sexcute ds que lanimation est initialise. Dans la fonction se trouvent les trois mmes lignes de code que nous avons utilises dans lexemple prcdent :
public function HelloWorld3() { var myText:TextField = new TextField(); myText.text = "Hello World!"; addChild(myText); } } }

Pour que ce code fonctionne dans une animation, vous devez crer une nouvelle animation. Lexemple est appel HelloWorld3.a. Cette animation na rien besoin dinclure dans le scnario, mais elle doit se voir associer une classe de document. Celle-ci indique le chier ActionScript qui contrle lanimation. Pour dnir une classe de document, ouvrez le panneau Proprits en choisissant Fentre > Proprits > Proprits. Flash afche le panneau prsent la Figure 1.7. Ensuite, tapez le nom de classe HelloWorld3 dans le champ Classe du document.
Figure 1.7
La classe du document de cette animation est HelloWorld3.

prsent, lanimation sait quelle doit charger et utiliser le chier HelloWorld3.as. Lorsque vous la testez, le chier de classe AS est compil dans lanimation. Lexcution de lanimation initialise la classe, qui excute la fonction HelloWorld3 et afche le texte "Hello World".

Chapitre 1

Utiliser Flash et ActionScript 3.0

17

Travailler avec Flash CS3


Si lessentiel de notre travail se fera en ActionScript, il est ncessaire de connatre certains termes et certaines notions concernant le travail avec le scnario, la scne et la bibliothque de Flash CS3.

Si vous dbutez avec Flash, tapez "Utiliser Flash" dans la documentation daide. Cette section livre une explication dtaille de la scne, du scnario, de la bibliothque et dautres lments de lespace de travail Flash et vous montre comment grer linterface Flash.

Objets dafchage et listes dafchage


Nous avons dj trait des objets dafchage. Il sagit au fond de tous les lments graphiques. Le plus polyvalent des objets dafchage est le clip, un lment graphique complet qui peut inclure nimporte quel nombre dautres objets dafchage et possde un scnario pour lanimation. Le sprite est une version plus simple du clip, qui ne contient quune seule image. Les objets dafchage que nous crerons de toutes pices en ActionScript seront gnralement des sprites. Ils sont souvent plus efcaces que les clips parce quils nimpliquent pas la surcharge requise pour inclure plusieurs images danimation. Parmi les autres objets dafchage, on peut encore citer les champs texte, les images bitmap et les vidos. Certains objets dafchage, comme les clips et les sprites, peuvent eux-mmes contenir dautres objets dafchage. Par exemple, un sprite peut contenir plusieurs autres sprites, ainsi que des champs texte et des images bitmap. Limbrication des objets dafchage offre un moyen dorganiser vos lments graphiques. Par exemple, vous pouvez crer un unique sprite de jeu et y inclure tous les lments du jeu que vous crez en ActionScript. Vous pouvez ensuite y insrer un sprite darrire-plan qui contient lui-mme plusieurs sprites pour les lments de larrire-plan. Un sprite contenant les pices du jeu pourrait alors venir se placer au-dessus et servir de conteneur pour les pices dplaables. Comme ils peuvent contenir plusieurs objets, les clips et les sprites conservent chacun une liste de ces lments an de dterminer lordre dans lequel ils doivent les afcher. On parle alors de liste dafchage. Cette liste dafchage peut tre modie pour positionner des objets devant ou derrire dautres objets. Il est galement possible de dplacer un objet dafchage dun objet parent un autre. Cette opration ne copie pas lobjet : elle le supprime dun ct et lajoute de lautre. Ce systme rend les objets dafchage incroyablement exibles et simples demploi.

18

ActionScript 3.0 pour les jeux

Le concept de liste dafchage est une nouveaut dActionScript 3.0. Si vous avez lhabitude du mcanisme dActionScript 2.0, qui utilise des niveaux et des profondeurs, oubliez tout ds prsent et adoptez sans tarder la mthode plus simple des listes dafchage. Grce ces listes, aucun objet ne se trouve un niveau dni. Lobjet dafchage le plus lointain se trouve simplement tre le premier dans la liste et le plus proche, le dernier. Vous pouvez tout moment dplacer des objets dans la liste, et les risques derreur et les effets indirects sont considrablement rduits.

La scne
La scne est la principale zone de travail graphique dans Flash. Elle reprsente lcran qui sera observ par les utilisateurs lorsquils joueront votre jeu. La Figure 1.8 prsente la fentre Document, dont la scne occupe la plus grande partie. Le scnario apparat galement en haut de la fentre.
Figure 1.8
La fentre Document inclut la fois la scne et le scnario.

Un grand nombre de nos jeux possderont une scne et un scnario compltement vides. Tous les lments graphiques seront crs par le code ActionScript.

Chapitre 1

Utiliser Flash et ActionScript 3.0

19

Dans le cas de quelques autres, des lments graphiques se trouveront dj dans la scne. Cette approche est particulirement utile lorsquun concepteur graphique non programmeur sattelle crer un jeu. Il peut souhaiter disposer les lments dinterface et les ajouter en cours de dveloppement. Dans ce genre de cas, il nest pas pratique que ces lments soient crs par le code ActionScript. Au cours du dveloppement, la scne peut tre utilise pour crer des lments graphiques rapides. Par exemple, vous pouvez dessiner avec les outils de dessin dans la scne, slectionner la forme, puis appuyer sur F8 pour crer un clip dans la bibliothque.

La bibliothque
La bibliothque Flash contient tous les lments multimdias requis dans votre jeu et se trouve intgre dans le chier SWF nal. Vous pouvez importer dautres lments multimdias dans votre animation, comme vous le verrez lorsque nous importerons des images bitmap externes, au Chapitre 6. La Figure 1.9 prsente le panneau Bibliothque. Il est gnralement plus troit, mais nous lavons tir pour faire apparatre la colonne Liaison.
Figure 1.9
Le panneau Bibliothque prsente tous les objets multimdias inclus dans lanimation.

la Figure 1.9, la plupart des lments de la bibliothque sont des clips. Le premier est un bouton et quelques autres situs dans le dossier Sounds sont des sons. Certains des clips possdent un nom dexportation dans la colonne Liaison. Il sagit dlments qui peuvent tre extraits de la bibliothque par notre code ActionScript lexcution.

20

ActionScript 3.0 pour les jeux

Le scnario
Lanimation Flash est dcompose en images. Le scnario en haut de la fentre permet de choisir limage afche dans la scne en bas de la fentre. Comme nous produisons non pas des animations mais des applications de jeu, nous allons utiliser les images pour diffrencier les crans de nos jeux. La Figure 1.10 prsente un scnario. Seules trois images sont utilises. Toutes sont des images-cls. La premire est destine un cran dintroduction du jeu et contient des instructions. La seconde correspond limage dans laquelle la partie se joue. La troisime correspond un message "Game Over" (partie termine) et un bouton "Play Again" (rejouer).
Figure 1.10
Le scnario a t lgrement tendu en utilisant le menu droulant droite an que les images soient un peu agrandies.

Chaque image-cl possde une tiquette, bien quon ne puisse la voir dans le scnario. Un petit drapeau apparat dans le calque suprieur de chaque image, qui signale la prsence dune tiquette cet endroit. Pour voir et dnir les tiquettes dimage, vous devez slectionner limage puis vrier le panneau Proprits. Celui-ci contient un champ Image. Dans le cas prsent, il contient la valeur "start" et vous pouvez le modier si vous le souhaitez (voir Figure 1.11).
Figure 1.11
Le panneau Proprits permet de dnir ou de modier ltiquette de limage.

Si vous examinez la Figure 1.10, vous remarquerez que lanimation contient quatre calques. Le premier, Label, contient trois images-cls. Pour crer des images et des images-cls, vous devez utiliser la touche F5 pour ajouter une image au calque et F7 pour ajouter une image-cl parmi ces images. Le second calque, nomm "Score", ne contient que deux images-cls, limage 1 et limage 2. Limage 3 est simplement une extension de limage 2. Les lments de score prsents durant le jeu limage 2 seront ainsi toujours prsents limage 3. Le scnario, la scne et la bibliothque seront vos principaux outils visuels pour le dveloppement de vos jeux.

Chapitre 1

Utiliser Flash et ActionScript 3.0

21

crire et modier du code ActionScript


Sil sera gnralement ncessaire de travailler un peu dans le document Flash pour crer vos jeux, vous passerez le plus clair de votre temps dans la fentre Document ActionScript. Vous avez dj rencontr cette fentre la Figure 1.6, mais la Figure 1.12 la prsente sous un nouveau jour. Elle montre gauche un menu hirarchique de la syntaxe ActionScript 3.0.
Figure 1.12
La fentre Document ActionScript contient plusieurs outils pratiques dans sa partie suprieure.

Tout en haut de la fentre apparaissent deux onglets. Deux documents sont en effet ouverts : HelloWorld3.a et HelloWorld3.as. Ils permettent de travailler la fois sur lanimation Flash et sur le document ActionScript. Vous pouvez passer de lun lautre en cliquant sur les onglets. Vous pouvez galement ouvrir dautres chiers ActionScript, ce qui peut se rvler pratique si vous travaillez avec plusieurs classes ActionScript la fois. Vous remarquerez la Figure 1.12 que les lignes de code sont indentes. Le moyen appropri de crer ces retraits est dutiliser la touche Tab. Lorsque vous appuyez sur Entre la n dune ligne de code, le curseur apparat automatiquement en retrait au bon niveau de la ligne suivante. Si vous souhaitez supprimer une tabulation pour ramener une ligne vers la gauche, appuyez simplement sur Suppr ou sur Maj + Tab.

22

ActionScript 3.0 pour les jeux

Vous pouvez galement slectionner une section de code et appuyer sur Tab pour dplacer tout le bloc vers la droite dune tabulation. Utilisez Maj + Tab pour ramener le bloc dune tabulation vers la gauche.

Les outils de la partie suprieure de la fentre de script ralisent diffrentes oprations et tout programmeur ActionScript se doit de savoir les utiliser. En voici une liste (comme le montre la fentre, de gauche droite) :

Ajouter un nouvel lment au script. Cet imposant menu droulant offre accs chacune des commandes ActionScript. Leur nombre est tel quil savre difcile utiliser pour les commandes standard, mais il peut tre utile pour les commandes plus rares. Rechercher. Utilisez cet outil pour ouvrir la bote de dialogue Rechercher et remplacer. Vous pouvez galement utiliser le raccourci Pomme + F (Mac) ou Ctrl + F (Windows). Vrier la syntaxe. Cet outil permet damener le compilateur Flash oprer une vrication de la syntaxe de votre script. Le rsultat safche dans le panneau Sortie. Format automatique. Cet outil reprend votre script entier et le reformate avec des tabulations, des espacements et des accolades cohrents. Si vous dcidez de lutiliser, assurez-vous de consulter la section Format automatique des Prfrences an doprer des dcisions concernant les actions que ce bouton doit ou ne doit pas raliser. Afcher les conseils de code. Voil probablement le plus utile de tous ces boutons. Lorsque vous commencez taper une fonction, par exemple gotoAndStop(, un conseil de code apparat instantanment pour vous faire connatre les paramtres que prend la fonction. Si vous souhaitez diter lappel de fonction par la suite, vous pouvez positionner le curseur lintrieur des paramtres de la fonction et utiliser ce bouton pour afcher de nouveau les conseils. Options de dbogage. Ce menu droulant permet de dnir et de supprimer des points darrt. Nous traiterons du dbogage par la suite, dans la section "Test et dbogage" de ce chapitre. Rduire entre les accolades. Si vous cliquez sur ce bouton, la section courante de code entre accolades se rduit une unique ligne. Le code reste prsent, mais il est masqu. Vous pouvez cliquer sur le triangle (Mac) ou le signe plus (Windows) gauche de la fentre ou sur le bouton Dvelopper tout pour ltendre. La Figure 1.13 montre quoi ressemble le code lorsquune portion est rduite. Rduire la slection. Ce bouton rduit le code actuellement slectionn. Dvelopper tout. Ce bouton ramne toutes les sections rduites leur tat normal. Appliquer un commentaire de bloc. Slectionnez une portion de code et appuyez sur ce bouton pour transformer la slection en un commentaire en la faisant prcder de /* et suivre de */. Consultez la section "Stratgies de programmation des jeux ActionScript" pour en apprendre plus sur les commentaires dans le code.

Chapitre 1

Utiliser Flash et ActionScript 3.0

23

Figure 1.13
Un bloc de code a t rduit. Ce mcanisme est pratique lorsque vous travaillez sur un script trs long et que vous souhaitez masquer les sections du code sur lesquelles vous ne travaillez pas pour le moment.

Appliquer un commentaire de ligne. Cliquez sur ce bouton pour transformer la ligne courante en un commentaire. Si plusieurs lignes sont slectionnes, toutes sont transformes en commentaire en ajoutant // au dbut de chacune. Supprimer le commentaire. Reconvertit les commentaires slectionns en code. Ce bouton est pratique lorsque vous souhaitez supprimer temporairement du code de votre programme. Vous pouvez transformer les lignes en commentaire an quelles ne soient pas compiles puis supprimer les marques de commentaire pour faire rapparatre le code. Afcher ou masquer la bote outils. Ce bouton afche ou masque la liste des commandes ActionScript gauche de la fentre.

droite des boutons se trouve un menu droulant intitul Cible qui permet de slectionner le document danimation Flash qui doit se compiler et sexcuter lorsque vous slectionnerez Contrle > Tester lanimation. Il vous permet ainsi dapporter une modication votre code puis de tester lanimation sans avoir revenir pralablement la fentre Document. En gnral, cest le dernier document danimation Flash visualis qui apparat dans la liste, mais vous pouvez slectionner un document particulier lorsque plusieurs documents sont ouverts. Parmi les autres fonctionnalits importantes de la fentre Document ActionScript, il faut encore citer les numros de ligne qui apparaissent ct gauche. Chaque ligne possde son propre numro. Lorsque vous obtenez des erreurs de compilation en essayant de publier votre animation, elles font rfrence au numro de ligne pour vous permettre de retrouver la source du problme.

24

ActionScript 3.0 pour les jeux

Stratgies de programmation des jeux ActionScript


ActionScript 3.0 est trs polyvalent. Vous pouvez adopter toutes sortes de styles de programmation et crer dans tous les cas des jeux qui fonctionnent bien. Certains programmeurs prfrent cependant certains styles plutt que dautres. Dans ce livre, jai adopt une mthode qui permet de se concentrer sur le code central du jeu, au dtriment ventuel dune organisation plus labore.

Mthode une seule classe


Le troisime programme Hello World de ce chapitre est un simple chier de classe li une animation Flash du mme nom. Cette approche simple est rapide et facile.

Lautre option consiste utiliser diffrents chiers de classe pour les diffrents objets et processus du jeu. Il peut cependant alors devenir difcile de se rappeler o se trouvent les diffrentes portions de code des petits jeux. Par exemple, si une balle entre en collision avec une raquette dans un jeu, la dtection de collision va-t-elle se trouver dans la classe de lobjet balle ou dans celle de lobjet raquette ? Vous pouvez parfaitement dcomposer le code en plusieurs classes si vous tes familiaris avec ce type dorganisation dans dautres langages de programmation.

Avec un chier de classe, toutes les proprits de classe peuvent tre clairement dnies comme des variables en haut de la classe. La classe du document contrle le scnario principal, ce qui signie quil est possible dappeler des fonctions publiques dans la classe partir de boutons placs dans la scne par les concepteurs. On peut aussi aisment contrler le scnario principal en passant dune image une autre.

La mthode des petits pas


Voil linformation qui risque bien dtre la plus importante du livre : si vous ne savez pas comment programmer quelque chose, dcomposez votre problme en tapes plus petites et poursuivez ainsi jusqu ce que vous puissiez trouver la solution. Les programmeurs dbutants et certains programmeurs expriments qui oublient tout simplement cette rgle se retrouvent souvent bloqus lorsquils crivent du code. Ils se disent : "Je ne sais pas comment faire pour que le programme ralise cette tche." Le problme tient cependant uniquement au fait que la tche nen est pas une, mais en ralit plusieurs.

Chapitre 1

Utiliser Flash et ActionScript 3.0

25

Par exemple, supposons quun programmeur souhaite faire pivoter un vaisseau spatial lorsque le joueur appuie sur les touches ches du clavier. Il se fruste parce quil ne sait pas comment raliser cette tche. La solution consiste dcomposer la tche de "rotation du vaisseau" : vrier si la touche che de gauche a t enfonce ; soustraire un montant la proprit rotation du sprite du vaisseau ; vrier si la touche che de droite a t enfonce ; ajouter un montant la proprit rotation du vaisseau. La tche de rotation du vaisseau correspond donc nalement quatre petites tches combines en une. Parfois, les programmeurs dbutants font la mme erreur plus grande chelle. Ils supposent quils ne pourront pas crer un jeu entier, parce quil semble trop complexe. Pourtant, si vous dcomposez le jeu en une srie de tches de plus en plus petites (et vous occupez de ces tches une par une), vous pourrez crer nimporte quelle sorte de jeu. Un jeu de marteau simple pourra ne requrir quune centaine de tches, alors quun jeu de plateforme complexe en ncessitera plusieurs centaines. Chacune des tches, si elle se trouve dcompose en ses tapes les plus lmentaires, se rvlera cependant tout aussi facile programmer.

Bonnes pratiques de programmation


Pendant que vous apprenez utiliser le langage ActionScript 3.0 pour crer des jeux, il est aussi judicieux que vous gardiez lesprit quelques-unes des bonnes pratiques en matire de programmation. Il nexiste pas tant de rgles que cela respecter. Je mautorise moi-mme les enfreindre certaines occasions dans ce livre. Il ne fait pourtant aucun doute que vous serez meilleur programmeur si vous commencez par bien assimiler ces bonnes pratiques.

Du bon usage des commentaires


Ponctuez votre code de commentaires simples mais signiants. Ce petit effort supplmentaire du moment vous attirera tous les loges quelques mois plus tard lorsque vous devrez vous replonger dans vos programmes pour les modier. Si vous travaillez avec dautres programmeurs ou si vous pensez quil y a la moindre chance quune autre personne puisse avoir modier votre code lavenir, ce simple conseil doit faire gure de rgle imprative. Il existe gnralement deux types de commentaires : les commentaires de ligne et les commentaires de bloc. Le commentaire de ligne est une simple remarque en style tlgraphique la n dune ligne ou quelquefois une simple ligne de commentaire avant la ligne de code. Le commentaire de bloc est

26

ActionScript 3.0 pour les jeux

un commentaire plus important, gnralement dune ou de plusieurs phrases, qui apparat avant une fonction ou une section de code :
someActionScriptCode(); // Voici un commentaire de ligne // Voici un commentaire de ligne someActionScriptCode(); /* Voici un commentaire de bloc. Les commentaires de bloc sont plus longs. Et contiennent une description concernant le code qui suit. */

Il est galement important de rendre vos commentaires signiants et concis. Ne vous contentez pas de reformuler ce que le code voque en lui-mme, comme ceci :
// Boucle 10 fois for (var i:int=0;i<10;i++) {

En outre, nutilisez pas de paragraphe de texte lorsque quelques mots sufsent. Les commentaires inutilement longs peuvent devenir aussi inefcaces que sils taient absents. Ne cherchez pas en faire trop.

Utiliser des noms de variable et de fonction descriptifs


Ne craignez pas dutiliser des noms longs et descriptifs pour vos variables et vos fonctions. Vous crerez ainsi du code qui sexplique en partie de lui-mme. Prenez cet exemple :
public function placerTruc() { for(var i:int=0;i<10;i++) { var a:Chose = new Chose(); a.x = i*10; a.y = 300; addChild(a); } }

Que fait ce code ? Il semble placer des copies dun clip lcran. Mais quel clip, dans quel but ? Voici une autre version du programme :
public function placerPersonnagesEnnemis() { for(var numEnnemi:int=0; numEnnemi<10; numEnnemi++) { var ennemi:PersonnageEnnemi = new PersonnageEnnemi(); ennemi.x = numEnnemi*10; ennemi.y = 300; addChild(ennemi); } }

Il sera dj bien plus facile de revenir ce code quelques mois plus tard.

Chapitre 1

Utiliser Flash et ActionScript 3.0

27

Lexception courante cette rgle concerne lutilisation de la variable i comme variable incrmentale dans les boucles. Dans lexemple prcdent, jaurais normalement conserv la variable i au lieu de la remplacer par numEnnemi. Les deux approches conviennent, mais il est devenu assez standard pour les programmeurs dutiliser la variable i dans les boucles. En fait, les programmeurs poursuivent gnralement cette logique en utilisant les variables j et k dans les boucles for imbriques.

Transformer le code rptitif ou similaire en fonction


Si vous devez utiliser la mme ligne de code plusieurs fois dans un programme, envisagez de la transformer en une fonction et dappeler cette fonction la place. Par exemple, il se peut que vous souhaitiez mettre jour le score plusieurs endroits de votre jeu. Si le score est afch dans un champ texte nomm scoreDisplay, vous procderez ainsi :
scoreDisplay.text = "Score: "+playerScore;

Au lieu dinclure cette mme ligne de code cinq endroits diffrents, il est prfrable de placer un appel de fonction dans ces cinq emplacements :
showScore();

Ensuite, la fonction peut prendre la forme suivante :


public function showScore() { scoreDisplay.text = "Score: "+playerScore; }

prsent que ce code est situ un seul endroit, il devient trs facile de changer le terme Score et de le remplacer par Points. Inutile deffectuer une opration de recherche et de remplacement dans le code : il ny a quun seul endroit modier. Vous pouvez en faire de mme lorsque le code nest pas identique. Par exemple, supposons que vous ayez une boucle dans laquelle vous placez dix copies du clip A gauche de la scne et une autre dans laquelle vous placez dix copies du clip B droite de la scne. Vous pouvez crer une fonction qui prend la rfrence du clip et la position horizontale de lemplacement et positionne les clips en fonction de ces paramtres. Ensuite, vous pouvez appeler votre fonction deux fois, une fois pour le clip A et une autre pour le clip B.

Tester votre code par petits blocs


mesure que vous crivez votre code, testez-le sur des portions aussi rduites que possible. Vous pourrez ainsi capturer les erreurs mesure que vous crivez votre code.

28

ActionScript 3.0 pour les jeux

Par exemple, si vous souhaitez crer une boucle qui place au hasard dix cercles de couleur diffrente lcran, vous devez dabord crer les dix cercles en les positionnant de manire alatoire. Testez ce code et faites-le fonctionner comme vous le souhaitez. Ensuite, ajoutez la fonctionnalit qui dnit alatoirement la couleur. Il sagit en ralit dune variante de la "mthode des petits pas". Dcomposez votre tche de programmation en petites tapes. Crez le code pour chaque tape et effectuez un test chaque fois.

Notions lmentaires du langage ActionScript


Examinons la syntaxe de programmation la plus lmentaire en ActionScript 3.0. Si vous dbutez avec ActionScript mais que vous ayez dj utilis un autre langage de programmation, vous pourrez ainsi dcouvrir rapidement le fonctionnement dActionScript. Si vous avez dj utilis ActionScript ou ActionScript 2.0, vous aurez loccasion de constater les diffrences introduites avec ActionScript 3.0.

Crer et utiliser des variables


Le stockage de valeurs peut soprer en ActionScript 3.0 laide dune simple instruction dattribution. Vous devez cependant dclarer vos variables la premire fois que vous les utilisez. Pour cela, vous pouvez placer le mot-cl var avant le premier usage de la variable :
var maValeur = 3;

Vous pouvez aussi commencer par dclarer votre variable et lutiliser par la suite :
var maValeur;

Linstruction var nest pas requise avec ActionScript 2.0. Elle lest en revanche avec ActionScript 3.0.

Lorsque vous crez une variable de cette manire, elle prend le type polyvalent Object. Cela signie quelle peut contenir nimporte quel type de valeur de variable : un nombre, une chane comme "Hello" ou un contenu plus complexe comme un tableau ou une rfrence de clip. Si vous dclarez une variable comme tant dun type spcique, vous ne pourrez en revanche lutiliser que pour stocker des valeurs du mme type :
var maValeur:int = 7;

Chapitre 1

Utiliser Flash et ActionScript 3.0

29

Une variable de type int peut tre un entier, positif ou ngatif. Les variables de type uint sont destines uniquement aux entiers positifs. Si vous souhaitez utiliser des valeurs fractionnelles (aussi appeles nombres virgule ottante), vous devez utiliser le type Number :
var maValeur:Number = 7.8;

Vous pouvez aussi utiliser les types String et Boolean. Les valeurs String contiennent du texte, tandis que les valeurs Boolean correspondent true ou false. Nous venons dnumrer les types primitifs de base. Vous pouvez cependant avoir aussi des tableaux, des rfrences de clip et de sprite et de nouveaux types qui correspondent aux classes de code que vous crez.

Il y a un avantage vident en termes defcacit utiliser des variables prcisment dnies. Par exemple, laccs aux valeurs int se fait bien plus rapidement quaux valeurs Number. Vous pouvez ainsi contribuer acclrer des processus critiques dans vos jeux en choisissant des types aussi basiques que possible pour toutes vos variables.

Les oprations sur les variables numriques ressemblent celles de presque tous les autres langages de programmation. Laddition, la soustraction, la multiplication et la division seffectuent avec les oprateurs +, -, * et / :
var monNombre:Number = 7.8+2; var monAutreNombre:int = 5-6; var monAutreNombre:Number = monNombre*3; var monNombreSuivant:Number = monNombre/monAutreNombre;

Vous pouvez galement utiliser des oprateurs spciaux pour simplier les oprations. Par exemple, loprateur ++ incrmente dune unit la variable laquelle il sapplique. Loprateur -- lui soustrait une unit :
monNombre++;

Vous pouvez utiliser +=, -=, *= et /= pour raliser une opration sur la variable dorigine. Par exemple, linstruction suivante ajoute sept la variable :
monNombre += 7;

Vous pouvez galement utiliser des parenthses pour dnir lordre des oprations :
var monNombre:Number = (3+7)*2;

Les valeurs String peuvent galement tre manipules avec loprateur + et loprateur += :
var maValeurString:String = "Hello"; var monAutreValeurString = maValeurString+"World"; maValeurString += "World";

30

ActionScript 3.0 pour les jeux

Lorsque nous utilisons des variables dans des classes, elles deviennent des proprits de cette classe. Dans ce cas, il faut encore les dnir comme prives ou publiques. Les variables prives ne sont pas accessibles depuis le code hors de la classe. Dans la plupart des cas, cela ne pose pas de problme, car les fonctions de classe doivent tre les seules pouvoir modier les valeurs des variables de classe.

Instructions conditionnelles
Linstruction if fonctionne en ActionScript comme elle le fait dans de nombreux langages de programmation :
if (maValeur == 1) { faireQuelqueChose(); }

Loprateur de comparaison == vrie lgalit gnrale. Vous pouvez galement utiliser >, <, >= et <= pour dterminer si une valeur est suprieure, infrieure, suprieure ou gale ou infrieure ou gale une autre. Il est aussi possible dajouter les mots-cls else et else if pour tendre la structure if :
if (maValeur == 1) { faireQuelqueChose(); } else if (maValeur == 2) { faireAutreChose(); } else { neRienFaire(); }

Vous pouvez galement inclure des conditions plus complexes avec && et | |. Ces signes reprsentent les oprateurs de comparaison ET et OU.

Avant ActionScript 3.0, il tait possible dutiliser les mots-cls and et or la place de && et | |. Ces mots-cls ne sont maintenant plus accepts.

if ((maValeur == 1) && (maChaine == "This")) { faireQuelqueChose(); }

Chapitre 1

Utiliser Flash et ActionScript 3.0

31

Boucles
Les boucles seffectuent avec linstruction for ou linstruction while. Linstruction for contient trois parties : linstruction initiale, une condition et une instruction de changement. Par exemple, le code suivant positionne la variable i zro, boucle tant quelle est infrieure dix et augmente la valeur de i chaque passage dans la boucle :
for(var i:int=0;i<10;i++) { faireQuelqueChose(); }

Vous pouvez utiliser la commande break pour quitter une boucle tout moment. La commande continue ignore le reste des lignes de code dans la boucle et commence la prochaine itration dans la boucle. La boucle while est une boucle qui se poursuit indniment jusqu ce quune condition initiale soit remplie :
var i:int = 0; while (i < 10) { i++; }

La boucle do est une variante de la boucle while. Elle lui est pour lessentiel identique, ceci prs que linstruction conditionnelle intervient aprs la boucle, ce qui lui garantit de sexcuter au moins une fois :
var i:int = 0; do { i++; } while (i <10);

Fonctions
Pour crer une fonction avec ActionScript 3.0, vous devez simplement dclarer la fonction, les paramtres qui lui sont passs en entre et la sortie quelle retourne. Ensuite, vous dnissez la fonction avec le code quelle contient. Si la fonction se trouve dans une classe, vous devez galement indiquer sil sagit dune fonction publique ou dune fonction prive. Les fonctions prives ne sont pas accessibles depuis lextrieur de la classe. Avec notre mthode de dveloppement de jeu classe unique, nous utiliserons principalement des classes prives.

32

ActionScript 3.0 pour les jeux

Vous constaterez parfois que les fonctions sont appeles des mthodes. Dans la documentation, le terme de mthode est frquemment utilis, mais cest le mot-cl function qui est adopt pour la dnition, comme vous le verrez ci-aprs. Je prfre donc pour ma part utiliser le terme de fonction.

Voici une fonction simple lintrieur dune classe. Si cette fonction se trouvait dans le scnario principal au lieu dtre dans une classe, nous pourrions ignorer le mot-cl private :
private function maFonction(monNombre:Number, maChaine:String): Boolean { if (monNombre == 7) return true; if (maChaine.length < 3) return true; return false; }

Cette fonction dexemple se contente de retourner true si le nombre vaut sept ou si la longueur de la chane est infrieure trois caractres. Il sagit dun exemple simple qui illustre la syntaxe de cration dune fonction.

Test et dbogage
Personne ne peut prtendre crire du premier jet un code absolument parfait, pas mme le programmeur le plus chevronn au monde. Il est donc ncessaire de programmer votre code, de le tester et de le dboguer.

Types de bogues
Il existe trois raisons de dboguer votre code. La premire concerne le cas o vous obtenez un message derreur lors de la compilation ou de lexcution de votre code. Vous devrez alors retrouver le problme et le corriger. En gnral, vous le dcouvrirez immdiatement. Il pourrait par exemple sagir dun nom de variable mal orthographi. La seconde raison concerne le cas o le programme ne fonctionne pas comme prvu. Par exemple, un personnage cens bouger ne le fait pas, lentre de lutilisateur nest pas accepte ou les balles tires par le hros traversent lennemi sans le toucher. Ce type de bogue doit tre analys et traqu et cette opration peut parfois prendre du temps. La troisime raison de dboguer votre code concerne le cas o vous souhaitez lamliorer. Vous pouvez reprer les inefcacits et les problmes qui gnrent des ralentissements. Parfois, ces problmes sont aussi critiques que des bogues, car un jeu lent peut devenir aussi injouable quun jeu dysfonctionnant.

Chapitre 1

Utiliser Flash et ActionScript 3.0

33

Le type de question le plus courant que jobtiens de la part dautres programmeurs concerne des cas o le code ne fonctionne pas comme prvu. Puis-je leur dire ce qui cloche ? Oui, je le peux, mais la rponse se trouve juste devant eux. Il suft quils exploitent leurs comptences en dbogage pour le savoir. Or, en qualit de crateur du code, ce sont eux les mieux placs pour le faire.

Mthodes pour le test


Il existe plusieurs manires de pister les problmes dans votre code. Lapproche la plus simple consiste tout simplement le reparcourir mentalement. Par exemple, parcourez le code suivant ligne par ligne et effectuez les calculs par vous-mme, comme si vous tiez lordinateur :
var monNombre:int = 7; monNombre += 3; monNombre *= 2; monNombre++;

Inutile dexcuter ce code pour savoir que la valeur de monNombre est prsent 21. Dans les cas o le code est trop long ou lorsque les calculs sont trop difciles raliser, une simple commande trace transmet des informations au panneau Sortie an que vous puissiez les examiner :
var monNombre:int = 7; monNombre += 3; monNombre *= 2; monNombre++; trace("monNombre = ", monNombre);

Avant Flash CS3, la commande trace nacceptait quune unique chane et la transmettait au panneau Sortie. Elle peut maintenant accepter nimporte quel type de donnes, ainsi que des lments multiples spars par des virgules. Ces nouvelles capacits en font maintenant un outil bien plus utile pour le dbogage.

Jutilise moi-mme assez souvent des instructions trace en cours de dveloppement. Par exemple, si le joueur doit oprer une srie de choix au dbut du jeu, jenvoie les rsultats de ces choix vers le panneau Sortie avec trace. Jobtiens ainsi pendant que jeffectue mes tests un rappel des options que jai choisies avant de jouer au jeu si quelque chose dinattendu se produit.

34

ActionScript 3.0 pour les jeux

Utiliser le dbogueur
Flash CS3 vous permet dutiliser un dbogueur dexcution pour tester votre code pendant que votre animation sexcute. Si vous utilisiez auparavant le dbogueur ActionScript 2.0, ne vous ez pas ces anciennes sensations : le dbogueur ActionScript 3.0 est un tout autre animal.

Dnir un point darrt


Le moyen le plus simple de dboguer un programme consiste dnir un point darrt. Vous pouvez le faire en slectionnant une ligne de votre code et en choisissant Dboguer > Basculer le point darrt dans la barre des menus. Vous pouvez galement appuyer sur Commande + B (Mac) ou Ctrl + B (Windows) pour dnir ou supprimer un point darrt. La Figure 1.14 prsente le code DebugExample.as, dans lequel un point darrt est dni. Il apparat sous la forme dun cercle rouge gauche de la fentre avant la huitime ligne. Le programme cre simplement dix champs texte contenant les numros 0 9 et les place verticalement du ct gauche de lcran.
Figure 1.14
Le curseur a t plac la ligne 8 avant de choisir Dboguer >Basculer le point darrt an de dnir un point darrt cet endroit.

Une fois quun point darrt est dni, vous pouvez utiliser la commande Dboguer > Dboguer lanimation au lieu de Contrle > Tester lanimation pour tester votre animation. Lorsque le programme atteint la ligne o se trouve le point darrt, il sinterrompt et afche une varit dinformations dans diffrentes fentres de dbogage.

Chapitre 1

Utiliser Flash et ActionScript 3.0

35

Si vous utilisez la commande Dboguer > Dboguer lanimation avec le point darrt la ligne 8, toute une srie de panneaux safche en plus de lanimation Flash qui sexcute (voir Figure 1.15).
Figure 1.15
Le panneau Dbogage prsente diverses informations concernant ltat de votre programme.

Parcourir le code au pas pas


Cinq boutons apparaissent en haut de votre panneau Console de dbogage dans le coin suprieur gauche. Le premier est le bouton Continuer, qui reprend la lecture de lanimation partir du point o elle sest interrompue. Le second est un X. Il interrompt la session de dbogage et relance lanimation partir de ce point sans dbogage. Les trois autres boutons concernent le parcours du code au pas pas. Le premier, Pas pas principal, excute la ligne courante et passe la suivante. Si la ligne de code courante appelle une autre fonction, il excute cette fonction. Le bouton suivant, Pas pas dtaill, introduit le programme dans une nouvelle fonction sil en existe une dans la mme ligne. En utilisant ce bouton de manire rptitive, vous pourrez consulter une une chaque ligne individuelle du programme au lieu de sauter les appels de fonction. Le dernier bouton ressort de la fonction courante. Utilisez-le pour terminer lexcution de la fonction courante et passer la ligne suivante de la fonction que vous venez de quitter. La Figure 1.16 prsente les panneaux dbogage une fois que vous tes entr dans la fonction showNumber puis descendu de quelques lignes. Comme vous pouvez le voir, le panneau Variables prsente la valeur de i. Vous pouvez galement tendre la variable myText pour voir toutes les proprits du champ texte.

36

ActionScript 3.0 pour les jeux

En haut gauche, le panneau de dbogage indique o vous vous trouvez dans le programme. Dans cet exemple, vous vous trouvez actuellement dans la fonction showNumber, qui a t appele partir de la fonction constructeur de cette classe. Cette indication se rvle pratique lorsque vous avez une fonction qui peut tre appele partir de plusieurs emplacements. Le fait de savoir comment utiliser le dbogueur pour corriger des bogues et des comportements inattendus est aussi important que savoir comment crire du code. Lorsque vous travaillerez avec les jeux de ce livre et tenterez de les modier pour les adapter vos besoins, apprenez galement dboguer votre code.
Figure 1.16
Les panneaux de dbogage prsentent ltat du programme mesure que vous en parcourez les diffrentes tapes.

Publier votre jeu


Une fois que vous aurez termin un jeu, que vous laurez test et aurez t satisfait, il sera temps de le publier. Les jeux Flash se publient gnralement sur le Web en tant incorpors dans des pages Web. Flash CS3 facilite considrablement ce processus, mais il convient de comprendre quelques options avant de se lancer dans la publication. Pour accder la bote de dialogue Paramtres de publication, choisissez Fichier >Paramtres de publication. La bote de dialogue Paramtres de publication contient trois sections : Formats, Flash et HTML.

Chapitre 1

Utiliser Flash et ActionScript 3.0

37

Formats
Les paramtres Formats (voir Figure 1.17) permettent de slectionner les chiers exporter. Les formats dimage dsignent des substitutions lorsque lutilisateur ne possde pas de lecteur Flash. Lexportation QuickTime sert placer une animation Flash 5 dans un chier QuickTime. Aucun de ces paramtres ne nous concerne en tant que dveloppeurs de jeux ActionScript 3.0. Les deux options Projection peuvent tre utilises pour crer des versions autonomes de nos jeux. Elles reprsentent un moyen compltement diffrent dexporter vos animations termines.
Figure 1.17
Seuls les formats Flash et HTML sont slectionns pour lexportation.

Si vous possdez dj un modle de page Web personnalis que vous utilisez sur votre site, loption HTML ne sera pas forcment ncessaire. Dans ce cas, vous navez pas besoin de page par dfaut dans laquelle incorporer votre jeu. Vous pouvez cependant lexporter quoi quil en soit puis rcuprer le code du corps de la page dexemple an de lutiliser lemplacement appropri de votre page personnalise.

Flash
Les paramtres Flash sont les plus importants pour lexportation dune animation Flash complexe comme nos jeux. De prfrence, exportez des chiers Flash Player 9, en choisissant la version ActionScript 3.0 (voir Figure 1.18).

38

ActionScript 3.0 pour les jeux

Cochez galement loption Protger contre limportation. Il deviendra ainsi plus difcile pour vos utilisateurs de tlcharger votre animation et de la modier pour se lapproprier.

Malheureusement, il nexiste pas de moyen garanti de protger votre animation Flash aprs quelle a t publie sur le Web. Il existe des programmes de dcompilation qui permettent de rcuprer un chier SWF compress et protg et de le reconvertir en une animation FLA modiable. Les options Protger contre limportation et Compresser lanimation compliquent ce processus mais ne protgent pas de manire absolue contre ces techniques.

Le reste des paramtres Flash concerne les paramtres de compression et de scurit. Consultez la documentation Flash pour une documentation dtaille concernant chacun de ces rglages.
Figure 1.18
Ces paramtres sont conseills pour lutilisation habituelle des jeux Flash.

Chapitre 1

Utiliser Flash et ActionScript 3.0

39

HTML
Les paramtres HTML nimportent que si vous souhaitez utiliser la page HTML cre avec la commande Publier. Il est cependant judicieux de voir comment Adobe considre quil est prfrable de publier vos animations Flash. La Figure 1.19 prsente ces options.
Figure 1.19
Les paramtres HTML vous permettent de choisir un modle HTML exporter avec lanimation Flash.

Le rglage par dfaut (Flash uniquement) utilise du code JavaScript pour incorporer lanimation. Il utilise le chier AC_RunActiveContent.js qui est galement gnr lors de la publication. La page HTML principale charge ensuite le JavaScript dans ce chier, qui place lanimation Flash dans une balise <div> lintrieur de la page Web.

Pourquoi se donner la peine dutiliser du JavaScript alors quil serait possible de nutiliser quune simple balise <object>/<embed>, comme vous lavez fait les annes prcdentes ? En raison dun conit portant sur des brevets, Microsoft a d changer la manire dincorporer les lments multimdias dans les pages sous Internet Explorer. Tous les lments multimdias incorpors directement dans une page requirent maintenant un clic pour tre activs dans Internet Explorer 7 et certaines versions dInternet Explorer 6. Cette mthode JavaScript vite cependant ce clic supplmentaire.

40

ActionScript 3.0 pour les jeux

Lune des options souvent utilises consiste amener lanimation Flash se redimensionner pour remplir la fentre entire du navigateur. Cette mise lchelle peut seffectuer en choisissant loption Pourcentage dans le menu droulant Dimensions et en xant la Largeur et la Hauteur 100. Lanimation stend alors de manire remplir la fentre tout en conservant ses proportions. Loption Taille exacte de la liste droulante chelle lui permet de perdre ses proportions dorigine et de stendre verticalement pour sadapter la hauteur de la fentre et horizontalement pour couvrir sa largeur. Comme tous les graphismes vectoriels se redimensionnent harmonieusement dans Flash et que votre code peut fonctionner sans problme nimporte quelle chelle, il est gnralement judicieux de permettre lutilisateur dajuster la taille du jeu en modiant simplement la taille de sa fentre de navigateur. Les utilisateurs qui possdent de petits crans et les autres dots de grands pourront ainsi jouer aux jeux comme ils lentendent. Le paramtre Qualit fait partie des autres options disponibles. Avec le rglage leve, le lecteur Flash reproduit limage haute rsolution an dobtenir le meilleur effet de lissage sur les bords des formes vectorielles. Loption Moyenne rduit la rsolution du lissage mais amliore les performances de lanimation. Avec loption leve automatiquement, Flash tente dutiliser le rglage leve mais repasse loption Moyenne si la lecture est trop lente. Le rglage Infrieure supprime le lissage mais propose la meilleure vitesse de lecture.

Chek-list de la programmation de jeux ActionScript


Lorsque vous crez un jeu Flash, plusieurs facteurs doivent tre pris en compte. Un lment cl peut toujours tre oubli qui amnerait le jeu ne pas fonctionner correctement. Pour viter certains problmes simples, voici une check-list rapide laquelle vous pourrez vous reporter loccasion.

Paramtres de publication et de document


Il est important de se rappeler quil existe des paramtres essentiels dans la bote de dialogue Paramtres de publication et dans le panneau Proprits de lanimation.

La classe du document est-elle correctement dnie ?


La Figure 1.7 montre comment dnir la classe du document en utilisant le panneau Proprits de lanimation. Si vous oubliez de dnir ce rglage, lanimation sexcutera et ignorera tout simplement la classe que vous avez cre.

Les paramtres de publication sont-ils correctement dnis ?


Assurez-vous de dnir les Paramtres de publication de manire que lanimation Flash soit compile pour Flash 9 et ActionScript 3.0. Il est assez improbable que votre animation se compile si ces paramtres ne sont pas correctement dnis, mais cela reste possible.

Chapitre 1

Utiliser Flash et ActionScript 3.0

41

Vrier les paramtres de scurit


Dans la section Flash des Paramtres de publication gure un paramtre Scurit de lecture locale. Vous pouvez choisir loption Accs aux chiers locaux uniquement ou loption Accs au rseau uniquement. An de vous assurer que vos animations Flash sont scurises, choisissez loption approprie. Ce rglage peut poser problme si vous devez accder des chiers locaux et que loption Accs rseau uniquement soit slectionne. Si vous utilisez des chiers externes et que quelque chose ne se passe pas comme prvu lorsque vous chargez les chiers sur un serveur, commencez par vrier ces paramtres.

Noms des classes, des fonctions et des variables


Mme en vous efforant de suivre les bonnes pratiques de programmation prcdemment mentionnes, il se peut que vous commettiez des erreurs simples parfois difciles retrouver.

Penser la casse des caractres


Lorsque vous nommez une variable ou une fonction, la casse des caractres est prise en compte. maVariable et mavariable sont ainsi compltement diffrentes. De la mme manire, une classe nomme maClasse excute la fonction maClasse lorsquelle sinitialise. Si vous avez nomm votre fonction maclasse, elle ne sera pas appele. Les incohrences de noms de variable sont habituellement captures par le compilateur, car un nom de variable mal orthographi nest pas initialis, mais il reste possible doublier de dclarer une variable et de la dclarer de nouveau avec une autre casse de caractres. Voil le genre derreur surveiller.

Les chiers de classe de lanimation sont-ils prsents ?


Si un clip se voit attribuer des proprits Liaison que le code ActionScript doit utiliser, il peut utiliser la classe dynamique par dfaut ou vous pouvez crer une classe pour lui. Par exemple, vous pouvez crer un clip EnemyCharacter et lui associer un chier de classe EnemyCharacter.as. Rien de plus facile cependant que doublier cette classe ou de lorthographier de manire incorrecte. Par exemple, un chier Enemycharacter.as sera tout simplement ignor et ne sera pas li au clip EnemyCharacter.

Les classes tendent-elles le bon type ?


Vous pouvez commencer la classe dune animation par une dnition de ce genre :
public class myClass extends Sprite {

Toutefois, en tendant un Sprite plutt quun MovieClip, vous prsupposez que lanimation ne contient quune image. Tout code qui ferait rfrence aux autres images ne fonctionnerait ds lors pas comme prvu.

42

ActionScript 3.0 pour les jeux

La fonction constructeur possde-t-elle le bon nom ?


Si vous avez une classe nomme maClasse, la fonction constructeur doit tre trs prcisment nomme maClasse, sans quoi elle ne sexcutera pas lorsque la classe sera initialise. Si vous ne souhaitez pas quelle sexcute immdiatement, nommez-la par exemple lancerMaClasse et appelez-la aprs que limage dmarre.

Problmes dexcution
Il existe aussi des problmes qui ne provoquent pas derreur de compilateur et ne se font pas remarquer au dpart. Ils peuvent apparatre par la suite en cours de dveloppement et se rvler trs difciles dbusquer.

Dnissez-vous des proprits avant que lobjet ne soit prt ?


En voil un qui magace particulirement. Vous passez une nouvelle image dans lanimation ou un clip et vous essayez de dnir une proprit dun objet ou dy accder. Malheureusement, limage et ses objets nayant pas encore t initialiss, la proprit concerne nexiste pas. Les chiers TooEarlyExample.a et TooEarlyExample.as en livrent un bon exemple. La classe saute limage 2 du scnario principal, o attendent deux champs texte. Elle tente immdiatement de dnir le texte du premier champ mais cette action dclenche un message derreur lexcution. Le second champ est dni lorsque lanimation a termin linitialisation et excute le script dans cette image. Ce script son tour appelle une fonction dans la classe. Cette fonction dnit le texte du second champ sans problme.

Dtruisez-vous des objets ?


Bien que cela ne soit pas ncessairement un gros problme, il est de bon usage de supprimer les objets que vous avez crs lorsque vous avez ni de les utiliser. Par exemple, si le joueur tire des balles dans tous les sens lcran, il peut maintenir une touche enfonce et en dcocher des milliers la minute. Lorsque ces balles quittent la portion visible de lcran, il est inutile de les conserver en mmoire et de les laisser accaparer lattention du programme. Pour supprimer compltement un objet, vous devez simplement vous dbarrasser de toutes les rfrences qui y renvoient dans vos variables et vos tableaux et utiliser removeChild pour les retirer de sa liste dafchage.

Toutes les variables sont-elles correctement types ?


Le typage des variables fait partie des autres facteurs qui, sans provoquer de problme sur le moment, peuvent causer bien des soucis long terme. Nutilisez pas le type Number lorsque les types int ou mme uint conviennent. Ce dernier type est bien plus rapide manipuler et consomme moins de mmoire. Si vous stockez des milliers de nombres dans des tableaux, il se peut que vous constatiez un certain ralentissement si vous utilisez le type Number plutt que int.

Chapitre 1

Utiliser Flash et ActionScript 3.0

43

Il y a pire encore, si vous utilisez des variables non types, autrement dit des variables Object. Ces dernires peuvent stocker des nombres et des entiers mais gnrent une surcharge signicative. Veillez aussi ne pas laisser passer les objets MovieClip, quil serait possible de remplacer par de simples objets Sprite une image.

Problmes de test
Ces problmes sont lis ce qui se produit durant les tests ou ce qui peut tre intgr dans vos procdures de test.

Devez-vous dsactiver les raccourcis clavier ?


Si vous utilisez la saisie clavier lorsque vous testez vos animations, il se peut que vous constatiez que certaines touches ne rpondent pas. Cest que lenvironnement de test dispose de quelques raccourcis clavier qui accaparent les touches concernes. Pour dsactiver les raccourcis clavier dans lenvironnement de test et permettre votre animation de fonctionner comme elle le ferait sur le Web, choisissez Contrle > Dsactiver les raccourcis clavier.

Avez-vous effectu des tests avec dautres cadences dimages ?


Si vous utilisez une animation temporelle, la cadence dimages ne devrait pas importer. Lanimation devrait avancer vitesse constante. Il vaut cependant la peine deffectuer des tests avec une cadence faible, comprise entre 6 et 12, an de voir ce que les utilisateurs dots dordinateurs lents sont susceptibles de dcouvrir. Nous utiliserons la technique danimation temporelle tout au long de ce livre.

Avez-vous effectu un test sur un serveur ?


Un problme similaire se produit lorsque vous partez du principe que les objets sont tous prsents au dbut dune animation. En vrit, les animations Flash sont diffuses en ux continu, ce qui signie quelles commencent avant que lensemble du contenu multimdia ait t charg. la diffrence, lorsque vous testez une animation sur votre ordinateur local, tout le contenu multimdia est instantanment charg. Lorsque vous chargez et testez lanimation sur un serveur, il se peut que vous constatiez quune portion manque pendant les quelques premires secondes, voire les premires minutes.

Lorsque vous testez une animation, vous pouvez redmarrer le test en choisissant Afchage > Simuler le tlchargement. Vous pouvez aussi choisir une option du sous-menu Afchage > Paramtres de tlchargement pour dnir une vitesse de tlchargement simul, comme 56 K. Lanimation redmarre alors en simulant une mise disposition par ux continu des objets, la vitesse dsire. Pour ma part, je prfre toujours faire galement un test avec un vritable serveur, par scurit.

44

ActionScript 3.0 pour les jeux

La solution tous ces problmes consiste proposer un cran de tlchargement dont le rle se limite attendre que la totalit des lments soit charge. Nous examinerons un exemple dcran de tlchargement au Chapitre 2. Cette check-list devrait vous permettre dviter plus facilement les problmes courants et donc de consacrer plus de temps la cration de vos jeux et moins dnicher les bogues dans le code. Maintenant que nous avons trait des notions fondamentales dActionScript 3.0, nous tudierons au chapitre suivant quelques exemples courts de cration des blocs constructeurs que vous utiliserez pour composer vos jeux.

2
Composants de jeu ActionScript
Au sommaire de ce chapitre :

Crer des objets visuels Rcuprer les entres utilisateur Crer une animation Programmer l'interaction avec l'utilisateur Accder des donnes externes Composants de jeu divers

46

ActionScript 3.0 pour les jeux

Avant de crer des jeux complets, nous allons procder en composant de petits morceaux. Les programmes courts de ce chapitre offrent un aperu de certains des concepts essentiels dActionScript 3.0 et fournissent un certain nombre de blocs constructeurs qui pourront tre utiliss par la suite et dans vos propres jeux. Codes sources http://ashgameu.com A3GPU02_GameElements.zip

Crer des objets visuels


Nos quelques premiers lments impliquent de crer et de manipuler des objets lcran. Nous rcuprerons quelques clips de la bibliothque, les transformerons en boutons, dessinerons des formes et du texte et apprendrons regrouper des lments dans des sprites.

Utiliser des clips


Lorsque vous avez un clip dans la bibliothque et que vous souhaitez limporter dans votre jeu, deux approches sont possibles. La premire consiste faire glisser le clip sur la scne et lui donner un nom doccurrence dans linspecteur des proprits. La Figure 2.1 prsente un clip plac sur la scne puis nomm myClipInstance dans linspecteur des proprits.
Figure 2.1
Lobjet clip est nomm Mascot dans la bibliothque, mais son occurrence dans la scne est nomme myClipInstance.

Chapitre 2

Composants de jeu ActionScript

47

Ensuite, vous pouvez manipuler les proprits du clip en faisant rfrence son nom, comme ceci :
myClipInstance.x = 300; myClipInstance.y = 200;

La seconde approche pour importer un clip dans votre jeu ne requiert que du code ActionScript. Pour commencer, vous devez cependant rendre le clip accessible en dnissant ses proprits de liaison. Slectionnez le symbole dans la bibliothque et, dans le menu droulant du panneau Bibliothque, choisissez Liaison. Cochez loption Exporter pour ActionScript et indiquez le nom de la classe. Votre bote de dialogue devrait ressembler celle de la Figure 2.2.
Figure 2.2
La bote de dialogue Proprits de liaison est paramtre de manire que le clip Mascot puisse tre utilis par le code ActionScript.

En gnral, je donne ma classe le mme nom que celui du clip. Il est ainsi plus facile de le retenir.

Nous pouvons maintenant crer de nouvelles copies du clip avec ActionScript. La mthode consiste crer une variable pour contenir linstance1 de lobjet et utiliser addChild pour la placer dans une liste dafchage :
var myMovieClip:Mascot = new Mascot(); addChild(myMovieClip);

Comme nous navons dni aucune autre proprit du clip, celui-ci apparat lemplacement 0, 0 sur la scne. Nous pouvons dnir son emplacement avec les proprits x et y de linstance. Il est aussi possible de dnir son angle de rotation avec la proprit rotation. La valeur de cette proprit sexprime en degrs :
var myMovieClip:Mascot = new Mascot(); myMovieClip.x = 275; myMovieClip.y = 150; myMovieClip.rotation = 10; addChild(myMovieClip);

1. NdT : puisquil sagit ici de code, nous reprenons langlicisme universellement adopt dans la terminologie des langages de programmation. Dans linterface Flash, on parlera plus naturellement des "occurrences" dun objet. Langlais utilise dans les deux cas le mme terme : "instance".

48

ActionScript 3.0 pour les jeux

Si tout cela parat bien du travail pour un simple clip, notez quActionScript permet facilement dajouter plusieurs copies dun clip. Le code qui suit cre ainsi dix copies de lobjet Mascot, en changeant lemplacement horizontal de manire progresser de 50 pixels vers la droite chaque fois. Il xe galement lchelle des clips 50 % :
for(var i=0;i<10;i++) { var mascot:Mascot = new Mascot(); mascot.x = 50*i+50; mascot.y = 300; mascot.scaleX = .5; mascot.scaleY = .5; addChild(mascot); }

La Figure 2.3 prsente le rsultat de ces deux fragments de code. Le premier objet Mascot se trouve en haut, aux coordonnes 275, 100. Les autres objets Mascot sont rpartis de 50 500 au niveau de la position verticale 300 et sont mis lchelle 50 %.
Figure 2.3
Onze mascottes ont t cres et places par le code ActionScript.

Vous trouverez cet exemple dans lanimation UsingMovieClips.a. Le code est inclus dans limage 1.

Chapitre 2

Composants de jeu ActionScript

49

Crer des boutons


Il est galement possible de crer des boutons en nutilisant que du code ActionScript. Ces boutons peuvent tre crs partir de clips ou de symboles de bouton stocks dans la bibliothque. Pour transformer un clip en un bouton sur lequel lutilisateur peut cliquer, vous navez qu lui attribuer un couteur. Le clip peut alors accepter des vnements et notamment un vnement de clic de souris. Le code suivant place un nouveau clip aux coordonnes 100, 150 :
var myMovieClip:Mascot = new Mascot(); myMovieClip.x = 100; myMovieClip.y = 150; addChild(myMovieClip);

Pour attribuer un couteur, utilisez la fonction addEventListener. Incluez le type dvnement auquel lcouteur doit rpondre. Il sagit de valeurs constantes qui varient selon le type dobjet et dvnement. Dans le cas prsent, MouseEvent.CLICK ragira un clic avec la souris. Ensuite, incluez galement une rfrence la fonction que vous allez crer pour grer lvnement (dans le cas prsent, clickMascot) :
myMovieClip.addEventListener(MouseEvent.CLICK, clickMascot);

La fonction clickMascot transmet simplement un message la fentre Sortie. Dans une application ou un jeu, cette fonction serait videmment amene raliser des oprations plus productives :
function clickMascot(event:MouseEvent) { trace("You clicked the mascot!"); }

Pour mieux donner au clip lapparence dun bouton, vous pouvez attribuer la valeur true la proprit buttonMode de son instance. Le curseur se transforme alors en une main lorsque lutilisateur le survole :
myMovieClip.buttonMode = true;

Vous pouvez videmment aussi crer des instances de symboles de bouton avec du code ActionScript. Le principe est le mme quavec les clips. Dans lexemple suivant, le symbole est li en tant que classe LibraryButton :
var myButton:LibraryButton = new LibraryButton(); myButton.x = 450; myButton.y = 100; addChild(myButton);

50

ActionScript 3.0 pour les jeux

La principale diffrence entre les clips et les symboles de bouton tient ce que les boutons possdent quatre images spcialises dans leur scnario. La Figure 2.4 prsente le scnario de notre symbole LibraryButton.
Figure 2.4
Le script dun bouton contient quatre images reprsentant les trois tapes du bouton et une zone ractive.

La premire image reprsente lapparence du bouton lorsque le curseur ne le survole pas. La seconde correspond lapparence du bouton lorsque le curseur le survole. La troisime image dnit lapparence du bouton lorsque lutilisateur a cliqu dessus sans avoir encore relch le bouton de la souris. Enn, la dernire image correspond la zone ractive du bouton. Elle nest jamais visible.

La dernire image peut inclure un graphisme plus large que le reste an de permettre lutilisateur de cliquer sur le bouton ou proximit du bouton. Si les images visibles du bouton incluent des zones vides (par exemple sil sagit simplement de lettres) ou possdent une forme bizarre, on peut donner la dernire image une forme circulaire ou rectangulaire plus standard qui reprsente la zone ractive. Vous pouvez enn crer des boutons invisibles en ne plaant rien dans les images lexception de la dernire.

La Figure 2.5 prsente les trois tats de bouton et la zone ractive dun clip. Il ne sagit l que dun exemple. Votre bouton peut prsenter toutes sortes dtats Dessus et Abaiss.
Figure 2.5
Les quatre images qui composent un symbole de bouton.

Chapitre 2

Composants de jeu ActionScript

51

Vous pouvez ajouter un couteur au bouton de la mme manire que vous lavez fait avec un clip :
myButton.addEventListener(MouseEvent.CLICK, clickLibraryButton); function clickLibraryButton(event:MouseEvent) { trace("You clicked the Library button!"); }

La troisime option pour crer un bouton consiste utiliser le type SimpleButton an de crer un bouton de toutes pices. Ou presque. Il vous faut en ralit un clip pour chacune des quatre images du bouton : Haut, Dessus, Abaiss et Cliqu. Quatre lments doivent donc gurer dans la bibliothque au lieu dun. Pour crer ce type de bouton, utilisez le constructeur SimpleButton. Chacun des quatre paramtres de SimpleButton doit tre une instance de clip. Dans le cas prsent, nous allons utiliser quatre clips : ButtonUp, ButtonOver, ButtonDown et ButtonHit :
var mySimpleButton:SimpleButton = new SimpleButton(new ButtonUp(), new ButtonOver(), new ButtonDown(), new ButtonHit()); mySimpleButton.x = 450; mySimpleButton.y = 250; addChild(mySimpleButton);

Vous pouvez galement utiliser le mme clip pour plusieurs des quatre paramtres de SimpleButton. Par exemple, vous pouvez rutiliser ltat Haut du clip pour le clip Cliqu. Vous pouvez du reste utiliser le mme clip pour les quatre tats. Le bouton sera moins intressant, mais il ncessitera moins de clips dans la bibliothque.

Vous pouvez cette fois encore ajouter un couteur au bouton que vous venez de crer avec la commande addEventListener :
mySimpleButton.addEventListener(MouseEvent.CLICK, clickSimpleButton); function clickSimpleButton(event:MouseEvent) { trace("You clicked the simple button!"); }

Le chier MakingButtons.a inclut le code de ces trois boutons et transmet un message diffrent au panneau Sortie lorsque lutilisateur clique sur chacun dentre eux.

52

ActionScript 3.0 pour les jeux

Dessiner des formes


Tous les lments lcran ne doivent pas ncessairement provenir de la bibliothque. Vous pouvez utiliser ActionScript 3.0 pour tracer des lignes et des formes lmentaires. Chaque objet dafchage possde un calque graphique auquel vous pouvez accder avec la proprit graphics. Cest le cas dailleurs de la scne elle-mme, laquelle vous pouvez accder directement en crivant du code dans le scnario principal. Pour dessiner une ligne simple, dnissez le style de ligne, accdez au point de dpart de la ligne, puis tracez la ligne jusquau point de terminaison :
this.graphics.lineStyle(2,0x000000); this.graphics.moveTo(100,200); this.graphics.lineTo(150,250);

Ce code dnit un style de ligne de 2 pixels de large et de couleur noire, puis trace la ligne en partant de 100, 200 pour atteindre 150, 250.

Le mot-cl this nest pas indispensable mais, lorsque vous souhaitez que la ligne soit dessine dans une instance de clip spcique, vous devez lindiquer en utilisant son nom. Par exemple :
myMovieClipInstance.graphics.lineTo(150,250);

Nous incluerons donc le mot-cl this ici an de nous le rappeler et de rendre le code plus facile rutiliser dans vos propres projets.

Il est galement possible de crer une ligne courbe avec curveTo. Dans ce cas, vous devez spcier un point de terminaison et un point dancrage. Ce processus peut tre un peu compliqu si vous ntes pas familiaris avec les mthodes de cration des courbes de Bzier. Il ma fallu quelques tentatives avant de parvenir au rsultat souhait :
this.graphics.curveTo(200,300,250,250);

Ensuite, nous allons complter la squence de lignes par une autre ligne droite :
this.graphics.lineTo(300,200);

Nous venons de crer le trait prsent la Figure 2.6, compos dune ligne droite, dune courbe et dune nouvelle ligne droite. Il est aussi possible de dessiner des formes. La plus simple est le rectangle. La fonction drawRect prend une position pour le coin suprieur gauche puis une largeur et une hauteur :
this.graphics.drawRect(50,50,300,250);

Chapitre 2

Composants de jeu ActionScript

53

Figure 2.6
Une ligne, une courbe et une autre ligne composent ce dessin.

Vous pouvez galement dessiner un rectangle bords arrondis. Les deux paramtres supplmentaires dnissent la largeur et la hauteur des bords arrondis :
this.graphics.drawRoundRect(40,40,320,270,25,25);

Il est aussi possible de crer un cercle et une ellipse. La fonction drawCircle prend en paramtres les coordonnes du centre et le rayon du cercle :
this.graphics.drawCircle(150,100,20);

La fonction drawEllipse ne procde pas de la mme manire, puisquelle prend les mmes paramtres de coin suprieur gauche et de taille que la fonction drawRect :
this.graphics.drawEllipse(180,150,40,70);

Vous pouvez encore crer des formes remplies en commenant par une fonction beginFill et un paramtre de couleur de remplissage :
this.graphics.beginFill(0x333333); this.graphics.drawCircle(250,100,20);

Pour cesser dutiliser un remplissage, excutez la commande endFill. La Figure 2.7 prsente le rsultat de lensemble des tracs que nous venons deffectuer. La plupart de ces fonctions de dessin possdent dautres paramtres. Par exemple, lineStyle peut aussi prendre un paramtre alpha an de dessiner une ligne semi-transparente. Consultez la documentation pour chacune de ces fonctions si vous souhaitez en apprendre plus ce sujet. Vous pourrez retrouver les prcdents exemples dans le chier dexemple DrawingShapes.a.

54

ActionScript 3.0 pour les jeux

Figure 2.7
Deux lignes, une courbe, un cercle, une ellipse, un cercle rempli, un rectangle et un rectangle arrondi.

Tracer du texte
Les exemples Hello World du Chapitre 1 ont montr comment crer des objets TextField an de placer du texte lcran. Le processus implique de crer un nouvel objet TextField, de dnir sa proprit text et dutiliser addChild pour lajouter dans la scne :
var myText:TextField = new TextField(); myText.text = "Check it out!"; addChild(myText);

Vous pouvez galement dnir lemplacement du champ avec les proprits x et y :


myText.x = 50; myText.y = 50;

De la mme manire, vous pouvez dnir la largeur et la hauteur du champ :


myText.width = 200; myText.height = 30;

Parfois, il peut tre difcile destimer la taille dun champ texte. Une largeur de 200 peut sembler sufsante pour contenir le texte courant, mais pourra-t-elle contenir un autre texte si vous dcidez de le changer ? Lun des moyens rapides de voir la taille effective dun champ texte consiste positionner la proprit border true pendant que vous effectuez vos tests :
myText.border = true;

Chapitre 2

Composants de jeu ActionScript

55

La Figure 2.8 prsente le champ texte avec une bordure an de pouvoir en apercevoir la taille.
Figure 2.8
Un champ texte 50, 50 avec une largeur de 200 et une hauteur de 30.

Il convient aussi presque toujours de soccuper de la proprit selectable. Dans la plupart des cas, vous ne souhaiterez pas quelle soit active, or il sagit du rglage par dfaut. Si vous ignorez cette proprit, le curseur du joueur se transforme en un curseur ddition de texte lorsquil survole le texte et lui donne la possibilit de le slectionner :
myText.selectable = false;

Lorsque vous crerez du texte, il y a toutes les chances que vous souhaiterez dnir explicitement la police, la taille et le style du texte. Ces rglages ne peuvent se raliser directement. Vous devez en fait crer un objet TextFormat, puis positionner ses proprits font, size et bold :
var myFormat:TextFormat = new TextFormat(); myFormat.font = "Arial"; myFormat.size = 24; myFormat.bold = true;

Vous pouvez galement crer un objet TextFormat avec une seule ligne de code. Par exemple, lexemple prcdent pourrait tre ralis de la manire suivante :
var myFormat:TextFormat = new TextFormat("Arial", 24, 0x000000, true);

La fonction constructeur TextFormat accepte jusqu treize paramtres, mais vous pouvez utiliser la valeur null pour ignorer tous les paramtres que vous ne souhaitez pas dnir. Consultez la documentation pour en obtenir une liste complte.

56

ActionScript 3.0 pour les jeux

Maintenant que nous avons un objet TextFormat, il existe deux moyens de lutiliser. Le premier consiste utiliser setTextFormat sur un objet TextField. Cette approche modie le texte an dutiliser le style courant. Il nest cependant pas ncessaire dy recourir chaque fois que vous changez la proprit text du champ. Lapproche prfrable dans ce cas consiste utiliser defaultTextFormat. Vous devez le faire avant de dnir la proprit text. Le text suivant rcupre alors les proprits de style dcrites dans TextFormat. En fait, chaque fois que vous dnissez le texte de cet objet TextField, vous utilisez le mme style. Cette approche sera le plus souvent la meilleure pour lusage que nous ferons des champs texte lors du dveloppement de nos jeux :
myText.defaultTextFormat = myFormat;

La Figure 2.9 prsente le champ avec son format dni.


Figure 2.9
Le format texte a t dni pour une police Arial 24 points et en gras.

tudiez lensemble des proprits de TextFormat dans la documentation si vous prvoyez dtendre ses capacits. Vous pouvez galement choisir dutiliser des objets StyleSheet et du texte balis en HTML laide de la proprit htmlText de lobjet TextField. La fonctionnalit des feuilles de style est trs toffe : consultez la documentation si vous souhaitez en apprendre plus ce sujet.

Crer du texte li
Quobtient-on en croisant un champ texte et un bouton ? Un lien hypertexte, videmment. Ces lments peuvent eux aussi se crer facilement avec du code ActionScript 3.0.

Chapitre 2

Composants de jeu ActionScript

57

Le moyen le plus simple de crer du texte li dans un TextField consiste utiliser la proprit htmlText du champ et lui fournir du code HTML au lieu du texte brut utilis par la proprit text :
var myWebLink:TextField = new TextField(); myWebLink.htmlText = "Visit <A HREF=http://ashgameu.com>FlashGameU.com</A>!"; addChild(myWebLink);

Ce code fonctionne comme il le ferait dans une page Web, ceci prs quil nexiste pas de modication de style par dfaut pour le lien. Il prend la mme couleur et le mme style que le reste du texte. Nanmoins, lorsque lutilisateur clique dessus, il quitte la page Web dans son navigateur et se trouve conduit jusqu celle spcie par le lien.

Si lanimation Flash sexcute sous la forme dun projecteur Flash autonome, le lien lance le navigateur et conduit lutilisateur la page Web choisie lorsque celui-ci clique dessus. Vous pouvez galement spcier le paramtre TARGET de la balise A si vous en avez lhabitude en HTML. Utilisez _top pour spcier la page entire, par opposition au cadre (frame), ou _ blank pour ouvrir une nouvelle fentre dans le navigateur.

Si vous souhaitez que le texte apparaisse en bleu et en soulign comme il le ferait dans une page Web ordinaire, vous pouvez dnir une feuille de style rapide et dnir la proprit styleSheet avant htmlText :
var myStyleSheet:StyleSheet = new StyleSheet(); myStyleSheet.setStyle("A",{textDecoration: "underline", color: "#0000FF"}); var myWebLink:TextField = new TextField(); myWebLink.styleSheet = myStyleSheet; myWebLink.htmlText = "Visit <A HREF=http://ashgameu.com>FlashGameU.com</A>!"; addChild(myWebLink);

La Figure 2.10 prsente le texte qui utilise la fois la proprit textFormat avec la police Arial 24 points et en gras et styleSheet pour passer le lien en bleu et le souligner. Vos liens ne doivent pas ncessairement conduire des pages Web. Vous pouvez les utiliser comme de simples boutons, en attribuant des couteurs aux champs texte an de ragir lorsque lutilisateur clique dessus. Pour cela, vous devez simplement utiliser event: dans la balise HREF du lien. Ensuite, fournissez du texte que votre fonction couteur pourra recevoir :
myLink.htmlText = "Click <A HREF=event:testing>here</A>";

58

ActionScript 3.0 pour les jeux

Figure 2.10
Les proprits defaultTextFormat et styleSheet ont toutes deux t utilises pour formater le texte et le lien.

Lcouteur rcuprera le texte "testing" sous forme de chane dans la proprit text de lvnement retourn :
addEventListener(TextEvent.LINK, textLinkClick); function textLinkClick(event:TextEvent) { trace(event.text); }

Vous pourrez ainsi dnir plusieurs liens dans un TextField puis faire le tri pour savoir sur lequel dentre eux lutilisateur a cliqu en utilisant la proprit text du paramtre event. Les liens texte peuvent ainsi tre utiliss la manire de boutons. Vous pouvez aussi formater le texte avec defaultTextFormat et styleSheet comme le lien Web. Le chier CreatingLinkedText.a inclut des exemples des deux types de liens qui utilisent le mme format et le mme style.

Crer des groupes de sprites


Maintenant que vous savez crer une varit dlments lcran, il est temps dentrer un peu plus en matire et de voir comment fonctionnent les objets dafchage et les listes dafchage. Il est possible de crer des objets dafchage Sprite, qui nont dautre rle que de contenir dautres objets dafchage.

Chapitre 2

Composants de jeu ActionScript

59

Le code qui suit cre un nouveau Sprite et dessine un rectangle de 200 par 200 lintrieur. Le rectangle se voit attribuer une bordure noire de 2 pixels de large et un remplissage gris clair :
var sprite1:Sprite = new Sprite(); sprite1.graphics.lineStyle(2,0x000000); sprite1.graphics.beginFill(0xCCCCCC); sprite1.graphics.drawRect(0,0,200,200); addChild(sprite1);

Le Sprite peut ensuite tre positionn, avec la forme que nous avons dessine lintrieur, aux coordonnes 50, 50 dans la scne :
sprite1.x = 50; sprite1.y = 50;

Nous allons maintenant crer un second Sprite, comme le premier, mais en le positionnant cette fois 300, 100 :
var sprite2:Sprite = new Sprite(); sprite2.graphics.lineStyle(2,0x000000); sprite2.graphics.beginFill(0xCCCCCC); sprite2.graphics.drawRect(0,0,200,200); sprite2.x = 300; sprite2.y = 50; addChild(sprite2);

Crons pour nir un troisime Sprite, qui contiendra cette fois un cercle. Au lieu dutiliser addChild pour le placer dans la scne, nous le placerons lintrieur de sprite1. Nous lui attribuerons en outre un remplissage plus fonc :
var sprite3:Sprite = new Sprite(); sprite3.graphics.lineStyle(2,0x000000); sprite3.graphics.beginFill(0x333333); sprite3.graphics.drawCircle(0,0,25); sprite3.x = 100; sprite3.y = 100; sprite1.addChild(sprite3);

La Figure 2.11 montre quoi ressemblent nos trois sprites lcran. Vous remarquerez que, bien que nous ayons x les proprits x et y du cercle aux coordonnes 100, 100, ce cercle apparat cet emplacement non pas relativement la scne mais relativement au contenu de sprite1. Lanimation contient maintenant sprite1 et sprite2 comme enfants de la scne. sprite3 est pour sa part un enfant de sprite1. Si nous amenons sprite3 devenir un enfant de sprite2, il saute au centre de sprite2 car la position 100, 100 est ds lors relative sprite3, son nouveau parent.

60

ActionScript 3.0 pour les jeux

Figure 2.11
Le sprite du cercle est lintrieur du sprite du rectangle de gauche.

Lanimation CreatingSpriteGroups.a permet de visualiser ce mcanisme plus facilement en plaant un couteur sur sprite1 et sur sprite2. Lorsque vous cliquez sur lun dentre eux, sprite3 devient son enfant. Vous pouvez ainsi faire sauter sprite3 dun parent lautre :
sprite1.addEventListener(MouseEvent.CLICK, clickSprite); sprite2.addEventListener(MouseEvent.CLICK, clickSprite); function clickSprite(event:MouseEvent) { event.currentTarget.addChild(sprite3); }

Cet exemple montre bien galement comment un couteur de bouton peut tre utilis pour plusieurs boutons. Lobjet sur lequel lutilisateur clique est pass la fonction couteur via currentTarget. Dans le cas prsent, nous utilisons cette valeur pour addChild. Vous pouvez cependant aussi la comparer une liste dobjets sur lesquels lutilisateur est susceptible de cliquer et excuter du code en fonction de lobjet dsign.

Lors du dveloppement de nos jeux, nous ne cesserons de crer des groupes de Sprite pour contenir diffrents types dlments de jeu. Si nous utilisons des Sprite simplement pour les calques, nous les conserverons tous 0, 0 et pourrons dplacer des lments de Sprite en Sprite sans changer leur position relative lcran.

Chapitre 2

Composants de jeu ActionScript

61

Dnir la profondeur du Sprite


Le moment est sans doute bien choisi pour signaler maintenant la commande setChildIndex, qui permet de dplacer les objets dafchage vers le haut et le bas dans la liste dafchage. Elle offre en dautres termes la possibilit de placer un Sprite au-dessus dun autre. La liste dafchage peut se comparer un tableau qui commence par llment 0. Si vous avez cr trois Sprite, ceux-ci se trouvent aux positions 0, 1 et 2. La position 2 correspond au Sprite du haut, qui est dessin au-dessus des autres. Si vous souhaitez dplacer un Sprite vers le bas, autrement dit sous les autres Sprite, utilisez simplement la commande suivante :
setChildIndex(myMovieClip,0);

Ce code place lobjet dafchage myMovieClip la position 0, tandis que tous les autres remontent dun cran pour remplir lespace laiss libre par lobjet dplac. Il est un petit peu plus compliqu de placer un Sprite au-dessus des autres. Vous devez attribuer lindex la valeur du dernier lment dans la liste dafchage. Sil y a trois lments (0, 1 et 2), vous devez donc lui attribuer la valeur 2. Vous pouvez le faire laide de la proprit numChildren :
setChildIndex(myMovieClip,numChildren-1);

Vous devez utiliser -1 parce que, sil existe trois enfants (0, 1 et 2), numChildren retourne 3. Or il faut ici utiliser 2 dans setChildIndex. Le nombre 3 gnrerait une erreur. Lanimation dexemple SettingSpriteDepth.a place lcran trois Sprite qui se superposent les uns aux autres. Vous pouvez cliquer sur chacun dentre eux pour les amener au premier plan.

Accepter les entres de lutilisateur


Les sections qui suivent traitent de la rcupration des entres du joueur. Elles proviennent toujours du clavier ou de la souris car il sagit des seuls priphriques de saisie standard sur les ordinateurs modernes.

Entre souris
Nous savons dj bien comment transformer un Sprite en un bouton et lamener ragir aux clics de souris. La souris ne sert cependant pas qu cliquer. Vous pouvez aussi rcuprer la position du curseur tout moment et les Sprite peuvent dtecter si le curseur les survole. Pour dterminer tout moment lemplacement sur la scne du curseur, utilisez les proprits mouseX et mouseY. Le code qui suit rcupre lemplacement courant du curseur et le place dans un champ texte chaque image :
addEventListener(Event.ENTER_FRAME, showMouseLoc); function showMouseLoc(event:Event) { mouseLocText.text = X=+mouseX+ Y=+mouseY; }

62

ActionScript 3.0 pour les jeux

Pour dtecter le moment o le curseur survole un Sprite, vous pouvez procder de la mme manire que lorsque vous dtectez un clic de souris. Au lieu dun clic, vous devez cependant rechercher un vnement rollover. Un couteur destin cela peut tre ajout au Sprite :
mySprite.addEventListener(MouseEvent.ROLL_OVER, rolloverSprite); function rolloverSprite(event:MouseEvent) { mySprite.alpha = 1; }

Dans cette fonction, nous attribuons la valeur 1 la proprit alpha du Sprite, ce qui le rend opaque 100 %. Ensuite, lorsque le curseur quitte le Sprite, nous la rduisons 50 % :
mySprite.addEventListener(MouseEvent.ROLL_OUT, rolloutSprite); function rolloutSprite(event:MouseEvent) { mySprite.alpha = .5; }

Dans lanimation MouseInput.a, le Sprite commence 50 % dopacit et ne passe 100 % que lorsque le curseur le survole. La Figure 2.12 prsente les valeurs dans le champ texte de lemplacement du curseur et ce Sprite.

Entre clavier
La dtection des entres clavier sappuie sur les deux vnements clavier KEY_UP et KEY_DOWN. Lorsque lutilisateur enfonce une touche, le message KEY_DOWN est envoy. Si vous dnissez un couteur pour le surveiller, vous pouvez en tirer parti. La fonction addEventListener doit cependant rfrencer lobjet scne. En effet, les appuis sur les touches nont pas de cible vidente comme les clics de souris. Un objet doit donc recevoir le focus clavier au dmarrage de lanimation. Cest la scne que revient ce privilge :
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownFunction);

Lorsquune fonction rcupre lappel de cet couteur, elle peut accder plusieurs proprits du paramtre de lvnement. Lun de ces paramtres est charCode, qui retourne le numro de caractre de la touche enfonce.
keyboardText

Dans lexemple suivant, le charCode est converti en un caractre puis afch dans le champ texte :
function keyDownFunction(event:KeyboardEvent) { keyboardText.text = "Key Pressed: "+String.fromCharCode(event.charCode); }

Noubliez pas de slectionner Contrle > Dsactiver les raccourcis clavier au moment de vos tests. Sans cela, vos appuis sur les touches pourraient ne pas parvenir jusqu la scne.

Chapitre 2

Composants de jeu ActionScript

63

Figure 2.12
Le curseur survole le sprite, qui devient donc opaque.

Parmi les proprits de lvnement gure galement keyCode, qui sapparente charCode mais nest pas affecte par la touche Maj. Par exemple, lorsque la touche Maj est enfonce, la touche A donne le charCode 65 pour un A majuscule. Lorsque la touche est relche, le charCode est 97, ce qui reprsente un a minuscule. la diffrence, keyCode retourne 65 dans les deux cas. Parmi les autres proprits, on peut encore citer ctrlKey, shiftKey et altKey, qui indiquent si ces touches de modication sont enfonces. Dans les jeux, on ne se soucie gnralement pas de lappui initial sur la touche, mais du fait que le joueur continue la maintenir enfonce. Par exemple, dans un jeu de conduite, il faut savoir si le joueur conserve lacclrateur enfonc, que reprsente la touche che du haut. Pour reconnatre quune touche est enfonce, la stratgie consiste rechercher la fois KEY_DOWN et Si nous dtectons quune touche est enfonce, nous positionnons une variable boolenne correspondant true. Ensuite, lorsque la mme touche est relche, nous la positionnons false. Pour dterminer tout moment si la touche est enfonce, il suft ds lors de vrier la valeur de la variable boolenne.
KEY_UP.

Voici du code qui teste la barre despace de cette manire. La premire fonction repre quel moment la barre despace est enfonce et positionne la variable spacePressed true :
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownFunction); function keyDownFunction(event:KeyboardEvent) { if (event.charCode == 32) { spacebarPressed = true; } }

64

ActionScript 3.0 pour les jeux

La fonction suivante capture le relchement dune touche. Sil sagit de la barre despace, keyPressed est positionne false :
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpFunction); function keyUpFunction(event:KeyboardEvent) { if (event.charCode == 32) { spacebarPressed = false; } }

Cette mthode permet de surveiller les touches essentielles pour le jeu, comme la barre despace et les quatre touches ches. Lanimation dexemple KeyboardInput.a surveille la barre despace de cette manire et afche un message lorsque son tat change.

Entre texte
Parmi les autres types dobjets TextField gure le champ de saisie. La diffrence entre un champ texte statique ou dynamique et le champ de saisie tient ce que lutilisateur peut slectionner et taper du texte dans le champ de saisie. Pour crer un TextField qui agit comme un champ de saisie, dnissez simplement sa proprit type :
var myInput:TextField = new TextField(); myInput.type = TextFieldType.INPUT; addChild(myInput);

Ce code cre un champ de saisie difcile reprer et bien mal form dans le coin suprieur gauche de lcran. Il est cependant possible de lamliorer en dnissant ses proprits et en utilisant un objet TextFormat. Le code qui suit xe le format 12 points dans la police Arial, positionne le champ 10, 10 avec une hauteur de 18 et une largeur de 200. Il active galement la bordure comme on sattendrait en voir pour nimporte quel champ de saisie dans un logiciel classique :
var inputFormat:TextFormat = new TextFormat(); inputFormat.font = "Arial"; inputFormat.size = 12; var myInput:TextField = new TextField(); myInput.type = TextFieldType.INPUT; myInput.defaultTextFormat = inputFormat; myInput.x = 10; myInput.y = 10; myInput.height = 18;

Chapitre 2

Composants de jeu ActionScript

65

myInput.width = 200; myInput.border = true; addChild(myInput); stage.focus = myInput;

La dernire ligne de code place le curseur de saisie de texte dans le champ. En gnral, les TextField sont congurs pour ne reprsenter quune seule ligne de texte. Cette particularit peut cependant tre modie avec la proprit multiline. Pour la plupart des entres texte, vous naurez toutefois besoin que dune seule ligne. Cela signie que les touches Retour/Entre ne seront pas reconnues, car il nest pas possible de crer une seconde ligne de texte. Cette touche peut nanmoins tre capture et utilise pour signaler la n de la saisie. Pour capturer la touche Retour, vous devez placer un couteur sur lvnement de relchement de touche. Ensuite, la fonction rpondante doit vrier si la touche enfonce possde le numro de code 13, qui correspond la touche Retour :
myInput.addEventListener(KeyboardEvent.KEY_UP, checkForReturn); function checkForReturn(event:KeyboardEvent) { if (event.charCode == 13) { acceptInput(); } }

La fonction acceptInput prend le texte du champ de saisie et le stocke dans theInputText. Ensuite, elle le transmet la fentre Sortie et supprime le champ texte :
function acceptInput() { var theInputText:String = myInput.text; trace(theInputText); removeChild(myInput); }

En testant cette animation, je me suis rendu compte que lenvironnement de test interceptait parfois la touche Retour, mme en cochant loption Dsactiver les raccourcis clavier dans la barre des menus. Dans ce cas, cliquez sur la fentre et essayez nouveau pour obtenir le rsultat dsir. Ce problme ne doit pas se poser lorsque lanimation est dploye sur le Web.

Lanimation dexemple TextInput.a contient le code prcdent que vous pouvez tester directement.

66

ActionScript 3.0 pour les jeux

Crer une animation


Nous allons maintenant examiner du code ActionScript qui permet de dplacer des Sprite lcran. Nous tudierons cette occasion quelques mthodes qui permettent ce mouvement dimiter des dplacements rels.

Mouvement des sprites


x

Pour changer la position dun Sprite ou dun clip, rien de plus simple : il suft de dnir sa position ou y. Pour animer lun dentre eux, il suft donc de les modier intervalles rguliers.

Grce lvnement ENTER_FRAME, il est possible de programmer facilement ce type de changement rgulier. Par exemple, voici un programme court qui cre une copie dun clip dans la bibliothque et le dplace dun pixel vers la droite chaque image :
var hero:Hero = new Hero(); hero.x = 50; hero.y = 100; addChild(hero); addEventListener(Event.ENTER_FRAME, animateHero); function animateHero(event:Event) { hero.x++; }

Le personnage du hros se dplace maintenant dans la scne, en avanant dun pixel la fois. Au lieu de progresser dun pixel chaque fois, vous pourriez cependant avancer de 10 avec += 10 au lieu de ++. Lautre moyen de faire acclrer le hros consiste augmenter simplement la cadence dimages. Au lieu des 12 ips (images par seconde) par dfaut, vous pourriez par exemple passer 60 ips. Cette modication sopre dans le coin suprieur gauche de linspecteur des proprits lorsque la scne est slectionne. La Figure 2.13 prsente linspecteur des proprits lorsque la cadence dimages est xe 12 ips.
Figure 2.13
Linspecteur des proprits permet de modier la cadence dimages de lanimation.

Chapitre 2

Composants de jeu ActionScript

67

Que vous choisissiez une cadence dimages de 60 ips nimplique pas ncessairement que lanimation tournera 60 ips. Elle tentera seulement de le faire. Sil se passe beaucoup de choses dans cette animation et si lordinateur de lutilisateur est plutt lent, il nest pas sr que la cadence relle atteigne les 60 ips. Nous traiterons sous peu des animations temporelles, qui constituent une bonne alternative aux animations images.

Au lieu de nous contenter de faire glisser le hros lcran, nous pouvons le faire marcher. Il nous faut cependant laide dun artiste animateur. Celui-ci doit crer plusieurs images correspondant un cycle de marche et les placer dans des images squentielles du clip Hero. La Figure 2.14 prsente ce cycle de marche.
Figure 2.14
Cycle de marche simple dcompos en sept images.

Il ne nous reste plus qu rcrire la fonction animateHero an que le personnage se dplace de limage 2 limage 8 du clip, qui reprsentent les sept images de lanimation. Limage 1 est rserve la position statique debout. Lartiste animateur nous indique galement que le personnage doit avancer de 7 pixels par image sur le plan horizontal an que lanimation de la marche soit naturelle. Le code rsultant vrie la proprit currentFrame du clip et, sil se trouve limage 8, le ramne limage 2. Sans cela, le clip passerait simplement limage suivante :
function animateHero(event:Event) { hero.x += 7; if (hero.currentFrame == 8) { hero.gotoAndStop(2); } else { hero.gotoAndStop(hero.currentFrame+1); } }

Testez lanimation dexemple SpriteMovement.a pour voir ce code en action. Testez en outre diffrentes cadences dimages pour le voir avancer plus ou moins rapidement.

68

ActionScript 3.0 pour les jeux

Utiliser des Timer


Les Timer (minuteurs) peuvent se comparer de petites horloges messages. Vous en crez une et la lancez, puis elle se met cliquer et transmet des messages intervalles dnis. Par exemple, vous pouvez crer un Timer pour appeler une fonction spcique toutes les secondes. Pour dnir un Timer, vous devez crer un nouvel objet Timer. Vous devez lui passer le nombre de millisecondes entre les vnements. Vous pouvez galement passer un second paramtre pour le nombre dvnements gnrer avant larrt, mais nous ne nous en servirons pas ici. Le code qui suit cre un nouveau Timer qui dclenche un vnement toutes les 1 000 millisecondes ( chaque seconde). Il appelle la fonction timerFunction pour chacun de ces vnements :
var myTimer:Timer = new Timer(1000); myTimer.addEventListener(TimerEvent.TIMER, timerFunction);

Pour tester le Timer, il suft de lamener dessiner un petit cercle chaque vnement. Le paramtre event transmis dans la fonction inclut une proprit target qui fait rfrence au Timer. Vous pouvez lutiliser pour accder la proprit currentCount, qui contient le nombre de fois o le Timer a t dclench. Nous utiliserons cette technique pour dcaler chaque cercle et dessiner une ligne de cercles de gauche droite :
function timerFunction(event:TimerEvent) { this.graphics.beginFill(0x000000); this.graphics.drawCircle(event.target.currentCount*10,100,4); }

Le fait de crer le Timer et dattacher un couteur ne suft pas. Vous devez galement demander au Timer de dmarrer. Pour cela, utilisez la commande start() :
myTimer.start();

Lanimation UsingTimers.a illustre le fonctionnement du code prcdent. Vous pouvez galement utiliser un Timer pour raliser les mmes tches que celles prsentes dans la prcdente section avec les vnements enterFrame. Voici un Timer qui appelle la mme fonction animateHero pour dplacer le personnage dans lcran en lui faisant suivre un cycle de marche. Il remplace lappel addEventListener :
var heroTimer:Timer = new Timer(80); heroTimer.addEventListener(TimerEvent.TIMER, animateHero); heroTimer.start();

Ce code est illustr dans le chier UsingTimers2.a. Lorsque vous lexcutez, le personnage marche une allure correspondant une cadence de 12 ips. Vous pouvez cependant xer la cadence dimages 12, 6 ou 60 : la marche seffectuera toujours la mme vitesse.

Chapitre 2

Composants de jeu ActionScript

69

Essayez de xer la cadence dimages 1 ips. Avec le Timer qui dplace le personnage toutes les 80 millisecondes, ce dernier fera bien du chemin entre les mises jour de lcran. Cet exemple montre que les Timer peuvent tre utiliss pour crer un mouvement identique sur tous les ordinateurs jusquaux plus lents pour autant que les calculs raliss avec chaque vnement Timer ne surmnent pas le processeur.

Animation temporelle
Les animations en temps rel impliquent que les tapes de lanimation tiennent compte du temps coul et non dintervalles temporels arbitraires. Une tape danimation temporelle doit dabord calculer le temps coul depuis la dernire tape. Ensuite, elle dplace les objets en fonction de cette dure calcule. Par exemple, si le premier intervalle de temps est 0,1 seconde et le second, 0,2, les objets vont deux fois plus loin aprs le second intervalle de temps de manire oprer une progression continue. La premire chose faire est de crer une variable qui contient le temps de la dernire tape. Nous commencerons par placer la mesure temporelle courante rcupre partir de la fonction systme getTimer(). Cette fonction retourne le temps en millisecondes depuis que le lecteur Flash a dmarr :
var lastTime:int = getTimer();

Ensuite, nous allons crer un couteur dvnements li lvnement ENTER FRAME qui appelle animateBall :
addEventListener(Event.ENTER_FRAME, animateBall);

La fonction animateBall calcule la diffrence temporelle et positionne la variable lastTime an de prparer ltape suivante. Elle dnit ensuite lemplacement x dune instance de clip appele ball. Elle ajoute timeDiff multipli par 0,1. Le clip se dplace ainsi de 100 pixels toutes les 1 000 millisecondes :
function animateBall(event:Event) { var timeDiff:int = getTimer()-lastTime; lastTime += timeDiff; ball.x += timeDiff*.1; }

Lanimation TimeBasedAnimation.a utilise ce code pour dplacer une balle lcran. Commencez par la tester avec une cadence dimages de 12 ips. Ensuite, testez-la 60 ips. Vous remarquerez que la balle parvient de lautre ct de lcran au mme moment, mais que le mouvement parat bien plus uide 60 ips.

70

ActionScript 3.0 pour les jeux

Animation physique
Avec les animations ActionScript, vous pouvez faire bien plus quamener un objet se dplacer le long dun chemin prdni. Vous pouvez aussi lui donner des proprits physiques et le faire bouger comme un objet rel. Lanimation physique peut tre images ou temporelle. Nous allons poursuivre avec un exemple danimation temporelle, mais en utilisant la vlocit et la gravit pour indiquer lendroit vers lequel lobjet doit se dplacer.

La gravit est une acclration constante vers le sol (dans le cas prsent, vers le bas de lcran). Dans la ralit, la gravit est de 9,8 mtres/seconde ou de 32 pieds/seconde. Dans lunivers du lecteur Flash, tout se mesure en pixel par milliseconde. Une mise lchelle doit donc tre effectue par rapport au monde rel. Par exemple, si 1 pixel correspond 1 mtre, 0,0098 correspond 0,0098 mtre/milliseconde ou 9,8 mtres/seconde. Vous pouvez cependant tout aussi bien utiliser 0,001 ou 7 ou bien encore tout autre nombre, tant que ce rglage parat naturel dans votre jeu. Lide est de crer non pas des simulations scientiques mais des jeux.

Nous xerons la gravit 0,0098 et dnirons une vlocit de dpart pour llment mouvant. La vlocit dsigne tout simplement la vitesse et la direction dun objet en mouvement. dx et dy, qui reprsentent le changement des positions horizontale et verticale dnissent ensemble la vlocit :
// Dnition de la gravit var gravity:Number = .00098; var b:Number = .05; // Dnition de la vlocit de dpart var dx:Number = .2; var dy:Number = -.8;

Lobjet (dans le cas prsent, une balle) doit donc se dplacer de 0,2 pixel lhorizontale toutes les millisecondes et de 0,8 pixel verticalement chaque milliseconde. Autrement dit, il est lanc vers le haut et la droite. Pour contrler lanimation, nous allons crer un couteur ENTER FRAME et initialiser la variable lastTime :
// Marquer linstant de dpart et ajouter un couteur var lastTime:int = getTimer(); addEventListener(Event.ENTER_FRAME, animateBall);

Chapitre 2

Composants de jeu ActionScript

71

La fonction animateBall commence par calculer le temps coul depuis la dernire tape de lanimation :
// Animation par tapes function animateBall(event:Event) { // Calculer le temps coul var timeDiff:int = getTimer()-lastTime; lastTime += timeDiff;

La variable dy dnit la vitesse verticale et doit changer selon la traction de la gravit mesure par la diffrence temporelle :
// Ajuster la vitesse verticale pour la gravit dy += gravity*timeDiff;

La balle se dplace en fonction de deux variables : dx et dy. Dans les deux cas, la diffrence temporelle (timeDiff) est utilise pour dterminer la distance :
// Dplacer la balle ball.x += timeDiff*dx; ball.y += timeDiff*dy; }

Si vous excutez lanimation PhysicsBasedAnimation.a, vous obtiendrez un rsultat comparable celui de la Figure 2.15.
Figure 2.15
Cette capture dcran lente fait apparatre les diffrentes positions de la balle 12 ips.

72

ActionScript 3.0 pour les jeux

Programmer linteraction avec lutilisateur


Au-del de lentre utilisateur et du mouvement des sprites, il est encore possible de combiner les deux : lorsque linteraction de lutilisateur affecte les lments lcran. Les programmes suivants sont de petits exemples dinteraction de lutilisateur avec des sprites.

Dplacer des sprites


Les sprites lcran se dplacent gnralement avec la souris ou le clavier. Pour le clavier, ce sont le plus souvent les touches ches qui servent contrler le sprite. Prcdemment dans ce chapitre, vous avez vu comment dterminer si la barre despace a t enfonce. Il est possible dutiliser la mme procdure pour dterminer si les touches ches sont enfonces. Bien que ces dernires ne possdent pas de reprsentation visible sous forme de caractre, elles peuvent tre reprsentes par les codes de touche 37, 38, 39 et 40. La Figure 2.16 prsente les quatre touches ches et leurs codes correspondants.
Figure 2.16
Les quatre touches ches peuvent tre rfrences par ces quatre codes de touche.

38

37

40

39

Nous commenons par crer quatre variables boolennes pour y stocker ltat des quatre touches ches :
// Initialiser les variables des touches ches var leftArrow:Boolean = false; var rightArrow:Boolean = false; var upArrow:Boolean = false; var downArrow:Boolean = false;

Il nous faut la fois des couteurs KEY DOWN et KEY UP, ainsi quun couteur ENTER FRAME pour grer le dplacement du sprite chaque mise jour de lcran :
// Dnition des couteurs vnementiels stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedDown); stage.addEventListener(KeyboardEvent.KEY_UP, keyPressedUp); stage.addEventListener(Event.ENTER_FRAME, moveMascot);

Chapitre 2

Composants de jeu ActionScript

73

Lorsque lutilisateur enfonce une touche che, nous positionnons sa variable boolenne true :
// Positionnement true des variables des touches ches function keyPressedDown(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = true; } else if (event.keyCode == 39) { rightArrow = true; } else if (event.keyCode == 38) { upArrow = true; } else if (event.keyCode == 40) { downArrow = true; } }

De la mme manire, lorsque lutilisateur relche les touches ches, nous positionnons la variable boolenne correspondante false :
// Positionnement false des variables des touches ches function keyPressedUp(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = false; } else if (event.keyCode == 39) { rightArrow = false; } else if (event.keyCode == 38) { upArrow = false; } else if (event.keyCode == 40) { downArrow = false; } }

Nous pouvons maintenant utiliser ces variables boolennes pour dplacer le clip de la mascotte dune quantit dnie dans la direction approprie. Nous stockerons la quantit de mouvement dans la variable speed, au lieu de la rpter quatre fois dans le code :
// Dplacement chaque image function moveMascot(event:Event) { var speed:Number = 5; if (leftArrow) { mascot.x -= speed; } if (rightArrow) { mascot.x += speed; } if (upArrow) { mascot.y -= speed;

74

ActionScript 3.0 pour les jeux

} if (downArrow) { mascot.y += speed; } }

Lanimation MovingSprites.a prsente ce code en action. Vous remarquerez que, puisque nous testons sparment chacune des variables boolennes des touches ches, il est possible de combiner ces touches. Par exemple, vous pouvez appuyer sur les touches de droite et du bas pour faire avancer la mascotte vers le bas et la droite la fois. Si vous maintenez les touches gauche et droite simultanment enfonces, la mascotte ne se dplace pas (les deux mouvements sannulant).

Faire glisser des sprites


Lun des autres moyens de dplacer un Sprite dans la scne consiste permettre lutilisateur de cliquer dessus et de le faire glisser. Au lieu de surveiller le clavier, nous surveillerons donc cette fois la souris. Lorsque lutilisateur clique sur le sprite, nous faisons commencer le glissement. Lorsque lutilisateur relche le bouton de la souris, nous linterrompons. Nous ne pouvons cependant pas compter sur le fait que le curseur se trouve sur le sprite lorsque lutilisateur relche le bouton. Nous allons donc tester lvnement MOUSE_DOWN sur le sprite mascot, mais lvnement MOUSE_UP sur la scne. La scne rcupre en effet un vnement MOUSE_UP que le curseur se trouve ou non sur le sprite :
// Dnition des couteurs mascot.addEventListener(MouseEvent.MOUSE_DOWN, startMascotDrag); stage.addEventListener(MouseEvent.MOUSE_UP, stopMascotDrag); mascot.addEventListener(Event.ENTER_FRAME, dragMascot);

Lautre facteur prendre en compte est le dcalage du curseur. Nous souhaitons permettre lutilisateur de faire glisser le sprite en saisissant nimporte quel point du sprite. Si le joueur clique sur le coin infrieur droit du sprite, le curseur et le coin infrieur droit continuent de conserver la mme position relative pendant le glissement. Pour cela, nous allons dterminer le dcalage entre lemplacement 0, 0 du sprite et lemplacement du clic de souris et le stocker dans clickOffset. Nous utiliserons aussi cette variable pour dterminer si un glissement se produit ce moment. Si cest le cas, clickOffset se verra attribuer un objet Point. Sinon il sera null :
// Dcalage entre lemplacement du sprite et le clic var clickOffset:Point = null;

Chapitre 2

Composants de jeu ActionScript

75

Lorsque lutilisateur clique sur le sprite, le dcalage est rcupr partir des proprits localX et localY de lvnement de clic :
// Lutilisateur a cliqu function startMascotDrag(event:MouseEvent) { clickOffset = new Point(event.localX, event.localY); }

Lorsque lutilisateur relche le curseur, le clickOffset est ramen null :


// Lutilisateur a relch le bouton de la souris function stopMascotDrag(event:MouseEvent) { clickOffset = null; }

Ensuite, chaque image, si clickOffset nest pas null, nous allons dnir la position de la mascotte en lui attribuant lemplacement courant du curseur auquel nous soustrayons le dcalage :
// Excuter chaque image function dragMascot(event:Event) { if (clickOffset != null) { // must be dragging mascot.x = mouseX - clickOffset.x; mascot.y = mouseY - clickOffset.y; } }

Observez le chier DraggingSprites.a pour voir comment ce code fonctionne. Essayez de faire glisser la mascotte de diffrents points an de voir comment clickOffset gre ces diffrences.

Dtection de collisions
Une fois que vos objets se dplaceront lcran dans votre jeu, il arrivera trs couramment que vous deviez vrier sils entrent en collision les uns avec les autres. ActionScript 3.0 contient deux fonctions de dtection de collision natives. La fonction hitTestPoint teste un emplacement de point an de voir sil se trouve lintrieur dun objet dafchage. La fonction hitTestObject compare deux objets dafchage lun lautre an de voir sils se chevauchent. Pour examiner ces deux fonctions, crons un exemple simple qui examine lemplacement du curseur et lemplacement dun sprite qui se dplace chaque image :
addEventListener(Event.ENTER_FRAME, checkCollision);

La fonction checkCollision commence par utiliser hitTestPoint en recherchant lemplacement du curseur an de voir sil touche le clip du croissant dans la scne. Les deux premiers paramtres de la fonction hitTestPoint sont lemplacement x et y du point. Le troisime paramtre correspond au type de limite utiliser. La valeur par dfaut, false, signie que seul le rectangle de contour de lobjet dafchage doit tre pris en compte.

76

ActionScript 3.0 pour les jeux

moins que le sprite ne possde la forme dun rectangle, cela ne suft pas pour la plupart des usages pratiques dans les jeux. En positionnant le troisime paramtre true, hitTestPoint utilisera cette fois la forme effective de lobjet dafchage an de dterminer la collision. Nous placerons un texte diffrent dans un champ texte de message selon le rsultat de hitTestPoint :
function checkCollision(event:Event) { // Vrier lemplacement du curseur par rapport au croissant if (crescent.hitTestPoint(mouseX, mouseY, true)) { messageText1.text = "hitTestPoint: YES"; } else { messageText1.text = "hitTestPoint: NO"; }

La fonction hitTestObject ne propose pas doption de forme. Elle ne fait que comparer les deux rectangles de contour des deux sprites. Elle peut cependant tre utile dans certains cas. Le fragment de code suivant amne un clip dtoile suivre le curseur et place un message diffrent dans un autre champ texte si les rectangles de contour entrent en intersection :
// Dplacer ltoile avec la souris star.x = mouseX; star.y = mouseY; // Vrier si ltoile touche le croissant if (star.hitTestObject(crescent)) { messageText2.text = "hitTestObject: YES"; } else { messageText2.text = "hitTestObject: NO"; } }

Lanimation dexemple CollisionDetection.a illustre cet exemple. La Figure 2.17 montre que le curseur se trouve lintrieur du rectangle de contour du croissant ; comme nous testons hitTestPoint avec le drapeau de forme positionn true, aucune collision nest enregistre moins que le curseur ne se trouve effectivement au-dessus du croissant. Ltoile et le croissant, pendant ce temps, entrent en collision lorsque leurs rectangles de contour entrent en intersection.
Figure 2.17
Les emplacements du curseur et de ltoile sont tests an de vrier sils entrent en collision avec le croissant.

Chapitre 2

Composants de jeu ActionScript

77

Accder des donnes externes


Parfois, il peut tre ncessaire daccder des informations situes hors du jeu. Vous pouvez charger des paramtres de jeu externes depuis des pages Web ou des champs texte. Vous pouvez galement enregistrer et charger des informations localement.

Variables externes
Supposons que vous ayez un jeu susceptible de varier en fonction de certaines options, comme un jeu de puzzle qui pourrait utiliser diffrentes images ou un jeu darcade qui pourrait sexcuter diffrentes vitesses. Vous pouvez alimenter les valeurs des variables dans lanimation Flash partir de la page HTML dans laquelle elle se trouve. Il existe plusieurs moyens de sy prendre. Si vous utilisez le modle HTML par dfaut des paramtres de publication, vous pouvez passer des valeurs de paramtre via la proprit ashvars de la fonction AC_FL_RunContent.

Lanimation Flash est incorpore dans la page Web laide des balises OBJECT et EMBED pour les architectures ActiveX (Internet Explorer) et Plug-In (Firefox). Les balises OBJECT et EMBED sont cependant leur tour crites par un morceau de JavaScript fourni par Adobe et livr dans le chier AC_RunActiveContent.js. Selon vos paramtres de publication, vous obtiendrez une copie de ce chier chaque publication.

Voici une version raccourcie de lappel AC_FL_RunContent que vous trouverez dans le chier HTML export lors de la publication depuis Flash CS3. Il inclut un paramtre ashvars ajout par mes soins :
<script language="JavaScript"> AC_FL_RunContent( codebase, http://download.macromedia.com/pub/shockwave/cabs/ash/swash.cab#version=9,0,0,0, width, 550, height, 400, src, ExternalVariables, quality, high, ashvars, puzzleFile=mylename.jpg&difcultyLevel=7 ); </script>

78

ActionScript 3.0 pour les jeux

Le format ashvars est une srie de paires nom de proprit = valeur spares par le symbole &. Dans cet exemple, la proprit puzzleFile se voit donc attribuer la valeur mylename.jpg, tandis que la proprit difcultyLevel reoit la valeur 7. Lorsque lanimation Flash dmarre, elle peut obtenir ces valeurs en utilisant lobjet LoaderInfo. La ligne suivante rcupre tous les paramtres et les place dans un objet :
var paramObj:Object = LoaderInfo(this.root.loaderInfo).parameters;

Pour accder une valeur individuelle, il vous suft dutiliser une ligne de code de ce genre :
var diffLevel:String = paramObj["difcultyLevel"];

Vous pouvez passer nimporte quel nombre de constantes de jeu, comme des noms dimage, des niveaux de dpart, des vitesses, des positions, etc. Un jeu de pendu peut ainsi tre congur avec un autre mot ou une autre phrase. Un jeu dexploration terrestre peut se voir attribuer un autre emplacement pour le point de dpart. Lors de lexcution de lanimation ExternalVariables.a, gardez lesprit que le principe consiste charger la page ExternalVariables.html dans votre navigateur. Cette page contient tous les paramtres ashvars dnis. Si vous essayez deffectuer votre test dans Flash ou de crer une nouvelle page HTML, ces paramtres manqueront.

Charger des donnes


Le chargement de donnes depuis un chier texte externe est relativement facile. Sil sagit dun chier au format XML, la procdure seffectue mme de manire idale. Par exemple, supposons que vous souhaitiez charger une question dans un quiz partir dun chier. Les donnes XML pourraient ressembler ceci :
<LoadingData> <question> <text>This is a test</text> <answers> <answer type="correct">Correct answer</answer> <answer type="wrong">Incorrect answer</answer> </answers> </question> </LoadingData>

Pour charger les donnes, vous devez utiliser deux objets : un URLRequest et un URLLoader. Ensuite, vous effectuez une coute pour vrier que le chargement est complet et vous appelez lune de vos propres fonctions :
var xmlURL:URLRequest = new URLRequest("LoadingData.xml"); var xmlLoader:URLLoader = new URLLoader(xmlURL); xmlLoader.addEventListener(Event.COMPLETE, xmlLoaded);

Chapitre 2

Composants de jeu ActionScript

79

Le xmlLoaded, dans le cas prsent, correspond simplement des instructions trace an de montrer que des donnes ont t importes :
function xmlLoaded(event:Event) { var dataXML = XML(event.target.data);

trace(dataXML.question.text); trace(dataXML.question.answers.answer[0]); trace(dataXML.question.answers.answer[0].@type); }

Vous voyez quel point il est facile de rcuprer les donnes XML du chier. Lobjet XML tant dataXML, vous pouvez rcuprer le texte de la question avec dataXML.question.text et la premire rponse avec dataXML.question.answers[0]. Vous pouvez rcuprer un attribut, comme le type de la rponse, en utilisant @type. Lexemple LoadingData.a lit ses donnes partir du chier LoadingData.xml. Essayez de modier et dajouter des donnes au chier XML. Ensuite, lancez lanimation avec les instructions trace an daccder aux diffrentes parties des donnes.

Enregistrer des donnes locales


Lun des besoins courants en matire de dveloppement de jeu consiste stocker des donnes locales. Par exemple, vous pourriez stocker le prcdent score du joueur ou certaines options de votre jeu. Pour stocker des donnes sur lordinateur de lutilisateur, nous allons utiliser un objet SharedObject local. Laccs un SharedObject seffectue par la mme opration que sa cration. Le fait de demander sil existe le cre. Pour cela, attribuez une variable au SharedObject dun certain nom, avec la fonction getLocal :
var myLocalData:SharedObject = SharedObject.getLocal("mygamedata");

Lobjet myLocalData peut prendre nimporte quel nombre de proprits de nimporte quel type : nombres, chanes, tableaux, autres objets, etc. Si vous aviez stock les mmes donnes dans une proprit de lobjet partag nomm gameinfo, vous pourriez y accder avec myLocalData.data.gameinfo :
trace("Found Data: "+myLocalData.data.gameinfo);

Dnissez donc cette proprit gameinfo, comme vous le feriez pour une variable standard :
myLocalData.data.gameinfo = "Store this.";

Essayez dexcuter lanimation test SavingLocalData.a. Elle utilise la fonction trace pour afcher la proprit myLocalData.data.gameinfo. Comme elle na pas t dnie, vous obtenez le rsultat undened. Ensuite, elle positionne la valeur. Lors de la seconde excution du test, vous obtenez ainsi "Store this." .

80

ActionScript 3.0 pour les jeux

lments de jeu divers


Voici quelques scripts simples qui ralisent diffrentes tches. La plupart dentre eux peuvent tre ajouts nimporte quelle animation de jeu en cas de besoin.

Curseurs personnaliss
Supposons que vous souhaitiez remplacer le curseur de souris standard par un curseur qui correspond mieux au style de votre jeu. Ou supposons encore que vous souhaitiez un curseur plus grand pour un jeu denfant ou un curseur en forme de cible pour un jeu de tir. Si vous ne pouvez pas modier le curseur de lordinateur, vous pouvez le faire disparatre, tout le moins visuellement. Ensuite, vous pouvez le remplacer par un sprite dont la position correspond celle du curseur et qui otte au-dessus de tous les autres lments. Pour rendre le curseur invisible, utilisez la commande Mouse.hide() :
Mouse.hide();

Ensuite, pour faire agir un sprite en tant que curseur, placez-le dans un calque au-dessus de tous les autres lments de lcran. La Figure 2.18 prsente le scnario avec trois claques. Le curseur est le seul lment du second calque et tous les autres lments se trouvent en dessous dans le troisime calque.
Figure 2.18
Le curseur doit rester au-dessus de tous les autres lments lcran.

Si vous crez des objets avec ActionScript, vous devez veiller conserver le curseur au-dessus de tous les objets. La commande setChildIndex vous permet ainsi de placer le curseur en haut aprs avoir cr les objets de votre jeu.

Pour amener un sprite suivre le curseur, il nous faut un couteur ENTER FRAME :
addEventListener(Event.ENTER_FRAME, moveCursor);

Chapitre 2

Composants de jeu ActionScript

81

Ensuite, la commande moveCursor amne simplement lobjet arrow, qui correspond ici au nom dinstance du curseur dans la scne, suivre lemplacement de la souris :
function moveCursor(event:Event) { arrow.x = mouseX; arrow.y = mouseY; }

Vous devez galement positionner la proprit mouseEnabled du sprite false. Sans cela, le curseur masqu se trouverait toujours au-dessus du sprite du curseur et jamais au-dessus des sprites qui se trouvent en dessous de lui, comme un bouton :
arrow.mouseEnabled = false;

Sans cette ligne de code, votre bouton ne fait pas apparatre son tat de survol lorsque vous le survolez et ne rceptionne pas correctement les clics de souris. Cette ligne de code rend le curseur personnalis invisible pour les vnements de souris. La Figure 2.19 prsente le curseur personnalis qui survole un bouton.
Figure 2.19
Le bouton prsente son tat de survol bien que le sprite arrow soit techniquement le premier sprite sous lemplacement de la souris.

Lanimation dexemple CustomCursor.a contient un bouton simple dans la scne an que vous puissiez tester le survol du curseur personnalis sur un bouton.

Lire des sons


Il existe deux principaux moyens de lire des sons en ActionScript 3.0 : en tant que sons de bibliothque interne ou en tant que chiers externes.

82

ActionScript 3.0 pour les jeux

La meilleure mthode pour la plupart des effets de son de jeu consiste incorporer les sons dans la bibliothque de lanimation du jeu. Vous pouvez le faire en important le son avec la commande de menu Fichier > Importer > Importer dans la bibliothque. Une fois que le son est dans la bibliothque, slectionnez-le et examinez sa bote de dialogue Proprits audio (voir Figure 2.20). Pour utiliser un son dans votre code ActionScript, vous devez dnir la liaison du son exporter pour ActionScript, puis attribuer la classe un nom que vous allez utiliser dans votre code. Pour cet exemple, nous utiliserons le nom Sound1. Pour lire le son, vous navez ds lors besoin que de deux lignes de code :
var sound1:Sound1 = new Sound1(); var channel:SoundChannel = sound1.play();

Si vous souhaitez tre plus concis, il est mme possible de procder en une seule ligne :
var channel:SoundChannel = (new Sound1()).play();

Figure 2.20
La bote de dialogue Proprits audio permet de dnir lidenticateur de classe pour un son an de pouvoir lutiliser dans le code ActionScript.

La lecture dun chier externe est lgrement plus difcile. Pour commencer, vous devez charger le son dans un objet. Le code suivant charge le chier son PlayingSounds.mp3 dans lobjet sound2 :
var sound2:Sound = new Sound(); var req:URLRequest = new URLRequest("PlayingSounds.mp3"); sound2.load(req);

Chapitre 2

Composants de jeu ActionScript

83

Ensuite, pour lire le son, vous devez utiliser la commande play :


sound2.play();

Lanimation dexemple PlayingSounds.a contient deux boutons : lun qui lit un son de bibliothque et lautre qui lit un son externe. Le son externe est charg ds que lanimation commence et se trouve donc prt tre lu tout moment.

Avec certains sons externes plus longs, il est possible que le son nait pas ni de se charger avant quil ne soit requis. Vous pouvez dtecter ce cas en utilisant la proprit isBuffering de lobjet son. Vous pouvez galement utiliser les proprits bytesLoaded et bytesTotal pour un suivi plus prcis. Si le son na pas ni de se charger, il commencera cependant jouer aussitt quil le sera. Pour les sons courts, il nest donc probablement pas utile de se proccuper ce sujet.

cran de chargement
Flash est conu pour une diffusion du contenu en ux continu. Cela signie que lanimation ne commence que lorsque le contenu minimal requis a bien t charg, comme les lments utiliss pour la premire image. Ce mcanisme convient merveille pour les animations. Vous pouvez proposer une animation cousue main de 1 000 images qui dmarre immdiatement et continue charger les lments requis pour les prochaines images mesure que lutilisateur en observe les prcdentes. Pour les jeux, il est cependant rare que lon procde de cette manire. Les lments de jeu sont utiliss presque immdiatement par le code ActionScript. Si lun dentre eux venait manquer parce quil ntait pas charg, le jeu pourrait ne pas fonctionner correctement. La plupart des jeux utilisent donc un cran de chargement qui force lanimation attendre que tous les lments aient dabord t tlchargs. Cet cran contribue aussi tenir le joueur inform de ltat du tlchargement. Lun des moyens simples de crer un cran de ce type consiste insrer une instruction stop dans la premire image de lanimation an que celle-ci ne commence sa lecture quune fois que vous le lui aurez indiqu spciquement :
stop();

Ensuite, dnissez un couteur ENTER FRAME pour appeler une fonction loadProgress chaque image :
addEventListener(Event.ENTER_FRAME, loadProgress);

84

ActionScript 3.0 pour les jeux

Cette fonction rcupre ltat de lanimation en utilisant this.root.loaderInfo. Elle a des proprits bytesLoaded et bytesTotal. Nous les prendrons et les convertirons galement en kilo-octets grce une division par 1 024 :
function loadProgress(event:Event) { // Rcuprer les octets chargs et le nombre total doctets var movieBytesLoaded:int = this.root.loaderInfo.bytesLoaded; var movieBytesTotal:int = this.root.loaderInfo.bytesTotal;

// Conversion en kilo-octets var movieKLoaded:int = movieBytesLoaded/1024; var movieKTotal:int = movieBytesTotal/1024;

Pour indiquer au joueur la progression du chargement, nous plaons du texte dans un champ texte qui se trouve dj dans limage 1 de lanimation. Le message donnera une information du type "Loading: 5K/32K" :
// Afcher la progression progressText.text = "Loading: "+movieKLoaded+"K/"+movieKTotal+"K";

Lorsque movieBytesLoaded atteint movieBytesTotal, nous supprimons lcouteur vnementiel et conduisons lanimation limage 2. Sil sagit du dbut dune squence anime, vous pouvez utiliser gotoAndPlay la place :
// Avancer si OK if (movieBytesLoaded >= movieBytesTotal) { removeEventListener(Event.ENTER_FRAME, loadProgress); gotoAndStop(2); } }

Lanimation dexemple LoadingScreen.a contient ce code dans la premire image. Elle contient aussi une image de 33 Ko dans la seconde image. Pour tester ce code, commencez par tester lanimation normalement en choisissant Contrle > Tester lanimation. Ensuite, dans lenvironnement de test, choisissez Afchage > Simuler le tlchargement. Ce rglage simule un tlchargement 4,7 Ko/ seconde et permet de voir lcran de chargement en action.

Nombres alatoires
Les nombres alatoires sont utiliss dans presque tous les jeux. Ils permettent de raliser des variations linni et contribuent simplier votre code. En ActionScript 3.0, la cration de nombres alatoires sopre avec la fonction Math.random. Elle retourne une valeur comprise entre 0,0 et 1,0 sans inclure 1,0 lui-mme.

Chapitre 2

Composants de jeu ActionScript

85

Le code suivant rcupre ainsi un nombre compris entre 0,0 et 1,0 sans inclure 1,0 :
var random1:Number = Math.random();

Le nombre retourn est gnr par un algorithme complexe dans le lecteur Flash. Il semble tre compltement alatoire. Pourtant, tant donn quil sagit dun algorithme, il nest techniquement pas compltement alatoire. Pour nos besoins en matire de dveloppement de jeux, nous naurons cependant pas nous en soucier et pourrons considrer que les nombres retourns sont compltement alatoires.

En gnral, vous souhaiterez dnir une plage plus spcique pour le nombre alatoire. Par exemple, vous pourriez souhaiter un nombre alatoire compris entre 0 et 10. Pour dnir ces plages, il suft de multiplier le rsultat de Math.random par la plage concerne :
var random2:Number = Math.random()*10;

Si vous souhaitez une valeur entire au lieu dun nombre virgule ottante, utilisez Math.oor pour arrondir les valeurs lentier infrieur. Le code suivant fournit un nombre alatoire compris entre 0 et 9 :
var random3:Number = Math.oor(Math.random()*10);

Si vous souhaitez dnir une plage qui ne commence pas 0, ajoutez la valeur requise au rsultat. Le code suivant donne un nombre alatoire compris entre 1 et 10 :
var random4:Number = Math.oor(Math.random()*10)+1;

Lanimation RandomNumbers.a prsente ces lignes de code avec une sortie dans le panneau Sortie.

Mlanger un tableau
Lun des usages les plus courants des nombres alatoires dans les jeux consiste congurer les pices du jeu au dbut dune partie. En gnral, cela implique un mlange des lments du jeu, comme des cartes ou des pices de jeu. Par exemple, supposons que vous ayez cinquante-deux pices de jeu mlanger dans un ordre alatoire, comme un croupier mlangerait des cartes avant de servir une main de poker ou de blackjack. Lopration consiste crer dabord le tableau des pices de jeu sous forme de simple tableau tri. Le code qui suit le fait avec les nombres 0 51 :
// Crer un tableau tri var startDeck:Array = new Array(); for(var cardNum:int=0;cardNum<52;cardNum++) { startDeck.push(cardNum); } trace(Unshufed:,startDeck);

86

ActionScript 3.0 pour les jeux

Le rsultat dans la fentre Sortie ressemble ceci :


Unshufed: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 ,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51

Pour mlanger le tableau de manire alatoire, nous choisissons une position alatoire lintrieur et prenons le nombre de cette position pour le placer dans un nouveau tableau. Ensuite, nous supprimons le nombre de lancien tableau. Nous poursuivons ainsi de manire rptitive jusqu ce que lancien tableau soit vid :
// Mlange dans un nouveau tableau var shufedDeck:Array = new Array(); while (startDeck.length > 0) { var r:int = Math.oor(Math.random()*startDeck.length); shufedDeck.push(startDeck[r]); startDeck.splice(r,1); } trace(Shufed:, shufedDeck);

Le rsultat ressemblera ceci (il sera videmment diffrent chaque fois que vous excuterez le programme) :
Shufed: 3,42,40,16,41,44,30,27,33,11,50,0,21,23,49,29,20,28,22,32,39,25,17,19,8,7,10,3 7,2,12,31,5,46,26,48,45,43,9,4,38,15,36,51,24,14,18,35,1,6,34,13,47

Lanimation dexemple ShufingAnArray.a prsente cette procdure.

Afcher une horloge


Il est possible dobtenir une mesure du temps courant avec la fonction getTimer(). Cette fonction indique le nombre de millisecondes qui se sont coules depuis le dmarrage du lecteur Flash. En gnral, les horloges internes des jeux notent le dbut du jeu en plaant la valeur getTimer() cet instant dans une variable. Par exemple, le jeu peut commencer 7,8 secondes aprs le dmarrage du lecteur Flash sil a fallu ce temps lutilisateur pour trouver le bouton "Jouer" et cliquer dessus. La valeur 7800 est alors stocke dans startTime. Ensuite, pour obtenir la mesure temporelle tout moment, il suft de soustraire startTime de la mesure de temps actuelle. Le joueur ne sintressera cependant que rarement des millisecondes brutes. Il souhaitera plutt voir quelque chose comme "1:34" pour 1 minute et 34 secondes. La conversion des millisecondes en un format dhorloge requiert simplement une division par 1 000 pour obtenir le nombre de secondes, puis par 60 pour obtenir le nombre de minutes.

Chapitre 2

Composants de jeu ActionScript

87

Voici un exemple de programme qui place un champ texte lcran, capture la mesure temporelle au dbut puis afche lhorloge chaque image. Il convertit la mesure temporelle en secondes et en minutes, en insrant un zro dans le nombre de secondes sil est infrieur dix :
var timeDisplay:TextField = new TextField(); addChild(timeDisplay); var startTime:int = getTimer(); addEventListener(Event.ENTER_FRAME, showClock); function showClock(event:Event) { // Millisecondes coules var timePassed:int = getTimer()-startTime; // Calcul des minutes et des secondes var seconds:int = Math.oor(timePassed/1000); var minutes:int = Math.oor(seconds/60); seconds -= minutes*60; // Cration de la chane dhorloge var timeString:String = minutes+":"+String(seconds+100).substr(1,2); // Afchage dans le champ texte timeDisplay.text = timeString; }

Examinons de plus prs la conversion de chane. Le nombre de minutes est rcupr directement partir de la variable minutes. Le signe deux-points est ajout ensuite. Le nombre de secondes est gr diffremment : 100 lui est ajout, de sorte que 7 secondes devient 107 secondes ; 52 devient 152 secondes, etc. Ensuite, il est converti en une chane avec le constructeur String. Nous rcuprons alors la sous-chane dmarrant au caractre 1 et de longueur 2. Comme nous commenons compter les caractres partir de 0, cela signie que nous obtenons 07 ou 52, sans inclure le 1 au dbut de 107 ou de 152. Le rsultat donne une chane comme 1:07 ou 23:52. Consultez lanimation dexemple DisplayingAClock.fla pour voir ce code en action.

Donnes systme
Il peut souvent tre ncessaire dobtenir des informations concernant le type dordinateur sur lequel votre jeu est excut. Ces indications pourraient affecter la manire dont vous souhaitez que votre jeu gre diffrentes situations ou le niveau de dtail que vous dsirez proposer. Par exemple, vous pouvez rcuprer la largeur et la hauteur de la scne avec les proprits stage. stageWidth et stage.stageHeight. Ces valeurs changent mme en temps rel si lanimation est congure pour sajuster la taille de la fentre du navigateur.

88

ActionScript 3.0 pour les jeux

Si votre animation est conue pour faire 640 pixels de large et que vous dtectiez quelle se lit sur 800 pixels de largeur, vous pouvez choisir dafcher plus de dtails an que le joueur prote de cette prcision renforce. Vous pouvez aussi choisir linverse dafcher moins dimages danimation, car plus lchelle est grande plus il faut de puissance pour le rendu. Vous pouvez encore utiliser lobjet Capabilities pour obtenir diffrents lments dinformation concernant lordinateur. Voici une liste pratique des lments qui vous affecteront le plus en tant que dveloppeur de jeux : Capabilities.playerType. Retourne External si vous testez lanimation, StandAlone si elle sexcute sous forme de projecteur Flash, PlugIn si elle sexcute dans un navigateur comme FireFox ou Safari ou ActiveX si elle sexcute dans Internet Explorer. Vous pouvez donc insrer dans votre code des fragments qui ne fonctionnent que si playerType vaut External et vous permettent de tester votre jeu sans affecter la version Web.

Capabilities.language. Retourne le code deux lettres, comme en pour langlais, si lordinateur

est congur de manire utiliser cette langue comme langue principale.


Capabilities.os. Retourne le type et la version du systme dexploitation, comme Mac OS 10.4.9. Capabilities.screenResolutionX, Capabilities.screenResolutionY.

La rsolution dafchage,

comme 1280 et 1024.


Capabilities.version. La version du lecteur Flash, comme MAC 9,0,45,0. Vous pouvez extraire la version du systme dexploitation ou celle du lecteur de ce code.

Bien dautres proprits Capabilities sont disponibles. Consultez la documentation Flash CS3 ce sujet. Examinez le chier SystemData.a pour un exemple danimation qui rcupre la plupart des donnes prcdentes et les afche directement dans un champ texte.

Scurit et vol des jeux


Le vol de jeu est un vritable problme sur Internet. La plupart des jeux ne sont pas du tout protgs et rien nempche le premier venu de rcuprer le chier SWF et de le tlcharger sur son site Web en prtendant quil est le fruit de son propre labeur. Il existe de nombreux moyens dempcher ces agissements. Le plus simple consiste amener votre jeu sassurer quil sexcute rellement depuis votre serveur. Cette vrication peut soprer avec la proprit this.root.loaderInfo.url. Celle-ci retourne le chemin complet du chier en commenant par http:// si le chier se trouve sur le Web. Vous pouvez ensuite oprer une vrication portant sur le domaine. Par exemple, pour vous assurer que ashgameu.com apparat dans le chemin, procdez de la manire suivante :
if (this.root.loaderInfo.url.indexOf("ashgameu.com") != -1) { info.text = "Is playing at ashgameu.com"; } else { info.text = "Is NOT playing at ashgameu.com"; }

Chapitre 2

Composants de jeu ActionScript

89

Au lieu de dnir simplement un champ texte, vous pouvez arrter la lecture du jeu ou conduire le joueur votre site avec navigateToURL. Une fois que vous avez scuris votre jeu au niveau de votre site, ltape suivante consiste le scuriser de manire que personne ne puisse utiliser une balise EMBED avec une URL absolue vers votre chier SWF. Cette mthode permet en effet aux voleurs dincorporer votre jeu depuis votre serveur directement dans leur page Web sur leur serveur. Il nexiste aucun moyen facile dempcher cela mais, si vous dcouvrez ce subterfuge, vous pouvez toujours dplacer votre chier SWF. Vous pouvez remplacer votre chier SWF par un autre chier qui se contente de rediriger le joueur avec navigateToURL.

Certains serveurs Web peuvent empcher la liaison distante. Le but est avant tout dempcher les utilisateurs dincorporer des images de votre serveur dans leurs pages Web. Dans de nombreux cas, cela fonctionne aussi avec les chiers SWF. Renseignez-vous auprs de votre FAI concernant cette fonctionnalit.

Il existe une autre mthode plus avance et relativement complexe pour empcher la liaison incorpore. Elle implique de passer une valeur secrte lanimation Flash par deux biais : sous forme de paramtre ashvars et sous la forme dun fragment de texte ou de donnes XML avec URLLoader. Si les deux valeurs secrtes ne se correspondent pas, on en dduit que lanimation Flash a d tre vole. Lide est de modier rgulirement la valeur passe par les deux biais. Si quelquun vole votre animation Flash mais ne rcupre pas votre code HTML pour incorporer lanimation Flash dans la page, votre animation ne rcupre ds lors pas la version ashvars de la valeur secrte et ne peut fonctionner pour cette personne. Si la personne vole votre code HTML, elle ne possde que la version courante de la valeur secrte Pour linstant, cette valeur correspond la valeur secrte URLLoader mais, une fois que vous aurez mis jour la valeur secrte aux deux endroits, lancienne valeur ashvars dans la page du voleur cessera de correspondre la nouvelle valeur URLLoader de votre serveur.
ashvars.

Il reste videmment possible que le pirate vole votre jeu SWF, louvre avec un dcompilateur SWF et supprime le code de scurit. Il nexiste pas de solution scurise 100 %. La plupart des voleurs recherchent cependant des jeux faciles voler. Le vtre nen fera ainsi pas partie. Maintenant que vous avez dcouvert quelques-unes des techniques de programmation ActionScript 3.0 grce ces petits blocs constructeurs de code, il est temps de passer la ralisation de votre premier jeu.

3
Structure de jeu lmentaire : le Memory
Au sommaire de ce chapitre :

Placer des lments interactifs Jeu Encapsuler un jeu Ajouter un score et un chronomtre Ajouter des effets de jeu Modier le jeu

92

ActionScript 3.0 pour les jeux

Codes sources http://ashgameu.com A3GPU03_MatchingGame.zip

Pour crer votre premier jeu, jai choisi lun des jeux les plus populaires que vous puissiez trouver sur le Web et dans lunivers du logiciel interactif et ducatif : le Memory. Le Memory est un simple jeu de correspondance qui se joue habituellement avec un jeu de cartes reprsentant des images. Lide consiste placer des paires de cartes face cache selon une disposition alatoire. Ensuite, le ou les joueurs doivent tenter de trouver des correspondances en retournant deux cartes de suite. Lorsque deux cartes se correspondent, elles sont retires. Si elles ne se correspondent pas, elles sont retournes (et donc caches) de nouveau. Les bons joueurs sont ceux qui mmorisent les cartes aperues lorsque les cartes ne se correspondent pas et qui parviennent dterminer o se trouvent les vraies paires aprs plusieurs tentatives manques.

Certains des jeux de correspondance ducatifs pour enfants proposent non pas des correspondances exactes pour les paires de cartes mais des jeux dassociation. Par exemple, une carte peut contenir une image de chat et sa carte correspondante, contenir le mot Chat. Une carte peut afcher le numro 7 et lautre, la somme 3+4.

Les versions informatiques des jeux de correspondance possdent plusieurs avantages sur leurs quivalents physiques : vous navez pas besoin de rcuprer, de mlanger et de placer les cartes au dbut de chaque jeu. Lordinateur soccupe de tout cela pour vous. Il est galement plus facile et moins coteux pour le dveloppeur du jeu de crer diffrentes images pour les cartes avec des cartes virtuelles quavec de vraies cartes ! Pour crer un jeu de Memory, nous devons dabord placer des cartes lcran. Pour cela, nous devons mlanger le jeu an que les cartes soient disposes dans un ordre alatoire chaque nouvelle partie. Ensuite, nous devons rcuprer lentre de lutilisateur et nous en servir pour rvler les images de deux cartes slectionnes. Nous devons encore comparer les cartes et les retirer en cas de correspondance. Nous devons enn retourner les cartes pour les cacher de nouveau lorsquelles ne se correspondent pas et vrier quel moment toutes les paires ont t trouves pour que la partie puisse se terminer.

Chapitre 3

Structure de jeu lmentaire : le Memory

93

Placer les lments interactifs


Pour crer un jeu de Memory, nous devons dabord crer un jeu de cartes. Ces cartes devant aller par paires, il convient de dterminer quel nombre sera afch lcran et de crer la moiti de ce nombre dimages. Par exemple, si nous souhaitons afcher trente-six cartes dans le jeu, il nous faut dix-huit images, qui apparatront chacune sur deux cartes.

Mthodes pour la cration des pices du jeu


Il existe deux coles en matire de cration de pices de jeu et notamment pour la cration de cartes dans un jeu de Memory.

Mthode symboles multiples


La premire mthode consiste crer chaque carte sous forme de clip individuel. Dans ce cas, il y aura dix-huit symboles. Chacun reprsente une carte. Lun des problmes avec cette mthode tient ce quil y a de fortes chances pour que vous deviez dupliquer certains lments graphiques lintrieur de chacun des symboles. Par exemple, chaque carte doit possder la mme bordure et le motif de dos. Vous aurez ainsi dix-huit copies de la bordure et du dos. Vous pouvez videmment viter cela en crant un symbole de dos de carte et en lutilisant dans chacun des dix-huit symboles de carte.

Le recours aux symboles multiples peut tre utile si vous rcuprez des cartes dans un groupe de grande taille par exemple si vous avez besoin de dix-huit cartes sur un jeu de cent cartes. Cette mthode peut aussi tre utile si les cartes sont importes dans lanimation partir de chiers multimdias externes, comme une srie dimages JPG.

La mthode plusieurs symboles prsente cependant des inconvnients lorsquil sagit doprer des changements. Par exemple, supposons que vous souhaitiez redimensionner lgrement les images. Vous devrez alors le faire dix-huit fois pour dix-huit symboles diffrents. En outre, si vous associez vos talents de programmeur ceux dun graphiste, il nest pas souhaitable que le graphiste ait mettre jour dix-huit symboles ou plus. Sil est sous contrat, vous risquez dengloutir rapidement tout votre budget !

94

ActionScript 3.0 pour les jeux

Mthode symbole unique


La seconde mthode pour travailler avec une srie de pices de jeu comme des cartes est la mthode symbole unique. Vous utilisez dans ce cas un symbole (un clip) avec plusieurs images. Chaque image contient le graphisme dune carte diffrente. Les graphismes partags, comme la bordure et larrire-plan, peuvent alors se trouver sur un calque du clip qui stend sur toutes les images. Cette mthode possde dindniables avantages lorsquil sagit de mettre jour et de modier les pices du jeu. Vous pouvez aisment et rapidement vous dplacer entre les images et les diter dans le clip. Vous pouvez galement rcuprer facilement un clip mis jour par un graphiste avec lequel vous travaillez.
La mthode symbole unique peut elle aussi utiliser plusieurs symboles. Par exemple, si vos pices de jeu correspondent un jeu de cartes de poker, vous pouvez placer les quatre suites (pique, cur, carreau et tre) dans des symboles et les utiliser dans le symbole principal de votre jeu de cartes. Ainsi, si vous souhaitez modier lapparence du cur dans le jeu de cartes complet, vous pouvez le faire en ne modiant que le symbole de cur.

Congurer lanimation Flash


Grce la mthode symbole unique, il nous faut au moins un clip dans la bibliothque. Ce clip contiendra toutes les cartes et mme une image qui reprsente le dos de la carte que nous devons afcher lorsque la carte est retourne face en bas. Crez une nouvelle animation qui contient un unique clip appel Card. Pour crer une nouvelle animation dans Flash CS3, choisissez Fichier > Nouveau. Une liste de types de chiers apparat. Choisissez Fichier Flash (ActionScript 3.0) pour crer un chier danimation qui fonctionne avec le chier de classe ActionScript 3.0 que nous sommes sur le point de crer. Placez au moins dix-neuf images dans ce clip, lune reprsentant le dos des cartes et les dix-huit autres reprsentant les faces avec diffrentes images. Ouvrez le chier MatchingGame1.a pour cet exercice si vous navez pas votre propre chier de symboles utiliser. La Figure 3.1 prsente un scnario pour le clip Card que nous utiliserons dans ce jeu. La premire image correspond larrire des cartes. Cest ce que le joueur verra lorsque la carte sera tourne face en bas. Ensuite, chacune des autres images prsente une image diffrente pour la face dune carte. Une fois quun symbole se trouve dans la bibliothque, il faut le congurer pour pouvoir lutiliser dans notre code ActionScript. Pour cela, nous devons dnir ses proprits en le slectionnant dans la bibliothque et en afchant la bote de dialogue Proprits du symbole (voir Figure 3.2). Tapez le nom de symbole Card et choisissez le type Clip. Pour quActionScript puisse oprer avec le clip Cards, il faut que ce dernier se voie attribuer une classe. En cochant loption Exporter pour ActionScript, nous attribuons automatiquement le nom de classe Card au symbole. Cela conviendra parfaitement nos besoins. Rien dautre nest requis dans lanimation Flash. Le scnario principal est entirement vide. La bibliothque ne contient quun seul clip : Card. Il ne nous manque plus que du code ActionScript.

Chapitre 3

Structure de jeu lmentaire : le Memory

95

Figure 3.1
Le clip Card est un symbole avec trente-sept images. Chaque image reprsente une carte diffrente.

Figure 3.2
La bote de dialogue Proprits du symbole prsente les proprits du symbole Card.

96

ActionScript 3.0 pour les jeux

Crer la classe ActionScript de base


Pour crer un chier de classe ActionScript, choisissez Fichier > Nouveau, puis slectionnez Fichier ActionScript dans la liste des types de chiers. Vous crez ainsi un document ActionScript sans titre dans lequel vous pouvez taper votre code. Pour commencer un chier ActionScript 3.0, nous devons le dnir comme paquetage. Cest ce que fait la premire ligne de lexemple de code suivant :
package { import ash.display.*;

Juste aprs la dclaration de paquetage, nous indiquons au moteur de lecture Flash les classes requises pour accomplir nos tches. Dans le cas prsent, nous aurons besoin daccder la classe ash.display et chacune de ses sous-classes immdiates. Nous pourrons ainsi crer et manipuler des clips comme les cartes. Vient ensuite la dclaration de la classe. Le nom de la classe doit correspondre exactement celui du chier. Dans le cas prsent, nous lappelons MatchingGame1. Nous devons aussi dnir lobjet que cette classe affectera. Dans le cas prsent, elle affectera lanimation Flash principale, qui est un clip :
public class MatchingGame1 extends MovieClip {

Viennent ensuire les dclarations des variables qui seront utilises dans la classe. Notre premire tche, qui consiste crer les trente-six cartes lcran, est cependant si simple que nous naurons besoin daucune variable. Du moins pour linstant. Nous pouvons donc passer directement la fonction dinitialisation, galement appele fonction constructeur. Cette fonction sexcute aussitt que la classe est cre lorsque lanimation se lit. Elle doit porter exactement le mme nom que la classe et le chier ActionScript :
public function MatchingGame1():void {

Cette fonction na pas besoin de retourner de valeur. Nous pouvons donc placer le mot-cl :void pour indiquer Flash que rien ne sera retourn par cette fonction. Il est aussi possible de ne pas mentionner ce mot-cl, qui est par dfaut implicitement dclar par le compilateur Flash. Dans la fonction constructeur, nous pouvons raliser la tche qui consiste crer les trente-six cartes lcran. Nous crerons une grille de six cartes en largeur sur sixen hauteur. Pour cela, nous utilisons deux boucles for imbriques. La premire fait avancer la variable x de 0 5. Le x reprsente la colonne dans notre grille de 6 par 6. Ensuite, la seconde boucle fait avancer y de 0 5, qui reprsente la ligne :
for(var x:uint=0;x<6;x++) { for(var y:uint=0;y<6;y++) {

Chacune de ces deux variables est dclare de type uint, un entier non sign, juste lintrieur de linstruction for. Chacune commence par la valeur 0, puis poursuit tant que la valeur est infrieure 6. Elles augmentent dune unit chaque passage dans la boucle.

Chapitre 3

Structure de jeu lmentaire : le Memory

97

Il existe trois types de nombres : uint, int et Number. Le type uint est conu pour tous les nombres entiers suprieurs ou gaux 0. Le type int est conu pour tous les nombres entiers qui peuvent tre positifs ou ngatifs. Le type Number peut tre positif ou ngatif, entier ou virgule ottante, comme 3,5 ou 173,98. Dans les boucles for, nous utilisons gnralement des types uint ou int car nous ne progressons que par units compltes.

Il sagit ainsi dun moyen rapide deffectuer une boucle et de crer trente-six clips Card diffrents. La cration des clips se limite utiliser le mot-cl new et addChild. Nous devons aussi nous assurer que, lorsque chaque clip est cr, il est arrt sur sa premire image et correctement positionn lcran :
var thisCard:Card = new Card(); thisCard.stop(); thisCard.x = x*52+120; thisCard.y = y*52+45; addChild(thisCard); } } }

} }

Lajout dun symbole dans ActionScript 3.0 ne requiert que deux commandes : new, qui vous permet de crer une nouvelle instance du symbole, et addChild, qui ajoute linstance la liste dafchage pour la scne. Entre ces deux commandes, vous devez effectuer des tches, comme dnir la position x et y du nouveau symbole.

Le positionnement sopre en fonction de la largeur et de la hauteur des cartes que nous avons cres. Dans lanimation dexemple MatchingGame1.a, les cartes font 50 pixels sur 50 avec 2 pixels despacement entre les cartes. En multipliant les valeurs x et y par 52, nous espaons ainsi les cartes en intgrant un petit interstice supplmentaire. Nous ajoutons galement 120 horizontalement et 45 verticalement, an de positionner la carte peu prs au centre dune animation Flash standard de 550 400. Avant de tester ce code, nous devons lier lanimation Flash au chier ActionScript. Le chier ActionScript doit tre enregistr sous le nom MatchingGame1.as et situ dans le mme rpertoire que lanimation MatchingGame1.a.

98

ActionScript 3.0 pour les jeux

Figure 3.3
Dnissez la classe du document de lanimation Flash en lui donnant le nom du chier ActionScript contenant votre script principal.

Cette opration ne suft cependant pas oprer la liaison entre les deux. Vous devez galement dnir la proprit Classe du document dans linspecteur des proprits de lanimation Flash. Slectionnez longlet Proprits de linspecteur des proprits lorsque votre document danimation MatchingGame1.a est actif (voir Figure 3.3). Vous remarquerez que la classe du document est dnie en bas droite.

Vous pouvez tester votre animation lorsque lanimation Flash elle-mme est active ou lorsque le document courant correspond au chier ActionScript. Avec le chier ActionScript, recherchez la liste droulante Cible, situe en haut droite de la fentre Document. Elle indique lanimation Flash qui sera compile et excute au moment du test. Si le bon chier nest pas slectionn dans la liste, utilisez le menu droulant pour modier ce choix.

La Figure 3.4 prsente lcran aprs que nous avons test lanimation. Le moyen le plus simple deffectuer le test est daccder au menu et de choisir Contrle > Tester lanimation.
Figure 3.4
Lcran prsente trente-six cartes espaces et centres dans la scne.

Chapitre 3

Structure de jeu lmentaire : le Memory

99

Utiliser des constantes pour une meilleure programmation


Avant de poursuivre le dveloppement de ce jeu, voyons comment amliorer ce dont nous disposons dj. Nous allons copier lanimation existante dans le chier MatchingGame2.a et le code dans MatchingGame2.as. Noubliez pas de modier la classe de document de MatchingGame2.a en choisissant MatchingGame2 et la dclaration de classe et la fonction de constructeur en la remplaant par MatchingGame2. Supposons que vous souhaitiez afcher non plus une grille de 6 6 cartes mais une grille plus simple de 4 4. Ou mme une grille rectangulaire de 6 5. Pour cela, il vous suft de retrouver les boucles for du code prcdent et de les adapter pour effectuer un nombre de passages diffrent. Il existe pourtant une mthode encore meilleure qui consiste retirer ces nombres spciques du code. Au lieu de cela, placez-les en haut de votre code, en les tiquetant clairement, an de pouvoir les retrouver et les modier aisment par la suite.

Cette manire dinsrer des nombres spciques lintrieur du code, comme le 5 pour le nombre de lignes et de colonnes, est appele "coder en dur". Cette pratique est rpute contrevenir au bon usage en programmation car elle complique les adaptations ultrieures du programme, notamment pour les programmeurs qui hritent dun code quils nont pas cr eux-mmes et doivent pouvoir modier.

Plusieurs autres valeurs codes en dur gurent dans notre programme. Dressons-en la liste : Lignes horizontales = 6 Lignes verticales = 6 Espacement horizontal = 52 Espacement vertical = 52 Dcalage cran horizontal = 120 Dcalage cran vertical = 45 Au lieu de placer ces valeurs dans le code, insrons-les dans des variables constantes dans notre classe an de pouvoir les retrouver et les modier facilement :
public class MatchingGame2 extends MovieClip { // Constantes de jeu private static const boardWidth:uint = 6; private static const boardHeight:uint = 6; private static const cardHorizontalSpacing:Number = 52; private static const cardVerticalSpacing:Number = 52; private static const boardOffsetX:Number = 120; private static const boardOffsetY:Number = 45;

100

ActionScript 3.0 pour les jeux

Vous remarquerez que jai choisi private static const lors de la dnition de chacune des constantes. Le mot-cl private signie que ces variables ne sont accessibles que depuis lintrieur de cette classe. Le mot-cl static signie quelles possderont la mme valeur dans toutes les instances de la classe. Enn, le mot-cl const signie que les valeurs ne peuvent jamais changer. Si vous utilisiez public var la place, vous auriez la dclaration inverse : les variables seraient accessibles depuis lextrieur de la classe et contiendraient des valeurs diffrentes pour chacune des instances. Comme il sagit de lunique instance de la classe et quil nexiste pas de script externe, il ny a aucune diffrence faire lun ou lautre de ces choix, mais il est plus soigneux de procder comme nous lavons fait.

Maintenant que nous avons des constantes, nous pouvons remplacer le code dans la fonction constructeur an de les utiliser au lieu de nombres cods en dur :
public function MatchingGame2():void { for(var x:uint=0;x<boardWidth;x++) { for(var y:uint=0;y<boardHeight;y++) { var thisCard:Card = new Card(); thisCard.stop(); thisCard.x = x*cardHorizontalSpacing+boardOffsetX; thisCard.y = y*cardVerticalSpacing+boardOffsetY; addChild(thisCard); } } }

Comme vous pouvez le voir, jai galement chang le nom de la classe et la fonction en choisissant MatchingGame2. Ces exemples se trouvent dans les chiers MatchingGame2.a et MatchingGame2.as.

Lorsque nous avancerons dans ce chapitre, nous modierons les noms du chier ActionScript et de lanimation. Si vous suivez ces tapes en crant vos propres animations de toutes pices, noubliez pas non plus de modier la classe du document dans linspecteur des proprits an que chaque animation pointe sur le bon chier ActionScript. Par exemple, lanimation MatchingGame2.a doit utiliser le chier MatchingGame2.as, de sorte que sa classe de document doit tre MatchingGame2.

Ouvrez ces deux chiers. Testez-les un un. Ensuite, testez-les nouveau aprs avoir chang certaines des constantes. Par exemple, limitez la hauteur (boardHeight) cinq cartes. Faites glisser les cartes vers le bas de 20 pixels en modiant boardOffsetY. Le fait que vous puissiez oprer ces modications rapidement et sans peine est la meilleure dmonstration de lintrt des constantes.

Chapitre 3

Structure de jeu lmentaire : le Memory

101

Mlanger et attribuer des cartes


Maintenant que nous pouvons ajouter des cartes lcran, il faut que nous puissions attribuer alatoirement les images chaque carte. Sil y a trente-six cartes lcran, il doit donc y avoir dix-huit paires dimages positionnes de manire alatoire. Au Chapitre 2, nous avons trait de lutilisation des nombres alatoires. Nous ne pouvons cependant pas nous contenter de choisir une image alatoire pour chaque carte. Nous devons nous assurer quil y a exactement deux cartes de chaque type lcran. Pas une de plus, pas une de moins. Sans cela, nous naurons pas de vritables paires.

Ce processus est peu prs inverse de celui qui consiste mlanger un jeu de cartes. Au lieu de mlanger les cartes et de slectionner de nouvelles cartes partir du haut du paquet, nous allons utiliser une liste ordonne de cartes et slectionner de nouvelles cartes partir demplacements alatoires du paquet.

Pour cela, nous devons crer un tableau qui liste chaque carte, puis slectionner une carte alatoire dans ce tableau. Le tableau fera trente-six lments de long et contiendra deux exemplaires de chacune des dix-huit cartes. Ensuite, mesure que nous crerons la grille de 6 6, nous retirerons des cartes du tableau et les placerons dans la grille. Lorsque nous aurons ni, le tableau sera vide et toutes les dix-huit paires de cartes seront prises en compte dans la grille. Voici le code qui permet de raliser cette opration. Une variable i est dclare dans linstruction for. Elle ira de zro au nombre de cartes requis. Il sagit simplement de la largeur de la grille multiplie par sa hauteur et divise par deux (car chaque carte gure en deux exemplaires). Pour une grille de 6 6, il y aura donc trente-six cartes. Nous devons boucler dix-huit fois pour ajouter dix-huit paires de cartes :
// Cration dune liste de numros de carte var cardlist:Array = new Array(); for(var i:uint=0;i<boardWidth*boardHeight/2;i++) { cardlist.push(i); cardlist.push(i); }

La commande push est utilise pour placer deux fois un numro dans le tableau. Voici quoi ressemblera le tableau :
0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17

102

ActionScript 3.0 pour les jeux

prsent, lorsque nous bouclons an de crer les trente-six clips, nous rcuprons un nombre alatoire dans cette liste an de dterminer limage afcher sur chaque carte :
for(var x:uint=0;x<boardWidth;x++) { // Horizontal for(var y:uint=0;y<boardHeight;y++) { // Vertical var c:Card = new Card(); // Copie du clip c.stop(); // Arrt sur la premire image c.x = x*cardHorizontalSpacing+boardOffsetX; // Dnir la position c.y = y*cardVerticalSpacing+boardOffsetY; var r:uint = Math.oor(Math.random()*cardlist.length); // Obtenir une face alatoire c.cardface = cardlist[r]; // Attribuer la face la carte cardlist.splice(r,1); // Retirer la face de la list c.gotoAndStop(c.cardface+2); addChild(c); // Afcher la carte } }

Les nouvelles lignes se trouvent au milieu du code. Pour commencer, nous utiliserons la ligne suivante pour obtenir un nombre alatoire compris entre zro et le nombre dlments qui restent dans la liste :
var r:uint = Math.oor(Math.random()*cardlist.length);

La fonction Math.random() retourne un nombre compris entre 0,0 et 1,0 non inclus. Nous multiplions ce rsultat pour obtenir un nombre alatoire compris entre 0,0 et 35,9999. Ensuite, nous utilisons Math.oor() pour arrondir ce nombre lentier infrieur et obtenir ainsi un nombre compris entre 0 et 35 ( tout le moins, quand il y a trente-six lments dans le tableau cardlist, au dbut des boucles). Ensuite, le nombre lemplacement correspondant dans cardlist est attribu une proprit de c nomme cardface. Puis nous utilisons la commande splice pour retirer ce nombre du tableau an quil ne soit plus utilis de nouveau. Le script MatchingGame3.as inclut en outre cette ligne pour vrier que tout fonctionne jusque-l :
c.gotoAndStop(c.cardface+2);

Cette syntaxe amne le clip Card afcher son image. Ainsi, toutes les trente-six cartes seront face dessus plutt que face en bas. Elle prend la valeur de la proprit cardface, qui correspond un nombre compris entre 0 et 17 et ajoute 2 pour obtenir un nombre compris entre 2 et 19. Cette valeur correspond aux images dans le clip Card : limage 1 reprsente le dos des cartes et les images 2 et suivantes, leurs faces.

Chapitre 3

Structure de jeu lmentaire : le Memory

103

Sil faut gnralement dclarer et dnir des variables, il est galement possible dajouter des proprits dynamiques comme cardface un objet. Cela ne peut se faire que si lobjet est dynamique, ce que lobjet Card est par dfaut car nous navons pas spci le contraire. La proprit cardface prsuppose le type de la valeur quelle se voit attribuer (soit Number, dans le cas prsent). Il ne sagit pas du meilleur usage en programmation. Il serait prfrable de dnir une classe pour la Card, avec un chier ActionScript dclarant un paquetage, une classe, des proprits et une fonction constructeur. Il sagit cependant dun considrable effort supplmentaire lorsquune seule petite proprit est requise ; la commodit lemporte donc sur lintrt de sen tenir aux bonnes pratiques de la programmation.

Il nest videmment pas souhaitable que cette ligne de code gure dans notre jeu nal, mais elle est utile ce stade pour montrer ce que nous avons accompli. La Figure 3.5 montre quoi pourrait ressembler lcran une fois que nous excutons le programme avec cette ligne de test en place.
Figure 3.5
La troisime version de notre programme inclut du code qui rvle chacune des cartes. Cest utile pour obtenir une conrmation visuelle que notre code fonctionne jusque-l.

104

ActionScript 3.0 pour les jeux

Jeu
prsent que la grille est congure, nous devons permettre lutilisateur de cliquer sur des cartes pour tenter de trouver des correspondances. Nous devons galement tenir le registre de ltat du jeu, ce qui implique ici de savoir si le joueur clique sur la premire carte ou la seconde et si toutes les cartes ont t trouves.

Ajouter des couteurs clavier


La premire tape consiste amener chacune des cartes que nous crons ragir des clics de souris. Nous pouvons le faire en ajoutant un couteur chacun de ces objets. La fonction addEventListener sen charge. Elle prend deux paramtres : lvnement couter et la fonction appeler lorsque lvnement se produit. Voici la ligne de code :
c.addEventListener(MouseEvent.CLICK,clickCard);

Vous devez galement ajouter une autre instruction import au dbut de la classe pour indiquer Flash que vous souhaitez utiliser des vnements :
import ash.events.*;

La syntaxe pour lvnement est ici MouseEvent.CLICK, ce qui correspond un simple clic sur la carte. Lorsque cet vnement se produit, la fonction clickCard est appele. Cette fonction reste encore crer. Nous devons la programmer avant de tester lanimation de nouveau car Flash ne peut compiler lanimation sil manque une portion du code. Voici un dbut simple pour la fonction clickCard :
public function clickCard(event:MouseEvent) { var thisCard:Card = (event.currentTarget as Card); // Quelle carte ? trace(thisCard.cardface); }

Lutilisation dun appel linstruction trace peut tre un excellent moyen de vrier votre code an davancer par petites tapes et dviter les maux de tte. Par exemple, si vous ajoutez vingt-sept lignes de code la fois et quensuite le programme ne fonctionne pas comme prvu, vous devez localiser le problme dans vingt-sept nouvelles lignes de code. Si vous najoutez que cinq nouvelles lignes de code et utilisez une instruction trace pour afcher les valeurs des variables cls, vous pouvez rsoudre tous les problmes avec ces cinq lignes de code avant de passer la suite.

Chapitre 3

Structure de jeu lmentaire : le Memory

105

chaque fois quune fonction ragit un vnement, elle doit prendre au moins un paramtre, savoir lvnement lui-mme. Dans le cas prsent, il sagit dune valeur de type MouseEvent que nous attribuerons la variable event.

Vous devez accepter le paramtre dvnement ou une fonction dcouteur vnementiel, que vous vous souciez de sa valeur ou non. Par exemple, si vous crez un unique bouton et savez que la fonction ne sexcutera que lorsque ce bouton sera enfonc, vous devez malgr tout accepter lvnement comme paramtre, mme si vous ne lutilisez pour rien ensuite.

Dans le cas prsent, le paramtre event est essentiel parce que nous devons savoir sur laquelle des trente-six cartes le joueur a cliqu. La valeur du paramtre event est en fait un objet avec toutes sortes de proprits, mais la seule chose qui nous intresse est de connatre lobjet Card sur lequel lutilisateur a cliqu. Il sagit de la cible ou, plus prcisment, de la proprit currentTarget de lvnement.
currentTarget est cependant un objet vague pour le moteur ActionScript ce stade. Bien sr, il sagit dun objet Card. Il sagit cependant aussi dun clip, autrement dit dun objet dafchage galement. Nous souhaitons obtenir sa valeur en tant quobjet Card et dnissons donc une variable en tant que Card, puis utilisons un Card pour spcier que nous souhaitons que la valeur de event.currentTarget soit retourne sous forme de Card.

Maintenant que nous avons un objet Card dans la variable thisCard, nous pouvons accder sa proprit cardface. Nous utiliserons trace pour la placer dans la fentre Sortie et excuter un test rapide de MatchingGame4.a pour nous assurer que lanimation fonctionne.

Congurer la logique du jeu


Lorsquun joueur clique sur une carte, nous devons dterminer les tapes suivre en fonction de son choix et de ltat du jeu. Il existe trois tats principaux grer :

tat 1. Aucune carte na t choisie, le joueur slectionne la premire carte dune correspondance possible. tat 2. Une carte a t choisie, le joueur slectionne une seconde carte. Une comparaison doit tre opre et une action, entreprise en fonction du fait quil sagit ou non dune correspondance. tat 3. Deux cartes ont t choisies, mais aucune correspondance na t trouve. Conserver ces cartes face visible jusqu ce quune nouvelle carte soit choisie, puis les retourner toutes les deux et rvler la nouvelle carte.

Les Figures 3.6 3.8 prsentent les trois tats du jeu.

106

ActionScript 3.0 pour les jeux

Figure 3.6
tat 1, o lutilisateur est sur le point de choisir sa premire carte.

Figure 3.7
tat 2, o lutilisateur est sur le point de choisir sa seconde carte.

Dautres considrations entrent ensuite en jeu. Que se passe-t-il si le joueur clique sur une carte puis clique sur la mme carte de nouveau ? Nous en dduisons que le joueur souhaite probablement revenir sur son premier choix : nous devons retourner cette carte et revenir au premier tat.

Chapitre 3

Structure de jeu lmentaire : le Memory

107

Figure 3.8
tat 3, o une paire de cartes a t slectionne mais aucune correspondance, trouve. Lutilisateur doit maintenant choisir une autre carte pour tenter de trouver une autre paire.

Nous devrons invitablement tenir le registre des cartes qui ont t choisies lorsque le joueur tombe sur une correspondance. Voil donc loccasion de crer nos premires variables de classe. Nous les appellerons rstCard et secondCard. Elles seront toutes deux de type Card :
private var rstCard:Card; private var secondCard:Card;

Comme nous navons dni aucune valeur pour ces variables, elles commenceront toutes deux avec la valeur dobjet par dfaut null. En fait, nous utiliserons les valeurs null de ces deux variables pour dterminer ltat.

Tous les types de variables ne peuvent pas tre positionns null. Par exemple, une variable int sera positionne zro au moment de sa cration, moins que vous ne spciiez une autre valeur. Vous ne pouvez pas la positionner null mme si vous le souhaitez.

Si rstCard et secondCard valent toutes deux null, nous devons nous trouver au premier tat. Le joueur est sur le point de choisir sa premire carte. Si rstCard ne vaut pas null et secondCard vaut null, nous nous trouvons au second tat. Le joueur choisira bientt la carte quil espre correspondre la premire. Si rstCard et secondCard ne valent null ni lune ni lautre, nous nous trouvons au troisime tat. Nous utiliserons les valeurs rstCard et secondCard pour savoir quelles cartes retourner lorsque lutilisateur choisira la rstCard suivante.

108

ActionScript 3.0 pour les jeux

Examinons le code :
public function clickCard(event:MouseEvent) { var thisCard:Card = (event.target as Card); // Quelle carte ? if (rstCard == null) { // Premire carte dans une paire rstCard = thisCard; // La mmoriser rstCard.gotoAndStop(thisCard.cardface+2); // La retourner

Jusque-l, vous pouvez voir ce qui se passe lorsque le joueur clique sur la premire carte. Vous remarquerez que la commande gotoAndStop est analogue celle que nous avons utilise pour tester le mlange des cartes prcdemment dans ce chapitre. Elle doit ajouter 2 au numro de limage an que les valeurs de carte comprises entre 0 et 17 correspondent aux numros dimage compris entre 2 et 19 qui contiennent les dix-huit faces de carte. prsent que la valeur de rstCard est dnie, nous pouvons attendre le second clic. Cette tape est gre par les deux parties suivantes de linstruction if. Cette partie gre le cas o le joueur clique sur la premire carte de nouveau et retourne cette carte en redonnant la valeur null rstCard :
} else if (rstCard == thisCard) { // Premire carte clique de nouveau rstCard.gotoAndStop(1); // Retourner rstCard = null;

Si le joueur clique sur une autre carte an de dcouvrir la seconde, une comparaison doit tre effectue entre les deux. Nous comparons non pas les cartes elles-mmes mais leur proprit cardface. Si les faces sont les mmes, une correspondance a t trouve :
} else if (secondCard == null) { // Seconde carte dans une paire secondCard = thisCard; // La mmoriser secondCard.gotoAndStop(thisCard.cardface+2); // La retourner // Comparer les deux cartes if (rstCard.cardface == secondCard.cardface) {

Si une correspondance a t trouve, nous souhaitons supprimer les cartes et rinitialiser les variables rstCard et secondCard : il faut pour cela utiliser la commande removeChild, qui est linverse de addChild. Elle retire lobjet de la liste dafchage et le supprime de lafchage. Dans le cas prsent, les objets se trouvent cependant toujours stocks dans des variables, aussi devons-nous les positionner null pour quils soient supprims par le lecteur Flash :
// Supprimer une correspondance removeChild(rstCard); removeChild(secondCard); // Rinitialiser slection rstCard = null; secondCard = null; }

Chapitre 3

Structure de jeu lmentaire : le Memory

109

Le cas suivant correspond ce qui se passe si le joueur a slectionn une rstCard puis slectionn une seconde carte qui ne lui correspond pas et clique prsent sur une nouvelle carte. Cette opration doit retourner les deux premires cartes en les ramenant leur position face cache, ce qui correspond limage 1 du clip Card. Immdiatement aprs, elle doit attribuer la nouvelle carte rstCard et afcher son image :
} else { // Recherche dune autre paire // Rinitialisation de la paire prcdente rstCard.gotoAndStop(1); secondCard.gotoAndStop(1); secondCard = null; // Slection de la premire carte de la paire suivante rstCard = thisCard; rstCard.gotoAndStop(thisCard.cardface+2); } }

Voil tout, en fait, pour le jeu de base. Vous pouvez tester MatchingGame5.a et MatchingGame5. as pour y jouer. Vous pouvez slectionner des paires de cartes et voir comment les cartes correspondantes sont retires de la grille. Ce jeu peut tre considr comme complet. Vous pourriez aisment placer une image larrire-plan des cartes dans le scnario de lanimation principale et faire de la dcouverte de limage complte la rcompense pour le gain du jeu. Comme simple gadget dans un site Web, cela sufra parfaitement. Il est pourtant possible daller bien plus loin et dajouter dautres fonctionnalits.

Vrier si la partie est nie


Vous souhaiterez sans nul doute vrier si la partie est nie pour rcompenser les joueurs en afchant un cran indiquant quils ont termin le jeu. Ltat de n de partie est atteint lorsque toutes les cartes ont t supprimes.

Dans les exemples de ce chapitre, nous conduisons simplement le joueur vers un cran qui afche les mots Game Over. Vous pourriez cependant afcher une animation et conduire une nouvelle page Web. Nous nous en tiendrons nanmoins ici exclusivement ce qui concerne la programmation des jeux.

110

ActionScript 3.0 pour les jeux

Il existe plusieurs approches pour ce travail. Par exemple, vous pouvez avoir une nouvelle variable dans laquelle vous tenez le registre du nombre de paires trouves. chaque fois que vous trouvez une paire, ajoutez une unit cette valeur, puis vriez-la pour voir si elle est gale au nombre total de paires. Une autre mthode consiste vrier la proprit numChildren de lobjet MatchingGame. Lorsque vous lui ajoutez trente-six cartes, numChildren vaut 36. mesure que des paires sont supprimes, numChildren savance vers zro. Lorsque sa valeur atteint zro, la partie est termine. Le problme avec cette mthode tient ce que si vous placez dautres lments dans la scne, comme un arrire-plan ou une barre de titre, ils sont galement compts dans numChildren. Pour le prsent exemple, la premire mthode semble prfrable. Au lieu de compter le nombre de cartes supprimes, comptons le nombre de cartes afches. Crons une nouvelle variable de classe nomme cardsLeft :
private var cardsLeft:uint;

Ensuite, positionnons-la zro juste avant les boucles for qui crent les cartes et ajoutons une unit cette variable pour chaque carte cre :
cardsLeft = 0; for(var x:uint=0;x<boardWidth;x++) { // Horizontale for(var y:uint=0;y<boardHeight;y++) { // Verticale var c:Card = new Card(); // Copier le clip c.stop(); // Arrt sur la premire image c.x = x*cardHorizontalSpacing+boardOffsetX; // Dnir la position c.y = y*cardVerticalSpacing+boardOffsetY; var r:uint = Math.oor(Math.random()*cardlist.length); // Obtenir une face alatoire c.cardface = cardlist[r]; // Attribuer face la carte cardlist.splice(r,1); // Supprimer face de la liste c.addEventListener(MouseEvent.CLICK,clickCard); // couter les clics addChild(c); // Afcher la carte cardsLeft++; } }

Nous devons ensuite ajouter du nouveau code lorsque lutilisateur trouve une correspondance et que les cartes sont supprimes de lcran. Il vient se placer dans la fonction clickCard.
cardsLeft -= 2; if (cardsLeft == 0) { gotoAndStop(gameover); }

Chapitre 3

Structure de jeu lmentaire : le Memory

111

Vous pouvez utiliser ++ pour ajouter une unit une variable et -- pour la soustraire. Par exemple, cardsLeft++ quivaut cardsLeft = cardsLeft + 1. Vous pouvez galement utiliser += pour ajouter un nombre une variable et -= pour le soustraire. Par exemple, cardsLeft -= 2 quivaut cardsLeft = cardsLeft - 2.

Voil tout ce dont nous avions besoin pour la programmation du code. prsent, le jeu mmorise le nombre de cartes lcran laide de la variable cardsLeft et intervient lorsque ce nombre atteint zro.
Figure 3.9
Lcran de n de partie le plus simple du monde.

Laction effectue consiste sauter une nouvelle image comme celle prsente la Figure 3.9. Si vous examinez lanimation MatchingGame6.a, vous verrez que jai ajout une seconde image. Jai galement ajout des commandes stop(); la premire image. Elles arrtent lanimation sur la premire image an que lutilisateur puisse jouer sa partie au lieu de poursuivre limage suivante. La seconde image est tiquete gameover et sera utilise lorsque la proprit cardsLeft vaudra zro. ce stade, nous souhaitons supprimer tous les lments de jeu crs par le code. Comme le jeu ne cre que trente-six cartes et que toutes les trente-six cartes sont supprimes lorsque le joueur trouve toutes les correspondances, il ne reste nanmoins aucun lment supplmentaire supprimer lcran. Nous pouvons sauter limage gameover sans craindre quil ne reste dlment lcran. Lcran gameover afche les mots Game Over dans lanimation dexemple. Vous pouvez y ajouter des images ou des animations sophistiques si vous le souhaitez. Dans la suite de ce chapitre, nous verrons comment ajouter un bouton Play Again (Rejouer) cette image.

112

ActionScript 3.0 pour les jeux

Encapsuler le jeu
Nous disposons maintenant dun jeu qui sexcute sous la forme dune animation Flash complte. Lanimation est appele MatchingGameX.a et la classe ActionScript, MatchingGameX.as. Lorsque lanimation sexcute, le jeu sinitialise et la partie dmarre. Lanimation quivaut au jeu et le jeu, lanimation. Ce dispositif fonctionne bien dans des situations simples. En pratique, il est cependant souhaitable davoir des crans dintroduction, des crans de n de partie, des crans de chargement, etc. Vous pourriez mme souhaiter avoir diffrents crans avec diffrentes versions du jeu ou des jeux compltement diffrents. Flash excelle lencapsulation. Les animations Flash sont des clips et vous pouvez insrer des clips lintrieur dautres clips. Un jeu peut ainsi tre une animation ou bien un clip lintrieur dune animation. Pourquoi procder de cette manire ? Pour une raison simple : il est ais dajouter dautres crans votre jeu. Il est possible de faire de limage 1 un cran dintroduction, de limage 2 un jeu et de limage 3 lcran de n de partie. Limage 2 contiendra en fait un clip appel MatchingGameObject7 qui utilise la classe MatchingGameObject7.as. La Figure 3.10 prsente un diagramme des trois images que nous prvoyons dinclure dans notre animation mise jour et du contenu de chacune dentre elles.
Figure 3.10
La seconde image de lanimation contient un clip qui correspond au jeu lui-mme. Les autres images peuvent contenir des crans divers.

Image 1 cran d'introduction

Image 2 cran du jeu Clip du jeu

Image 3 cran de fin de partie

Bouton Jouer

Bouton "Rejouer"

Crer le clip du jeu


MatchingGameObject7.a contient trois images. Passons directement la deuxime. Elle contient un unique clip. Vous ne laurez peut-tre pas remarqu au premier abord parce quil sagit dun clip entirement vide qui apparat donc sous la forme dun petit cercle dans le coin suprieur gauche de lcran. Dans la bibliothque, ce clip est nomm MatchingGameObject7 et, comme le montre la Figure 3.11, la classe MatchingGameObject7 lui est associe.

Chapitre 3

Structure de jeu lmentaire : le Memory

113

Figure 3.11
Ce clip utilisera le chier MatchingGameObject7.as comme classe.

En somme, ce clip remplace le jeu entier et le scnario de lanimation principal correspond maintenant un clip plus grand qui lenglobe. Lorsque lanimation atteint limage 2, le clip MatchingGameObject7 prend vie, excute la fonction constructeur de classe dans sa classe MatchingGameObject7.as et la lecture du jeu se lance dans ce clip. Lorsque lanimation passe limage 3, le jeu entier disparat car le clip nexiste qu limage 2. Ce dispositif permet de placer des images avant et aprs le jeu (et donc disoler le code du jeu an de ne soccuper que du jeu lui-mme).

Ajouter un cran dintroduction


La plupart des jeux proposent un cran dintroduction. On prfre gnralement que le joueur ne soit pas immdiatement plong dans le jeu mais commence par une introduction ou puisse lire des instructions. Lcran dintroduction contiendra du code dans limage 1 du scnario principal. Ce code doit dabord arrter lanimation an quelle ne poursuive pas au-del de limage 1. Ensuite, il doit congurer un bouton an de permettre aux utilisateurs de dmarrer le jeu.

114

ActionScript 3.0 pour les jeux

Si vous souhaitez conserver tout le code lcart du scnario principal, vous pouvez congurer un nouveau chier de classe AS comme classe de document de lanimation complte. Ce code sexcutera limage 1 et peut raliser les mmes tches que dans le scnario principal. Il est cependant tellement simple dajouter ce petit bout de code au scnario principal et dviter ainsi de crer plus de chiers que ncessaire

Le script de limage doit dabord attribuer un couteur un bouton que nous allons crer dans la premire image. Nous nommerons ce bouton playButton. Lcouteur vnementiel appellera la fonction startGame, qui met simplement une commande gotoAndStop destination du scnario principal an de lui ordonner datteindre limage appele playgame, qui correspond limage 2. Nous placerons galement une commande stop dans limage an que, lorsque lanimation sexcute, elle sarrte limage 1 et attende que lutilisateur clique sur le bouton :
playButton.addEventListener(MouseEvent.CLICK,startGame); function startGame(event:MouseEvent) { gotoAndStop("playgame"); } stop();

Dans la seconde image se trouvera le clip MatchingGameObject7. Ensuite, nous devrons renommer le chier AS de classe de document MatchingGameObject7.as an quil soit utilis par ce clip et non par lanimation principale.

Pour crer un clip vide, accdez la bibliothque et choisissez Nouveau symbole dans son menu. Nommez le symbole, choisissez le type Clip et dnissez ses proprits. Ensuite, faites glisser le clip de la bibliothque vers la scne. Placez-le dans le coin suprieur gauche an que sa position 0, 0 soit la mme que la position 0, 0 de la scne.

Nous devons oprer un changement dans le code. Une rfrence au scnario principal est utilise lorsque la partie se termine. La commande gotoAndStop ne fonctionne plus correctement car le jeu se trouve dans le clip alors que limage gameover se trouve dans le scnario principal. Il convient de faire la modication suivante :
MovieClip(root).gotoAndStop("gameover");

Chapitre 3

Structure de jeu lmentaire : le Memory

115

Pourquoi nest-il pas possible dcire simplement root.gotoAndStop("gameover") ? Aprs tout, root correspond bien au scnario principal et au parent du clip. Le compilateur ActionScript ne le permettra cependant pas. La commande gotoAndStop ne peut tre mise qu destination de clips et, techniquement, root peut tre autre chose quun clip, comme un clip une image appel sprite. An de rassurer le compilateur sur le fait que root est un clip, nous le tapons donc explicitement en utilisant la fonction MovieClip().

Limage gameover de lanimation est pour linstant la mme que dans MatchingGame6.a. Il sagit simplement dune image contenant les mots Game Over. Lanimation MatchingGame7.a est un peu diffrente des six prcdentes versions car aucune classe de document ne lui est associe. En fait, il nexiste mme pas de chier MatchingGame7.as. Observez de prs la structure de cette animation ainsi que la Figure 3.10 pour comprendre comment le jeu tient dans lanimation principale plus importante.

Ajouter un bouton pour rejouer


Dans la dernire image, nous souhaitons ajouter un autre bouton qui permette aux joueurs de rejouer. Il suft de dupliquer le bouton Play dorigine provenant de limage 1. Ne vous contentez pas dune opration de copier-coller. Au lieu de cela, crez un duplicata du bouton dans la bibliothque. Ensuite, changez le texte du bouton en remplaant Play par Play Again. Votre image gameover devrait maintenant ressembler celle de la Figure 3.12.
Figure 3.12
Lcran gameover contient maintenant un bouton Play Again.

116

ActionScript 3.0 pour les jeux

Une fois que vous avez ajout ce bouton la troisime image, nommez-le playAgainButton laide de linspecteur des proprits an de pouvoir lui attribuer un couteur. Le script de limage devrait ressembler ceci :
playAgainButton.addEventListener(MouseEvent.CLICK,playAgain); function playAgain(event:MouseEvent) { gotoAndStop(playgame); }

Testez MatchingGame7.a an de voir ces boutons en action. Vous disposez maintenant dune structure de jeu trs exible o vous pouvez substituer du contenu dans les pages intro et gameover et redmarrer le jeu sans craindre que tranent des lments dcran ou des valeurs de variable restants. Ctait un problme avec ActionScript 1 et 2, mais ce nest pas le cas avec ce type de framework dans ActionScript 3.0.

Ajouter un score et un chronomtre


Le but de ce chapitre est de dvelopper une structure de jeu complte autour dun jeu de Memory. Parmi les lments qui se rencontrent frquemment dans la plupart des jeux gurent le score et le chronomtre. Si le principe du Memory ne les requiert pas vraiment, nous les ajouterons tout de mme an de disposer des fonctionnalits les plus compltes possibles.

Ajouter le score
Le problme consiste dcider de la manire de comptabiliser le score pour un jeu de ce type. Il nexiste pas de solution vidente. Il devrait cependant y avoir une rcompense pour lobtention dune correspondance et ventuellement une sanction en cas dchec. Comme il arrive presque toujours que le joueur rate quelques coups de plus quil nen russit, il faut que les correspondances rapportent plus de points que nen cotent les tentatives manques. Pour commencer, on peut envisager dattribuer 100 points pour une correspondance et -5 en cas dchec. Au lieu de coder ces montants en dur dans le jeu, ajoutons-les la liste de constantes au dbut de la classe :
private static const pointsForMatch:int = 100; private static const pointsForMiss:int = -5;

Il nous faut maintenant un champ texte pour afcher le score. Comme vous lavez vu au Chapitre 2, il est assez facile de crer un champ texte. Nous devons dabord dclarer un nouvel objet TextField dans la liste des variables de classe :
private var gameScoreField:TextField;

Chapitre 3

Structure de jeu lmentaire : le Memory

117

Ensuite, nous devons crer ce champ texte et lajouter comme enfant :


gameScoreField = new TextField(); addChild(gameScoreField);

Nous pourrions aussi le formater et lhabiller quelque peu, comme nous lavons fait au Chapitre 2, mais nous laisserons de ct cette tche pour linstant. Le score lui-mme sera une simple variable entire nomme gameScore. Nous la dclarerons au dbut de la classe :
private var gameScore:int;

Ensuite, nous la positionnerons zro dans la fonction constructeur :


gameScore = 0;

En outre, il serait intressant dafcher immdiatement le score dans le champ texte :


gameScoreField.text = "Score: "+String(gameScore);

Nous ralisons ce stade quil y a au moins plusieurs endroits dans le code o nous allons dnir le texte de gameScoreField. Le premier est la fonction constructeur. Le second intervient aprs que le score a chang pendant que la partie est en cours. Au lieu de copier et de coller la ligne de code prcdente deux endroits, plaons-la dans une fonction part. Nous pourrons alors appeler la mme fonction depuis chacun des endroits du code o nous devons mettre jour le score :
public function showGameScore() { gameScoreField.text = "Score: "+String(gameScore); }

Nous devons changer le code deux endroits. Le premier vient juste aprs quune correspondance eut t trouve et juste avant que nous vriions si la partie est termine :
gameScore += pointsForMatch;

Ensuite, nous ajoutons une clause else linstruction if qui vrie sil y a correspondance et soustrait les points en cas dchec :
gameScore += pointsForMiss;

Voici la section de code entire an de reprer o sinsrent ces deux lignes :


// Comparer les deux cartes if (rstCard.cardface == secondCard.cardface) { // Retirer une correspondance removeChild(rstCard); removeChild(secondCard); // Rinitialiser la slection rstCard = null;

118

ActionScript 3.0 pour les jeux

secondCard = null; // Ajouter des points gameScore += pointsForMatch; showGameScore(); // Vrier si la partie est termine cardsLeft -= 2; // 2 cartes en moins if (cardsLeft == 0) { MovieClip(root).gotoAndStop("gameover"); } } else { gameScore += pointsForMiss; showGameScore(); }

Vous remarquerez que nous ajoutons des points laide de loprateur +=, mme en cas de tentative manque. La variable pointsForMiss vaut en effet 5 et lajout de 5 quivaut soustraire 5 points. Nous plaons galement lappel la fonction showGameScore() aprs chaque changement du score. Nous nous assurons ainsi que le joueur verra un score jour, comme le montre la Figure 3.13.
Figure 3.13
Le score apparat maintenant dans le coin suprieur gauche avec la police et le style par dfaut.

MatchingGame8.a et MatchingGame8.as incluent ce code de score. Examinez-les pour dcouvrir cet exemple en action.

Chapitre 3

Structure de jeu lmentaire : le Memory

119

En passant de MatchingGame8.a MatchingGame9.a, vous devez faire plus que changer les noms de chiers. Dans lanimation, vous devez changer la fois le nom et la classe du clip MatchingGameObject7 en choisissant MatchingGameObject8. Ne commettez pas lerreur de ne changer que le nom du clip et de laisser la classe pointer vers MatchingGameObject7. Ensuite, vous devez videmment changer le nom du chier ActionScript pour le remplacer par MatchingGame8.as et changer le nom de la classe et de la fonction constructeur galement. Cela vaut galement pour les prochaines versions du jeu de Memory dans la suite du chapitre.

Ajouter un chronomtre
Lajout dun chronomtre est un peu plus compliqu que le score. Tout dabord, le chronomtre doit constamment tre mis jour, la diffrence du score, qui ne se modie que lorsque lutilisateur tente de trouver une paire. Pour inclure un chronomtre, nous devons utiliser la fonction getTimer(). Elle retourne le temps coul en millisecondes depuis que lanimation Flash a dmarr. Il sagit dune fonction spciale qui requiert limportation dune classe Flash au dbut de notre programme :
import ash.utils.getTimer;

La fonction getTimer mesure le nombre de millisecondes coul depuis le dbut de lanimation Flash. En gnral, cette mesure brute nest cependant pas utile telle quelle car le joueur ne commence pas son jeu ds linstant o lanimation apparat lcran. getTimer est plutt utile lorsque lon rcupre deux mesures et soustrait la premire la deuxime. Cest ce que nous allons faire ici : obtenir le temps o lutilisateur a cliqu sur Play et soustraire cette valeur au temps courant pour obtenir la dure depuis laquelle la partie a commenc.

Il nous faut prsent de nouvelles variables. Nous avons besoin denregistrer le temps depuis lequel la partie a commenc. Ensuite, nous pourrons simplement soustraire cette mesure au temps courant pour obtenir la dure coule de la partie. Nous utiliserons aussi une variable pour stocker le temps de partie :
private var gameStartTime:uint; private var gameTime:uint;

Nous devons aussi dnir un nouveau champ texte pour afcher le temps lcran :
private var gameTimeField:TextField;

120

ActionScript 3.0 pour les jeux

Dans la fonction constructeur, nous ajoutons un nouveau champ texte pour afcher le temps coul. Nous nous dplaons en outre droite de lcran pour que ce champ texte ne se trouve pas par-dessus celui qui afche le score :
gameTimeField = new TextField(); gameTimeField.x = 450; addChild(gameTimeField);

Avant que la fonction constructeur nait termin, nous souhaitons dnir la variable gameStartTime. Nous pouvons aussi positionner gameTime zro :
gameStartTime = getTimer(); gameTime = 0;

Nous devons maintenant trouver un moyen de mettre jour le temps de jeu. Ce temps change constamment : nous ne souhaitons donc pas attendre que lutilisateur agisse pour lafcher. Lune des approches possibles consiste crer un objet Timer, comme au Chapitre 2. Il nest cependant pas essentiel que le chronomtre soit mis jour intervalles rguliers ; il faut simplement quil le soit sufsamment souvent pour que les joueurs aient un aperu prcis du temps de jeu coul. Au lieu dutiliser un Timer, nous pouvons amener lvnement ENTER_FRAME dclarer une fonction qui met jour le chronomtre. Dans une animation Flash par dfaut, cela se produit douze fois par seconde, ce qui suft amplement :
addEventListener(Event.ENTER_FRAME,showTime);

Il ne reste plus qu crer la fonction showTime. Elle calculera le temps courant en fonction de la valeur courante de getTimer() et de la valeur de gameStartTime. Ensuite, elle placera le rsultat dans le champ texte an de lafcher :
public function showTime(event:Event) { gameTime = getTimer()-gameStartTime; gameTimeField.text = "Time: "+gameTime; }

La Figure 3.14 prsente lcran avec le score et le temps de jeu. Le format de temps utilise cependant un signe deux-points et deux chiffres pour les secondes. Cest la prochaine tape que nous allons tudier.

Afcher le temps
La fonction showTime afche le nombre de millisecondes depuis le dbut de la partie. Les joueurs ne se proccupent gnralement pas des millisecondes ; ils souhaitent pouvoir observer un afchage de chronomtre ou dhorloge normal o sont indiques les minutes et les secondes, comme sur les montres digitales.

Chapitre 3

Structure de jeu lmentaire : le Memory

121

Figure 3.14
Le temps coul est maintenant afch en haut droite.

Dcomposons cette tche en une autre fonction. Au lieu dinclure directement dans le champ texte la mesure brute gameTime comme dans lexemple de code prcdent, nous pouvons appeler une fonction permettant de retourner une sortie plus lgante :
gameTimeField.text = "Time: "+clockTime(gameTime);

Quand lancien code afche ceci :


Time: 123726

Le nouveau code afche cette fois :


Time: 2:03

La fonction clockTime rcupre le temps en millisecondes brutes et le convertit en minutes et en secondes entires. En outre, elle formate cette mesure en utilisant un signe deux-points (:) et sassure quun zro est correctement plac lorsque le nombre de secondes est infrieur dix. La fonction commence en divisant simplement le nombre de millisecondes par 1 000 an dobtenir le nombre de secondes. Elle divise ensuite ce rsultat par 60 pour obtenir le nombre de minutes. Ensuite, elle doit soustraire les minutes des secondes. Par exemple, 123 secondes remplissent 2 minutes. En soustrayant 2 60 123, on obtient 3 secondes restantes. 123 correspond donc 2 minutes et 3 secondes :
public function clockTime(ms:int) { var seconds:int = Math.oor(ms/1000); var minutes:int = Math.oor(seconds/60); seconds -= minutes*60;

122

ActionScript 3.0 pour les jeux

prsent que nous avons le nombre de minutes et de secondes, nous devons insrer un signe deux-points entre les deux et veiller ce que les secondes soient toujours exprimes laide de deux chiffres. Je me sers dune astuce pour cela. La fonction substr permet de rcuprer un nombre dni de caractres dune chane. Le nombre de secondes sera compris entre 0 et 59. Ajoutez-y 100 et vous obtenez un nombre compris entre 100 et 159. Rcuprez le second et le troisime caractre de ce nombre sous forme de chane et vous obtenez un nombre de secondes deux chiffres compris entre 00 et 59. Voici comment se traduit ceci en ActionScript :
var timeString:String = minutes+":"+String(seconds+100).substr(1,2);

Ensuite, nous retournons simplement la valeur :


return timeString; }

Le temps coul safche maintenant en haut de lcran dans un format numrique familier au lieu de reprsenter un nombre rbarbatif de millisecondes.

Afcher le score et le temps une fois la partie termine


Avant den terminer avec MatchingGame9.a, rcuprons les nouveaux afchages du score et du temps et transportons-les dans lcran gameover. Cette opration est un peu prilleuse car limage gameover se situe dans le scnario principal, en dehors du clip du jeu. Pour que le scnario principal sache mme ce que sont le score et le temps, ces donnes doivent tre transmises du niveau du jeu vers le niveau racine.
gameover,

Juste avant dappeler la commande gotoAndStop, qui doit faire avancer lanimation jusqu limage nous passons ces deux valeurs la racine :
MovieClip(root).gameScore = gameScore; MovieClip(root).gameTime = clockTime(gameTime);

Vous remarquerez que nous passons le score sous forme de valeur brute, alors que nous faisons passer le temps par la fonction clockTime an quil sagisse dune chane avec un signe deux-points et des secondes deux chiffres. Au niveau racine, nous devons dnir ces nouvelles variables, qui utilisent les mmes noms que les variables de jeu : gameTime et gameScore. Jai ajout ce code la premire image :
var gameScore:int; var gameTime:String;

Ensuite, dans limage gameover, nous utilisons ces variables pour placer des valeurs dans de nouveaux champs texte :
showScore.text = "Score: "+String(gameScore); showTime.text = "Time: "+gameTime;

Chapitre 3

Structure de jeu lmentaire : le Memory

123

Il nest pas ncessaire dutiliser du code pour crer les champs texte dynamiques showScore et showTime ; cela peut se faire sur la scne avec les outils ddition de Flash. La Figure 3.15 montre quoi ressemble maintenant lcran gameover lorsquune partie est termine.
Figure 3.15
Lcran de n de partie avec le score et le temps coul.

Pour simplier les choses, nous avons ici inclus les chanes "Score: " et "Time: " avec les champs Score et Time. Il aurait cependant t plus rigoureux dinclure les mots Score et Time sous forme de texte statique ou dimage lcran et de ninclure que le score et le temps euxmmes lintrieur des champs. Dans le cas prsent, il est indispensable de faire passer la variable gameScore dans la fonction String (car la proprit .text dun champ texte doit tre une chane). En conservant simplement gameScore, vous tenteriez de dnir une chane par un entier et provoqueriez un message derreur.

Voil tout pour MatchingGame9.a et MatchingGameObject9.a. Nous disposons maintenant dun jeu avec un cran dintroduction et un cran de n de partie. Il tient le registre du score, enregistre le temps coul et afche ces indications en n de partie. Il permet galement au joueur de lancer une nouvelle partie. Nous allons maintenant naliser le jeu en ajoutant une varit deffets spciaux, comme une animation pour le retournement des cartes, une limite de temps pour la visualisation des cartes et des effets sonores.

124

ActionScript 3.0 pour les jeux

Ajouter des effets


Quils semblent loin, les premiers temps des jeux sur le Web o la simple ide de pouvoir samuser un jeu dans une page semblait dj un exploit ! Il faut aujourdhui semployer crer des jeux de qualit pour esprer attirer des visiteurs, et ce souci de perfection peut tenir de simples touches de nition comme des animations et des sons. Essayons de soigner notre jeu de Memory laide de quelques effets spciaux. Sils ne changeront pas le jeu lui-mme, ils contribueront le rendre plus intressant pour les joueurs.

Retournements de cartes anims


Puisque nous retournons sans cesse des cartes virtuelles, il est assez cohrent de vouloir reprsenter ce mouvement de retournement par une animation. Vous pourriez le faire avec une srie dimages lintrieur dun clip mais, puisquil sagit ici dapprendre programmer, faisons-le en ActionScript.

Il est assez difcile ici dutiliser une animation dans le scnario au lieu dune animation ActionScript, par la nature mme des cartes. Le but est danimer non pas dix-huit cartes mais une seule. Il serait donc plus judicieux de placer les faces des cartes dans un autre clip et de changer limage de ce clip imbriqu au lieu du clip Card principal. Les images 2 et suivantes du clip Card peuvent alors tre utilises pour une squence anime prsentant un retournement de carte. Tout cela nest pas simple visualiser moins dtre habitu crer des animations Flash.

Puisque cette animation affecte les cartes et elles seules, il est judicieux de la placer lintrieur de la classe Card. Nous ne possdons cependant pas de classe Card. Au dbut de ce chapitre, nous avons choisi de ne pas utiliser de classe Card et de permettre simplement Flash de lui attribuer une classe par dfaut. Il est cette fois temps de crer une classe Card. Si nous crons un chier Card.as, il sera cependant utilis par tous les objets Card qui se trouvent dans le dossier. Nous avons dj les animations MatchingGame1.a MatchingGame9.a qui contiennent des objets Card. An de signier clairement que nous souhaitons que seule lanimation MatchingGame10.a utilise cette classe Card, nous changerons donc le nom du symbole et de la classe quil rfrence en choisissant Card10. Ensuite, nous crerons le chier de classe ActionScript Card10.as. Cette classe permettra de crer un retournement anim de la carte au lieu de la changer instantanment. Elle remplacera toutes les fonctions gotoAndStop dans la classe principale. Elle demandera aux cartes doprer le retournement avec startFlip. Elle passera galement limage que la carte doit afcher une fois le retournement effectu.

Chapitre 3

Structure de jeu lmentaire : le Memory

125

La classe Card10 dnira ensuite certaines variables, congurera un couteur vnementiel et enclenchera lanimation de la carte dans les dix images suivantes :
package { import ash.display.*; import ash.events.*; public dynamic class Card10 extends MovieClip { private var ipStep:uint; private var isFlipping:Boolean = false; private var ipToFrame:uint; // Commencer le retournement, mmoriser limage atteindre public function startFlip(ipToWhichFrame:uint) { isFlipping = true; ipStep = 10; ipToFrame = ipToWhichFrame; this.addEventListener(Event.ENTER_FRAME, ip); } // 10 tapes pour le retournement public function ip(event:Event) { ipStep--; // tape suivante if (ipStep > 5) { // Premire partie du retournement this.scaleX = .2*(ipStep-6); } else { // Deuxime partie du retournement this.scaleX = .2*(5-ipStep); } // Au milieu du retournement, passer nouvelle image if (ipStep == 5) { gotoAndStop(ipToFrame); } // la n du retournement, arrter lanimation if (ipStep == 0) { this.removeEventListener(Event.ENTER_FRAME, ip); } } } }

126

ActionScript 3.0 pour les jeux

La variable ipStep commence donc 10 lorsque la fonction startFlip est appele. Elle est ensuite rduite dune unit chaque image subsquente.

La proprit scaleX rduit ou tend la largeur dun clip. La valeur par dfaut est 1,0. La valeur 2,0 double sa largeur et la valeur 0,5 la rduit de moiti.

Si ipStep est comprise entre 6 et 10, la proprit scaleX de la carte se voit attribuer la valeur .2*(ipStep-6), qui doit tre 0,8, 0,6, 0,4, 0,2 et 0. Le clip se rtrcit donc chaque tape. Ensuite, lorsque ipStep est comprise entre 5 et 0, on utilise la nouvelle formule .2*(5-ipStep). Le rsultat devient donc 0, 0,2, 0,4, 0,6, 0,8, puis 1. Le clip retrouve ainsi sa taille normale. Lors de la cinquime tape, la carte passe la nouvelle image. Elle se rtrcit, jusqu se rduire rien, passe la nouvelle image puis sagrandit de nouveau. Pour raliser cet effet, jai d apporter une modication concernant la disposition des images dans le clip Card. Dans toutes les prcdentes versions du jeu, nous avions plac le coin suprieur gauche des cartes au centre du clip. Pour que la modication de scaleX donne limpression que la carte pivote autour de son centre, jai cependant d centrer les images de carte dans chaque image sur le centre du clip. Pour observer cette diffrence, comparez les clips Card dans MachingGame9.a et MatchingGame10.a. La Figure 3.16 montre le rsultat lors de ldition des clips. Lors de la dernire tape, lcouteur vnementiel est compltement supprim. Lintressant avec cette classe tient ce quelle fonctionne tout aussi bien lorsque la carte est recouverte (retourne face en bas) en allant limage 1.
Figure 3.16
Le ct gauche fait apparatre le point dalignement du clip en haut gauche, comme dans les neuf premires animations dexemple du chapitre. doite, le clip est centr, comme dans lexemple nal.

Examinez MatchingGameObject10.as et remarquez comme tous les appels gotoAndStop ont t remplacs par startFlip. Grce cette modication, nous crons non seulement une animation de retournement, mais donnons galement la classe Card un meilleur contrle sur elle-mme. Idalement, vous pourriez mme donner aux cartes un contrle complet sur elles-mmes en attribuant plus de fonctions la classe Card10.as, comme celles qui dnissent lemplacement des cartes au dbut du jeu.

Chapitre 3

Structure de jeu lmentaire : le Memory

127

Temps dafchage limit des cartes


Lun des ajouts intressants ce jeu consiste retourner automatiquement les paires de cartes non correspondantes une fois que le joueur les a regardes sufsamment longtemps. Par exemple, supposons que le joueur choisisse deux cartes. Elles ne forment pas une paire et restent donc afches pour que le joueur les observe. Aprs deux secondes, les cartes se retournent, mme si le joueur na pas commenc slectionner une autre paire. Pour raliser cela, nous utiliserons un Timer. Cet objet est trs utile pour ajouter ce type de fonction. Pour commencer, nous devons importer la classe Timer dans notre classe principale :
import ash.utils.Timer;

Ensuite, nous devons crer une variable de minuteur au dbut de la classe :


private var ipBackTimer:Timer;

Plus loin dans la fonction clickCard, nous devons ajouter du code juste aprs que le joueur a choisi la seconde carte, quil na pas obtenu de correspondance et que son score a t diminu. Le code de Timer suivant congure un nouveau minuteur qui appelle simplement une fonction au bout de 2 secondes :
ipBackTimer = new Timer(2000,1); ipBackTimer.addEventListener(TimerEvent.TIMER_COMPLETE,returnCards); ipBackTimer.start();

Lvnement TimerEvent.TIMER_COMPLETE se dclenche lorsquun minuteur a ni. Le plus souvent, le Timer boucle un certain nombre de fois, en dclenchant un vnement TimerEvent.TIMER chaque fois. Lors du dernier vnement, il dclenche galement lvnement TimerEvent.TIMER_COMPLETE. Comme nous ne souhaitons dlencher quun seul vnement un moment ultrieur donn, nous xons le nombre dvnements Timer un, puis recherchons TimerEvent.TIMER_COMPLETE. Aprs 2 secondes, la fonction returnCards est appele. Il sagit dune nouvelle fonction qui procde comme la dernire partie de lancienne fonction clickCard. Elle retourne la premire et la seconde slection face vers le bas (masque les cartes) puis positionne les valeurs rstCard et secondCard null. Elle supprime galement lcouteur :
public function returnCards(event:TimerEvent) { rstCard.startFlip(1); secondCard.startFlip(1); rstCard = null; secondCard = null; ipBackTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,returnCards); }

128

ActionScript 3.0 pour les jeux

La fonction returnCards duplique le code qui se trouvait auparavant dans clickCard. Dans MatchingGameObject10.as, jai donc remplac ce code dupliqu dans clickCard par un simple appel returnCards. Cest ainsi un seul et mme emplacement dans notre code qui se charge de retourner les paires de cartes pour les masquer. Comme returnCards requiert un paramtre dvnement, nous devons lui passer ce paramtre dans returnCards que nous ayons quelque chose passer ou non. Lappel lintrieur de clickCard passe donc simplement la valeur null :
returnCards(null);

prsent, si vous excutez lanimation et retournez deux cartes, elles se retournent automatiquement au bout de 2 secondes. Comme nous avons une commande removeEventListener dans la fonction returnCards, lcouteur est supprim mme si la fonction returnCards est dclenche par le joueur qui retourne une autre carte. Sans cela, le joueur retournerait une nouvelle carte, les deux premires seraient masques et lvnement serait dclench aprs 2 secondes alors mme que les deux cartes sont dj caches.

Effets sonores
Un jeu ne saurait tre considr comme complet sil nmet pas de son. ActionScript 3.0 permet aisment dajouter des effets sonores, bien que cette opration require quelques tapes. La premire consiste importer vos sons. Pour ma part, jai cr trois sons et souhaite les importer chacun dans la bibliothque :
FirstCardSound.aiff MissSound.aiff MatchSound.aiff

Une fois les sons imports, il convient de modier leurs proprits. Nommez-les tous en utilisant leur nom de chier sans lextension .aiff. Cochez en outre loption Exporter pour ActionScript et donnezleur le mme nom de classe que le nom de symbole. La Figure 3.17 prsente la bote de dialogue Proprits de lun des sons. Ensuite, congurons la classe principale du jeu de manire lire les sons au bon moment. Pour commencer, nous devons importer deux nouvelles classes an de pouvoir utiliser du son :
import ash.media.Sound; import ash.media.SoundChannel;

Ensuite, nous crons des variables de classe pour contenir des rfrences ces sons :
var theFirstCardSound:FirstCardSound = new FirstCardSound(); var theMissSound:MissSound = new MissSound(); var theMatchSound:MatchSound = new MatchSound();

Chapitre 3

Structure de jeu lmentaire : le Memory

129

Figure 3.17
Chaque son est une classe et devient accessible dans le code ActionScript par le nom de sa classe.

Pour ma part, je prfre charger une seule et mme fonction de procder la lecture de tous mes sons. Appelons cette fonction playSound et ajoutons-la la n de la classe :
public function playSound(soundObject:Object) { var channel:SoundChannel = soundObject.play(); }

prsent, lorsque nous souhaitons lire un son, il nous suft dappeler playSound avec la variable du son utiliser, comme ceci :
playSound(theFirstCardSound);

Dans MatchingGameObject10.as, jai ajout playSound(theFirstCardSound) lorsque le joueur clique sur la premire carte et lorsquil clique sur une carte alors que deux cartes non correspondantes sont dj retournes. Jai ajout playSound(theMissSound) lorsque la seconde carte est retourne et quil ny a pas de correspondance. Jai ajout playSound(theMatchSound) lorsque la seconde carte est retourne et quune correspondance est trouve.

130

ActionScript 3.0 pour les jeux

Voil tout ce quil faut pour ajouter des effets sonores notre jeu.

ce stade, il peut tre intressant de passer en revue vos paramtres de publication an de choisir les rglages pour la compression des sons. Vous pouvez sinon dnir la compression des sons individuellement pour chaque son dans les proprits du symbole. Dans un cas comme dans lautre, il est sans doute prfrable dutiliser un rglage forte compression, comme MP3 16Mbps, car il ne sagit que de simples effets sonores.

Modier le jeu
Il nous reste quelques autres petites modications avant de terminer ce jeu. Tout dabord, lorsque nous avons recentr toutes les cartes, nous avons provoqu un dcalage horizontal et vertical pour le placement des cartes. Il faut ajuster cela :
private static const boardOffsetX:Number = 145; private static const boardOffsetY:Number = 70;

Comment ai-je calcul ces valeurs ? Voici le raisonnement :

La scne fait 550 pixels de largeur. Il y a six cartes en largeur espaces de 52 pixels. Cela fait 550 6 52 pour lespace total restant gauche et droite. Je divise le tout par deux pour obtenir lespace droite. Les cartes sont cependant centres sur 0,0. Je dois donc soustraire la moiti de la largeur dune carte, soit 26. Ainsi, (550 6 52) / 2 26 = 145. Idem pour le dcalage vertical : (400 6 52) / 2 26 = 70.

Reste encore considrer le curseur. Lorsque le joueur se positionne pour cliquer sur une carte, aucun curseur spcial ne lui signale quil peut cliquer cet endroit. On peut aisment remdier cela en positionnant la proprit buttonMode de chaque carte au moment de la crer.
c.buttonMode = true;

Un curseur en forme de main apparat maintenant lorsque lutilisateur survole les cartes. Cest dj le cas pour les boutons Play et Play Again car il sagit de symboles de bouton. Jai enn opr une dernire modication en augmentant la cadence dimages de lanimation an de passer de 12 ips 60 ips. Vous pouvez le faire en choisissant Modication > Document et en paramtrant les proprits du document de lanimation. 60 ips, les animations de retournement des cartes sont bien plus uides. Et, grce au moteur ActionScript 3.0 ultrarapide, les ordinateurs lents peuvent excuter ce jeu avec cette cadence dimages leve.

Chapitre 3

Structure de jeu lmentaire : le Memory

131

Voil tout pour notre jeu de Memory, dont la version nale utilise les chiers suivants : MatchingGame10.a MatchingGameObject10.as Card10.as

4
Jeux crbraux : Simon et dduction
Au sommaire de ce chapitre

Tableaux et objets de donnes Jeu de Simon Jeu de dduction

134

ActionScript 3.0 pour les jeux

Au chapitre prcdent, nous avons examin un jeu qui intgrait une unique conguration de grille de jeu et dont la partie se terminait une fois la grille entirement efface. Bien des jeux proposent cependant plusieurs congurations possibles. Ils crent une situation pour le joueur, celui-ci agit, puis la situation suivante est mise en place. Ces jeux peuvent tre considrs comme des jeux tours. Dans ce chapitre, nous allons examiner deux jeux de ce type : le jeu de Simon et le jeu de dduction. Le premier demande au joueur dobserver et de rpter une squence. chaque tour, la squence sallonge, jusqu ce que le joueur ne suive plus. Le second demande au joueur de deviner une squence, en enchanant des tours et en se servant des indications fournies chaque tape pour tenter de se rapprocher de la solution au tour suivant. La conguration simple utilise au prcdent chapitre ne fonctionne pas pour ces jeux. Nous devons utiliser des tableaux et des objets de donnes pour stocker des informations concernant le jeu et utiliser ces objets de donnes pour dterminer le rsultat de chaque tour du joueur.

Tableaux et objets de donnes


Les jeux que nous allons crer dans ce chapitre requirent que lon stocke des informations concernant la partie et les dplacements du joueur. Pour cela, nous allons utiliser ce que les informaticiens appellent des structures de donnes. Les structures de donnes dsignent tout simplement des mthodes pour le stockage de groupes dinformations. La structure de donnes la plus simple est le tableau, qui stocke une liste dinformations. ActionScript propose galement des objets de donnes qui permettent de stocker des informations tiquetes. Vous pouvez imbriquer cette structure dans la premire et crer ainsi un tableau dobjets de donnes.

Tableaux
Un tableau est une liste de valeurs. Par exemple, si nous souhaitons quun joueur puisse choisir parmi une liste de personnages au dbut dune partie, nous pouvons stocker cette liste de la manire suivante :
var characterTypes:Array = new Array(); characterTypes = ["Warrior", "Rogue", "Wizard", "Cleric"];

Nous pourrions galement utiliser la commande push pour ajouter des lments au tableau. Le code suivant produit ainsi le mme rsultat que les lignes prcdentes :
var characterTypes:Array = new Array(); characterTypes.push("Warrior"); characterTypes.push("Rogue"); characterTypes.push("Wizard"); characterTypes.push("Cleric");

Chapitre 4

Jeux crbraux : Simon et dduction

135

Cet exemple cre un tableau de chanes. Les tableaux peuvent cependant contenir nimporte quel type de valeur, comme des nombres ou mme des objets dafchage tels que des sprites ou des clips.

Les tableaux peuvent non seulement contenir des valeurs de nimporte quel type, mais galement combiner ces diffrents types. Il est ainsi possible de crer un tableau comme le suivant : [7, "Hello"].

Lun des usages courants des tableaux dans les jeux consiste stocker les clips et les sprites au fur et mesure quils sont crs. Par exemple, au Chapitre 3, nous avons cr une grille de paires de cartes. Pour pouvoir y accder facilement, nous aurions pu stocker une rfrence chaque Card dans un tableau. Ce tableau aurait pu tre cr de la manire suivante si nous avions voulu crer dix cartes :
var cards:Array = new Array(); for(var i:uint=0;i<10;i++) { var thisCard:Card = new Card(); cards.push(thisCard); }

Il y a plusieurs avantages ce que les pices de votre jeu se trouvent dans un tableau. Par exemple, il est ais de les parcourir en boucle puis de vrier chaque pice an de retrouver des correspondances ou de dtecter des collisions.

Vous pouvez galement imbriquer des tableaux an de crer des tableaux de tableaux. Cela se rvle particulirement utile pour les grilles de pices de jeu comme pour le Chapitre 3. Par exemple, une grille de morpion pourrait tre reprsente comme ceci : [["X","O","O"], ["O","X","O"], ["X","O","X"]].

Vous pouvez ajouter de nouveaux lments aux tableaux, leur retirer des lments, les trier et faire porter une recherche sur leur contenu. Le Tableau 4.1 liste certaines des fonctions de tableau les plus courantes.
Tableau 4.1 : Fonctions de tableau courantes

Fonction
push pop unshift

Exemple
myArray.push("Wizard") myArray.pop() myArray.unshift("Wizard")

Description
Ajoute une valeur la n dun tableau Supprime la dernire valeur dun tableau et la retourne Ajoute une valeur au dbut dun tableau

136

ActionScript 3.0 pour les jeux

Tableau 4.1 : Fonctions de tableau courantes (Suite)

Fonction
shift

Exemple
myArray.shift("Wizard")

Description
Supprime la premire valeur dun tableau et la retourne Supprime les lments dun emplacement du tableau et y insre de nouveaux lments Retourne lemplacement dun lment ou 1 si llment nest pas trouv Trie un tableau

splice

myArray.splice(7,2,"Wizard","Bard")

indexOf sort

myArray.indexOf("Rogue") myArray.sort()

Les tableaux sont des structures de donnes courantes et indispensables dans les jeux. En fait, lensemble des structures de donnes dont il sera question dans cette section utilise des tableaux pour convertir un unique lment de donnes en une liste dlments de donnes.

Objets de donnes
Les tableaux font merveille lorsquil sagit de stocker des listes de valeurs uniques, mais que faire lorsque lon souhaite regrouper des valeurs les unes avec les autres ? Supposons que, dans un jeu daventure, vous souhaitiez mmoriser des types de personnages, des niveaux et des points de sant dans un groupe. Supposons ainsi quun personnage lcran soit un "Guerrier", au niveau 15, avec un niveau de sant compris entre 0,0 et 1,0. Vous pourriez utiliser un objet de donnes pour stocker ensemble ces trois lments dinformation.

Dans certains autres langages de programmation, lquivalent des objets de donnes correspond en fait aux tableaux associatifs. Comme les objets de donnes, les tableaux associatifs sont des listes dlments qui incluent une tiquette (une cl) et une valeur. Vous pouvez en ralit utiliser les tableaux standard de cette manire dans ActionScript, mais ils ne sont pas aussi exibles que les objets de donnes.

Pour crer un objet de donnes, vous pouvez le dnir comme tant de type Object, puis lui ajouter des proprits avec la syntaxe points :
var theCharacter:Object = new Object(); theCharacter.charType = "Warrior"; theCharacter.charLevel = 15; theCharacter.charHealth = 0.8;

Chapitre 4

Jeux crbraux : Simon et dduction

137

Si vous le souhaitez, vous pouvez crer cette mme variable de la manire suivante :
var theCharacter:Object = {charType: "Warrior", charLevel: 15, charHealth: 0.8};

Les Object sont dynamiques, ce qui signie que vous pouvez leur ajouter de nouvelles proprits ds que vous le souhaitez et que ces proprits peuvent tre de nimporte quel type. Il nest pas ncessaire de dclarer les variables lintrieur dun Object ; vous navez qu leur attribuer une valeur comme dans lexemple prcdent. Les objets de donnes et les tableaux interagissent trs bien ensemble. Par exemple, vous pouvez crer un tableau de personnages comme le prcdent.

Les objets de donnes en ActionScript ne diffrent pas vraiment des objets normaux. Vous pouvez mme attribuer une fonction un objet de donnes. Par exemple, si vous avez un objet avec les proprits prenom et nom, vous pouvez crer une fonction nomcomplet() qui retourne prenom+" "+nom.

Tableaux dobjets de donnes


partir de maintenant, nous utiliserons dans presque chaque jeu des tableaux dobjets de donnes pour tenir le registre des lments du jeu. Nous pourrons ainsi stocker les sprites ou les clips euxmmes en plus des donnes les concernant. Par exemple, un objet de donnes pourrait ressembler ceci :
var thisCard:Object = new Object(); thisCard.cardobject = new Card(); thisCard.cardface = 7; thisCard.cardrow = 4; thisCard.cardcolumn = 2;

prsent, imaginons un tableau entier rempli de ces objets. Dans le jeu de Memory du Chapitre 3, nous aurions pu placer toutes les cartes dans des objets de cette sorte. Sinon imaginons un ensemble complet dlments lcran, comme dans un jeu darcade. Un tableau dobjets stockerait des informations les concernant, comme la vitesse, le comportement, lemplacement, etc.

Il existe un autre type dobjet, appel Dictionary. Les dictionnaires peuvent tre utiliss comme les Object, ceci prs quil est possible dutiliser nimporte quelle valeur comme cl, comme des sprites, des clips, dautres objets, enn, en somme, pratiquement nimporte quoi.

138

ActionScript 3.0 pour les jeux

Les structures de donnes comme les tableaux et les objets de donnes sont essentielles dans tous les jeux lexception des plus simples. Utilisons-les dans deux exemples de jeu complets.

Jeu de Simon
Codes sources http://ashgameu.com A3GPU04_MemoryGame.zip

Le jeu de Simon est un autre jeu simple pour les adultes et les enfants. Cest un jeu plus rcent que le Memory, lequel peut tre jou sans quipement technologique. Le jeu de Simon consiste prsenter une squence dimages ou de sons que le joueur doit tenter de reproduire. En gnral, la squence commence par un lment puis en ajoute un nouveau chaque tour. Le joueur doit ainsi rpter une squence un lment, puis deux, puis trois, etc., comme A, puis AD, puis ADC, puis ADCB, puis ADCBD, etc. En n de compte, la squence devient si longue que le joueur nit par faire une erreur et que la partie se termine.

La version la plus connue du jeu de Simon a t popularise par le jouet du mme nom commercialis dans le courant de lanne 1978. Il a t cr par Ralph Baer, considr comme lun des pres des jeux sur ordinateur. Ralph Baer a cr le jeu original Magnavox Odyssey, premier jeu de console familial. En 2005, il sest vu attribuer la Mdaille nationale de la technologie pour son rle de cration dans lindustrie du jeu vido.

Prparer lanimation
Conformment au style ActionScript 3.0, nous allons crer tous les lments du jeu dans notre code. Cela implique de commencer par un scnario principal vide mais pas une bibliothque vide. La bibliothque doit contenir au moins le clip pour les pices du jeu, qui seront des projecteurs dans cet exemple. Nous aurons cinq projecteurs, mais tous seront contenus dans un mme clip. En outre, il doit exister deux versions de chaque projecteur : allum et teint. Le clip Lights lui-mme (voir Figure 4.1) inclut deux images qui contiennent un autre clip, LightColors. Dans la premire image de Lights, un cache masque le clip LightColors et estompe sa couleur dans le calque Shade. Il sagit dun cache noir dont la proprit alpha est xe 75 %,

Chapitre 4

Jeux crbraux : Simon et dduction

139

ce qui signie que seulement 25 % de la couleur sous-jacente transparat. La premire image correspond donc une couleur attnue qui reprsente ltat teint des projecteurs. La seconde image ne contient plus ce cache et correspond donc ltat allum.
Figure 4.1
Le scnario du clip Lights contient deux images : teint et allum. Le clip est ici prsent avec le mode Aperu, auquel vous pouvez accder depuis le menu droulant situ en haut droite du scnario.

Il nexiste ni bon ni mauvais moyen de crer des lments de jeu comme les projecteurs de ce jeu de Simon. Vous pouvez avoir un clip pour chaque projecteur ou pour chaque tat de projecteur. Vous pourriez aussi placer les dix variantes (cinq projecteurs et deux tats possibles) dans un scnario dix images. Parfois, ces choix ne sont quaffaire de got. Si vous tes programmeur et que vous travailliez avec un artiste sur un jeu, lapproche peut tre adapte pour faciliter la cration des images par lartiste.

Le clip LightColors (voir Figure 4.2) contient cinq images qui afchent toutes une couleur diffrente. Le clip LightColors est nomm lightColors avec un l minuscule. Pour modier la couleur dun projecteur, il suft donc dutiliser lightColors.gotoAndStop avec le numro dimage. Nous nommerons lanimation MemoryGame.a et le chier ActionScript MemoryGame.as. Cela signie que la classe du document doit tre MemoryGame dans linspecteur des proprits, comme nous lavons fait pour le jeu de Memory au Chapitre 3.

140

ActionScript 3.0 pour les jeux

Figure 4.2
Le scnario du clip LightColors contient une couleur par image.

Stratgie de programmation
Lanimation commence avec rien, puis ActionScript cre tous les lments lcran. Nous devons donc crer les cinq projecteurs et leur attribuer chacun une couleur. Ensuite, nous devons crer deux champs texte : lun pour indiquer aux joueurs sils doivent observer la squence ou tenter de la reproduire et lautre pour leur faire savoir le nombre de projecteurs actuellement impliqus dans la squence.

Il existe de nombreuses autres solutions quutiliser deux champs texte pour afcher des informations. Par exemple, le nombre dlments dans la squence pourrait apparatre dans un cercle ou un rectangle sur un ct. Le texte "Watch and listen" (observez et coutez) et le texte "Repeat" (reproduisez) pourraient au lieu de cela tre des symboles qui sallument comme des feux vert et rouge de circulation. Les champs texte sont simplement un moyen pratique pour ne pas se soucier de ces lments et pour se concentrer ici sur le code de la logique du jeu.

Chapitre 4

Jeux crbraux : Simon et dduction

141

Les clips Light seront stocks dans un tableau. Il y a cinq projecteurs, soit cinq lments dans le tableau. Ce tableau nous permettra plus facilement de nous rfrer aux clips lorsque nous aurons besoin de les allumer ou de les teindre. Nous stockerons galement la squence dans un tableau. Elle commencera sous la forme dun tableau vide et nous y ajouterons un projecteur alatoire chaque tour. Une fois la lecture dune squence termine, nous dupliquerons le tableau de la squence. mesure que le joueur cliquera sur les projecteurs pour reproduire la squence, nous supprimerons un lment du devant du tableau chaque clic. Si cet lment de la squence correspond au clic, nous en dduirons que le joueur a fait le bon choix. Nous utiliserons galement des objets Timer dans ce jeu. Pour lire la squence, un minuteur appellera une fonction chaque seconde an dallumer un projecteur. Ensuite, un second minuteur dclenchera une fonction pour teindre le projecteur au bout dune autre demi-seconde.

Dnition de classe
Le chier MemoryGame.as contiendra le code de ce jeu. Noubliez pas de lassocier MemoryGame. a en dnissant la Classe du document dans linspecteur des proprits. Pour commencer le code, nous dclarerons le paquetage et la classe. Il faut importer quelques classes Flash. En plus de la classe ash.display.* pour afcher les clips, nous avons besoin de la classe ash.events.* pour les clics de souris, de la classe ash.text.* pour lafchage du texte et de ash.utils.Timer pour les minuteurs. Les classes ash.media.Sound et ash.media.SoundChannel sont requises pour lire les sons qui accompagnent les projecteurs. La classe ash.net.URLRequest est requise pour charger les sons depuis des chiers externes :
package { import ash.display.*; import ash.events.*; import ash.text.*; import ash.utils.Timer; import ash.media.Sound; import ash.media.SoundChannel; import ash.net.URLRequest;

Comment connaissais-je les noms des classes importer au dbut de ce code ? Simple : je les ai recherchs dans les pages de laide Flash. Par exemple, pour trouver ce dont javais besoin pour un champ texte, jai consult TextField et la dnition ma indiqu quil fallait ash.text.*. En fait, au lieu dexaminer la page de documentation, je saute en gnral directement la n de la page pour examiner le code dexemple. La commande import est trs facile retrouver de cette manire.

142

ActionScript 3.0 pour les jeux

La dnition de classe inclut plusieurs dclarations de variables. La seule constante que nous utiliserons est le nombre de projecteurs dans le jeu (ici, cinq) :
public class MemoryGame extends Sprite { static const numLights:uint = 5;

Nous aurons trois tableaux principaux : lun pour contenir des rfrences aux cinq clips de projecteur, puis deux pour contenir la squence de projecteurs. Le tableau playOrder stendra chaque tour. Le tableau repeatOrder contiendra un duplicata du tableau playOrder lorsque le joueur reproduit la squence. Il se rduira mesure que le joueur cliquera sur les projecteurs et que les comparaisons seront effectues avec chacun des projecteurs dans la squence :
private var lights:Array; // Liste des objets projecteur private var playOrder:Array; // Squence croissante private var repeatOrder:Array;

Il nous faut deux champs texte, lun pour contenir un message destination du joueur en haut de lcran et un autre pour contenir la longueur de la squence actuelle en bas de lcran :
// Message texte private var textMessage:TextField; private var textScore:TextField;

Nous utiliserons deux minuteurs dans le jeu. Le premier allumera chaque projecteur dans la squence au cours de sa lecture. Le second sera utilis pour teindre les projecteurs une demi-seconde plus tard :
// Minuteurs private var lightTimer:Timer; private var offTimer:Timer;

Parmi les autres variables requises gure gameMode, qui stockera la valeur "play" ou la valeur "replay" selon que le joueur observe la squence ou tente de la reproduire. La variable currentSelection stockera une rfrence aux clips Light. Le tableau soundList contiendra des rfrences aux cinq sons qui seront jous avec les projecteurs :
var gameMode:String; // Lecture (play) ou reproduction (replay) var currentSelection:MovieClip = null; var soundList:Array = new Array(); // Contient les sons

Voil lensemble des variables que nous devons suivre. Nous aurions galement pu inclure des constantes pour le positionnement du texte et des projecteurs, mais nous les coderons en dur an de nous concentrer sur le fonctionnement du code.

Congurer le texte, les projecteurs et les sons


La fonction constructeur MemoryGame sexcute ds que la classe est initialise. Nous lutiliserons pour congurer lcran du jeu et charger les sons. La Figure 4.3 prsente lcran au tout dbut du jeu.

Chapitre 4

Jeux crbraux : Simon et dduction

143

Figure 4.3
Lcran du jeu de Simon prsente deux champs texte et cinq projecteurs.

Ajouter le texte
Avant de congurer lun ou lautre champ texte, nous allons crer un objet TextFormat temporaire et dnir lapparence que nous souhaitons donner notre texte. Nous utiliserons cette variable temporaire lors de la cration des deux champs texte et nen aurons plus besoin ensuite. Il nest donc pas ncessaire de dnir la variable textFormat (notez lutilisation du t minuscule) dans la classe principale, mais uniquement dans cette fonction :
public function MemoryGame() { // Mise en forme du texte var textFormat = new TextFormat(); textFormat.font = Arial; textFormat.size = 24; textFormat.align = center;

Le champ texte du haut, qui doit tre nomm textMessage, contiendra un message lintention du joueur lui indiquant sil doit observer et couter la squence ou sil doit cliquer sur les projecteurs an de la reproduire. Nous le placerons vers le haut de lcran. Il fera 550 pixels de large, soit la largeur complte de lcran. Comme textFormat.align vaut "center" et comme le champ texte couvre la largeur de lcran, le texte doit tre centr lcran. Nous devons galement positionner la proprit selectable du champ false. Sans cela, le curseur se changera en un curseur de slection de texte lorsque le joueur survolera le champ.

144

ActionScript 3.0 pour les jeux

Loubli qui consiste ne pas attribuer la valeur false la proprit selectable dun champ texte fait partie des erreurs courantes. Par dfaut, la proprit selectable vaut true, ce qui signie que le curseur se transforme en un curseur ddition de texte lorsque le joueur survole le champ. Lutilisateur peut alors slectionner le texte mais, plus important encore, ne peut aisment cliquer sur les objets qui gurent sous le texte.

Pour nir, nous positionnons defaultTextFormat notre objet textFormat an de dnir la police, la taille de police et lalignement du texte pour le champ :
// Cration du champ texte suprieur textMessage = new TextField(); textMessage.width = 550; textMessage.y = 110; textMessage.selectable = false; textMessage.defaultTextFormat = textFormat; addChild(textMessage);

Le second champ texte afche la longueur de la squence courante an que le joueur puisse valuer son avancement. Il se trouvera vers le bas de lcran :
// Cration du champ texte infrieur textScore = new TextField(); textScore.width = 550; textScore.y = 250; textMessage.selectable = false; textScore.defaultTextFormat = textFormat; addChild(textScore);

Charger les sons


Ensuite, nous allons charger les sons. Au Chapitre 3, nous avons utilis des sons qui se trouvaient dans la bibliothque de lanimation. ActionScript 3.0 ne rend pas cette mthode exible parce que chaque son dans la bibliothque doit tre rfrenc comme son propre objet. Pour utiliser cinq sons, "note1" "note5", il faudrait alors cinq objets spars et des lignes de code distinctes pour chacun. ActionScript 3.0 propose en fait un jeu de commandes bien plus robuste pour la lecture des chiers son externes. Nous les utiliserons pour ce jeu. Pour cela, nous chargerons cinq chiers son, "note1. mp3" "note5.mp3", dans un tableau de sons.

Flash insiste sur le fait que les sons externes soient au format MP3. Le grand intrt du MP3 tient ce que vous pouvez vritablement contrler la taille et la qualit dun chier avec votre logiciel ddition audio. Vous pouvez donc crer des sons de petite taille et de faible qualit lorsquil convient de rduire le temps de tlchargement ou des sons volumineux de haute qualit lorsque cette dlit est requise.

Chapitre 4

Jeux crbraux : Simon et dduction

145

// Chargement des sons soundList = new Array(); for(var i:uint=1;i<=5;i++) { var thisSound:Sound = new Sound(); var req:URLRequest = new URLRequest("note"+i+".mp3"); thisSound.load(req); soundList.push(thisSound); }

Le

lintrieur de la fonction URLRequest construit une chane du type Le symbole + concatne les chanes et les autres lments en une chane plus longue. Le rsultat correspond donc la concatnation de "note" plus la valeur de la variable i, plus ".mp3".
"note"+i+".mp3" "note1.mp3".

Ajouter les clips Light


Maintenant que nous avons des champs texte et des sons, il ne nous reste plus qu ajouter les projecteurs. Nous crerons cinq clips Light et les espacerons de manire les centrer. Pour chaque objet Light, nous enverrons le clip lightColors intrieur une image diffrente an que chaque clip possde une couleur diffrente. En plus dajouter les clips la scne avec addChild, nous les ajouterons au tableau lights pour nous y rfrer par la suite. addEventListener permet aux clips de ragir aux clics de souris en appelant la fonction clickLight. Nous positionnerons galement la proprit buttonMode de manire que le curseur se transforme en une main lorsque lutilisateur survole le projecteur :
// Cration des projecteurs lights = new Array(); for(i=0;i<numLights;i++) { var thisLight:Light = new Light(); thisLight.lightColors.gotoAndStop(i+1); // Afcher limage approprie thisLight.x = i*75+100; // Position thisLight.y = 175; thisLight.lightNum = i; // Mmoriser numro de projecteur lights.push(thisLight); // Ajouter au tableau des projecteurs addChild(thisLight); // Ajouter lcran thisLight.addEventListener(MouseEvent.CLICK,clickLight); thisLight.buttonMode = true; }

146

ActionScript 3.0 pour les jeux

Tous les lments cran ont t crs. Il est maintenant temps de commencer le jeu. Nous allons attribuer un nouveau tableau vide playOrder, gameMode, pour "jouer" puis appeler nextTurn pour dmarrer le premier projecteur dans la squence :
// Rinitialisation de la squence, premier tour playOrder = new Array(); gameMode = "play"; nextTurn(); }

Lire la squence
La fonction nextTurn soccupe de dclencher chaque squence de lecture. Elle ajoute un projecteur alatoire la squence, positionne le message en haut de lcran en afchant "Watch and Listen" et dclenche le lightTimer qui afche la squence :
// Ajoute un la squence et dmarre public function nextTurn() { // Ajoute un nouveau projecteur la squence var r:uint = Math.oor(Math.random()*numLights); playOrder.push(r);

// Afche le texte textMessage.text = "Watch and Listen."; textScore.text = "Sequence Length: "+playOrder.length;

// Congure les minuteurs pour afcher la squence lightTimer = new Timer(1000,playOrder.length+1); lightTimer.addEventListener(TimerEvent.TIMER,lightSequence);

// Lance le minuteur lightTimer.start(); }

Lorsquune squence commence jouer, la fonction lightSequence est appele chaque seconde. Lvnement est pass en paramtre. Le currentTarget de cet event est lquivalent du Timer. Lobjet Timer possde une proprit nomme currentCount qui retourne le nombre de fois o le minuteur sest arrt. Nous linsrons dans playStep et pouvons lutiliser pour dterminer le projecteur dans la squence allumer.

Chapitre 4

Jeux crbraux : Simon et dduction

147

La fonction vrie la valeur de playStep an de dterminer sil va sagir du dernier arrt du minuteur. Si cest le cas, au lieu dafcher un projecteur, elle commence la deuxime moiti dun tour, lorsque le joueur doit rpter la squence :
// Lire llment suivant de la squence public function lightSequence(event:TimerEvent) { // O nous trouvons-nous dans la squence ? var playStep:uint = event.currentTarget.currentCount-1; if (playStep < playOrder.length) { // Ce nest pas la dernire tape lightOn(playOrder[playStep]); } else { // La squence est termine startPlayerRepeat(); } }

Allumer et teindre les projecteurs


Lorsquil est temps pour le joueur de commencer rpter la squence, nous remplaons le message texte par "Repeat" et attribuons gameMode la valeur "replay". Ensuite, nous crons une copie de la liste playOrder :
// Dbut de la rptition du joueur public function startPlayerRepeat() { currentSelection = null; textMessage.text = "Repeat."; gameMode = "replay"; repeatOrder = playOrder.concat(); }

Pour crer une copie dun tableau, nous utilisons la fonction concat. Bien quelle soit destine crer un nouveau tableau partir de plusieurs tableaux, elle fonctionne aussi bien pour crer un nouveau tableau partir dun seul autre tableau. Pourquoi procder de cette manire au lieu de crer simplement un nouveau tableau et de le dnir comme tant gal au premier ? Si nous posons une galit entre les deux tableaux, ces tableaux seront littralement identiques. En modiant lun, nous modierons lautre. Pour notre part, nous souhaitons crer un second tableau qui soit une copie du premier, de manire que les modications du second naffectent pas le premier. Voil ce que nous permet de faire la fonction concat.

Les deux fonctions suivantes allument et teignent un projecteur (Light). Nous passons le nombre de projecteurs dans la fonction. Lallumage dun projecteur requiert simplement dutiliser gotoAndStop(2) pour envoyer le clip Light la seconde image qui ne contient pas le cache recouvrant la couleur.

148

ActionScript 3.0 pour les jeux

Au lieu dutiliser les numros dimage 1 et 2, nous aurions galement pu intituler les images "on" et "off" et utiliser des noms dtiquette dimage. Cette mthode serait particulirement utile dans des jeux o interviennent plus de deux modes par clip.

Nous lirons galement le son associ au projecteur, mais en utilisant une rfrence au son dans le tableau soundList que nous avons cr.
lightOn

fait encore une dernire chose : crer et dmarrer le minuteur offTimer. Celui-ci ne se dclenche quune seule fois, 500 millisecondes aprs lallumage du projecteur :
// Allumage du projecteur et conguration du minuteur pour lteindre public function lightOn(newLight) { soundList[newLight].play(); // Lecture du son currentSelection = lights[newLight]; currentSelection.gotoAndStop(2); // Allumage du projecteur offTimer = new Timer(500,1); // Rappel pour lteindre offTimer.addEventListener(TimerEvent.TIMER_COMPLETE,lightOff); offTimer.start(); }

La fonction lightOff renvoie ensuite le clip Light la premire image. Cest l quil savre pratique de stocker une rfrence au clip Light dans currentSelection. Cette fonction demande galement au minuteur offTimer de sarrter. Pourtant, si offTimer ne se dclenche quune seule fois, quoi cela sert-il ? En ralit, si offTimer ne se dclenche quune seule fois, lightOff pourrait tre appele deux fois. Cela se produit si le joueur rpte la squence et clique sufsamment rapidement sur les projecteurs pour quils steignent avant que les 500 millisecondes expirent. Dans ce cas, lightOff est appele une fois pour le clic de souris, puis une nouvelle fois lorsque le minuteur lightOff sarrte. En mettant une commande offTimer.stop(), nous parvenons ainsi arrter ce second appel lightOff :
// teindre le projecteur si toujours allum public function lightOff(event:TimerEvent) { if (currentSelection != null) { currentSelection.gotoAndStop(1); currentSelection = null; offTimer.stop(); } }

Chapitre 4

Jeux crbraux : Simon et dduction

149

Accepter et vrier lentre de lutilisateur


La dernire fonction requise pour le jeu est appele lorsque le joueur clique sur un projecteur (Light) pendant la rptition de la squence.
"replay".

Elle commence par une vrication du mode de jeu (gameMode) an de sassurer que playMode vaut Sinon le joueur ne doit pas cliquer sur les projecteurs et la commande return est utilise pour sortir de la fonction.

Si return est gnralement utilise pour renvoyer une valeur partir dune fonction, elle peut galement tre utilise pour terminer une fonction qui nest pas cense retourner de valeur du tout. Dans un tel cas, il suft dune simple commande return seule. Si la fonction est suppose retourner une valeur, return doit cependant tre suivie par la valeur.

En supposant que cela ne se produise pas, la fonction lightOff est appele pour teindre le projecteur prcdent sil ne lest pas dj. Une comparaison est ensuite opre. Le tableau repeatOrder contient un duplicata du tableau playOrder. Nous utilisons la commande shift pour retirer le premier lment du tableau repeatOrder et le comparer la proprit lightNum du projecteur sur lequel le joueur a cliqu.

Rappelez-vous que shift retire un lment du devant du tableau, alors que pop le retire lautre extrmit. Si vous souhaitez simplement tester le premier lment dun tableau et non lenlever, vous pouvez utiliser monTableau[0]. De la mme manire, vous pouvez utiliser monTableau[monTableau.length-1] pour tester le dernier lment dun tableau.

En cas de correspondance, ce projecteur est allum.


repeatOrder se raccourcit mesure que des lments sont supprims du devant du tableau pour tre compars. Lorsque repeatOrder.length atteint zro, la fonction nextTurn est appele et la squence est ajoute et rejoue une nouvelle fois.

Si le joueur a choisi le mauvais projecteur, le message texte est modi an dindiquer que la partie est termine et gameMode est chang de manire quaucun autre clic de souris ne soit accept :
// Rception des clics de souris sur les projecteurs public function clickLight(event:MouseEvent) { // Empcher les clics pendant lafchage de la squence if (gameMode != replay) return; // teindre projecteur sil ne sest pas teint lui-mme lightOff(null);

150

ActionScript 3.0 pour les jeux

// Rponse exacte if (event.currentTarget.lightNum == repeatOrder.shift()) { lightOn(event.currentTarget.lightNum); // Vrier si la squence est termine if (repeatOrder.length == 0) { nextTurn(); } // Mauvaise rponse } else { textMessage.text = "Game Over!"; gameMode = gameover; } }

La valeur "gameover" de gameMode nest en fait utilise par aucun fragment de code. Puisquelle est diffrente de "repeat", les clics ne seront cependant pas accepts par les projecteurs, ce qui est exactement leffet recherch. Il ne reste plus maintenant que les accolades de fermeture des structures de classe et de paquetage. Elles viennent la n de chaque chier de paquetage AS. Le jeu ne peut se compiler en leur absence.

Modier le jeu
Au Chapitre 3, nous avons commenc par un jeu qui sexcutait dans le scnario principal, un peu comme ici. la n du chapitre, nous avons cependant plac le jeu lintrieur dun clip attitr (en rservant le scnario principal aux crans dintroduction et de n de partie). Vous pouvez procder de la mme manire ici. Sinon vous pouvez renommer la fonction MemoryGame en lappelant startGame. Elle ne sera ainsi plus dclenche ds le dpart de lanimation. Vous pourriez placer un cran dintroduction dans la premire image de lanimation, avec une commande stop dans limage et un bouton pour mettre la commande play an que lanimation se poursuive et passe limage suivante. Dans cette image, vous pourriez appeler la fonction startGame an de lancer la partie.

Si vous souhaitez tendre ce jeu au-del dune image, vous devez changer extends Sprite au dbut de la classe en le remplaant par extends MovieClip. Un sprite est un clip dot dune seule image, tandis quun clip peut contenir plusieurs images.

Chapitre 4

Jeux crbraux : Simon et dduction

151

Ensuite, au lieu dafcher simplement le message "Game Over" lorsque le joueur rate un coup, vous pourriez supprimer tous les projecteurs et le message texte avec removeChild et passer directement une nouvelle image. Ces deux mthodes (encapsuler le jeu dans un clip ou attendre limage 2 pour dmarrer le jeu) permettent de crer une application plus complte. Lune des modications qui pourraient tre apportes ce jeu consisterait commencer demble avec une squence de plusieurs tapes. Vous pourriez inclure au dpart deux nombres alatoires dans playOrder ; le jeu commencerait alors avec un total de trois lments dans la squence. Une autre modication intressante pourrait consister faciliter le jeu en najoutant dans la squence que de nouveaux lments qui ne correspondent pas au dernier. Par exemple, si le premier lment est 3, le suivant pourrait tre 1, 2, 4 ou 5. Le fait de ne pas rpter les lments rduit lgrement la complexit du jeu. Vous pourriez pour cela utiliser une simple boucle while :
do { var r:uint = Math.oor(Math.random()*numLights); } while (r == playOrder[playOrder.length-1]);

Vous pourriez galement augmenter la vitesse laquelle la squence est rejoue. Pour linstant, les projecteurs sallument toutes les 1 000 millisecondes. Ils steignent aprs 500 millisecondes. Vous pourriez ainsi stocker la valeur 1 000 dans une variable (comme lightDelay) puis rduire cette valeur de 20 millisecondes chaque tour. Utilisez sa valeur entire pour lightTimer et la moiti de sa valeur pour offTimer. Les variantes les plus intressantes de ce jeu soprent sans doute en apportant des modications non pas au code mais plutt aux graphismes. Pourquoi les projecteurs devraient-ils ncessairement tre aligns ? Pourquoi leur donner tous la mme apparence ? Pourquoi dailleurs utiliser des projecteurs ? Imaginez un jeu o les projecteurs seraient remplacs par des oiseaux chanteurs, tous diffrents et tous cachs dans une scne sylvestre. mesure quils ouvriraient leurs becs et ppieraient, vous seriez invit vous rappeler non seulement lesquels ont sif mais galement lendroit o ils taient situs.

Jeu de dduction
Voici un autre jeu classique. Comme le jeu de Memory, le jeu de dduction peut tre jou avec un simple jeu de pices. Il peut mme tre jou avec un crayon et du papier. Sans ordinateur, on ne peut cependant jouer qu deux joueurs. Lun doit produire une squence en quelque manire alatoire de couleurs tandis que lautre doit sefforcer de la deviner.

152

ActionScript 3.0 pour les jeux

Codes sources http://ashgameu.com A3GPU04_Deduction.zip

Le jeu de dduction a t popularis sous le nom de marque Mastermind. Il sagit de lun des jeux de dcouverte de code les plus simples.

Le jeu est gnralement jou avec une squence alatoire de cinq pions, chacun dune couleur parmi cinq possibles (par exemple rouge, vert, violet, jaune et bleu). Le joueur doit tenter une proposition pour chacun des cinq pions, mme sil peut ne proposer aucun choix pour un ou plusieurs pions. Le joueur peut donc par exemple proposer comme essai rouge, rouge, bleu, bleu, vide. Lorsque le joueur fournit sa proposition, lordinateur retourne le nombre de pions correctement placs et le nombre de pions dont la couleur correspond celle dun pion requis mais qui ne se trouve pas au bon endroit pour le moment. Ainsi, si la squence est rouge, vert, bleu, jaune, bleu et que le joueur propose la squence rouge, rouge, bleu, bleu, vide, le rsultat correspond une couleur au bon emplacement et une couleur exacte. Le joueur doit alors exploiter ces deux lments dinformation pour laborer sa proposition suivante. Un bon joueur parvient gnralement deviner la squence complte en moins de dix tentatives.

Mathmatiquement, il est possible de deviner nimporte quelle squence alatoire en cinq tentatives uniquement. Il faut pour cela des algorithmes plutt volus. Pour plus dinformations ce sujet, consultez larticle Wikipdia Mastermind en version anglaise.

Congurer lanimation
Nous allons congurer ce jeu de manire un peu plus robuste que le jeu de Simon. Il possdera trois images : une image dintroduction, une image de jeu et une image de n de partie. Toutes les trois possderont une apparence minimaliste an que nous puissions nous concentrer sur le code ActionScript. Un arrire-plan et un titre seront inclus dans les trois images. Vous pouvez le voir la Figure 4.4. Limage 1 contient un unique bouton. Jai cr un objet dafchage de bouton BasicButton simple dans la bibliothque. Il ne contient en fait aucun texte : le texte qui apparat la Figure 4.4 est en ralit plac au-dessus du bouton dans limage.

Chapitre 4

Jeux crbraux : Simon et dduction

153

Figure 4.4
Limage 1 inclut un arrire-plan et un titre qui sont prsents dans toutes les images, ainsi quun bouton Start qui ne gure que dans cette premire image.

Le script de limage 1 arrte lanimation cette image et congure le bouton de manire accepter un clic de souris pour dmarrer le jeu :
stop(); startButton.addEventListener(MouseEvent.CLICK,clickStart); function clickStart(event:MouseEvent) { gotoAndStop(play); }

La seconde image, intitule "play" dans le scnario, ne contiendra quune seule commande. Il sagit dun appel dans notre classe danimation une fonction nomme startGame que nous allons crer :
startGame();

La dernire image est intitule "gameover" et possde sa propre copie du bouton de limage 1. Le texte situ au-dessus est cette fois "Play Again". Le script dans limage est trs similaire :
playAgainButton.addEventListener(MouseEvent.CLICK,clickPlayAgain); function clickPlayAgain(event:MouseEvent) { gotoAndStop(play); }

Il nous faut deux symboles en plus du symbole de bibliothque BasicButton. Le premier est un petit bouton nomm DoneButton. Comme le montre la Figure 4.5, il inclut cette fois le texte qui lillustre.

154

ActionScript 3.0 pour les jeux

Figure 4.5
Le bouton Done utilis dans le jeu fait la mme hauteur que les trous pion utiliss dans le jeu.

Le clip principal requis pour le jeu est le clip Peg. Il sagit de plus que dun simple pion. Cest une srie de six images, la premire prsentant un trou vide et les cinq suivantes afchant cinq ampoules de couleur diffrente dans le trou. La Figure 4.6 prsente ce clip.
Figure 4.6
Le clip Peg contient une prise dampoule vide et cinq images o cette prise est remplie par une ampoule de couleur diffrente.

Chapitre 4

Jeux crbraux : Simon et dduction

155

part larrire-plan et le titre, le scnario principal ne contient rien. Nous allons utiliser le code ActionScript pour crer tous les lments du jeu. Et, cette fois, nous tiendrons le registre de chaque objet cr an de pouvoir les supprimer en n de partie.

Dnition de la classe
Lanimation de cet exemple est nomme Deduction.a et le chier ActionScript, Deduction.as. La classe du document dans linspecteur des proprits doit donc tre Deduction an que lanimation utilise le chier AS correspondant. La dnition de classe de ce jeu est un peu plus simple que celle du jeu de Simon. En effet, nous nutiliserons cette fois ni minuteur ni son. Seules les classes ash.display, ash.events et ash. text seront donc importes : la premire pour afcher et contrler les clips, la deuxime pour ragir aux clics de souris et la troisime pour crer des champs texte :
package { import ash.display.*; import ash.events.*; import ash.text.*;

Pour la dclaration de classe, nous la ferons tendre MovieClip au lieu de Sprite. En effet, le jeu stendra sur trois images et non une. Or un sprite nutilise quune image :
public class Deduction extends MovieClip {

Pour ce jeu, nous utiliserons une large gamme de constantes. Dabord, nous dnirons les constantes numPegs et numColors. Nous pourrons ainsi aisment modier le jeu an dinclure plus de cinq pions dans la squence ou plus ou moins doptions de couleur. Nous incluerons galement un ensemble de constantes an de dnir lemplacement o seront dessines les lignes de pions. Nous utiliserons un dcalage horizontal et vertical pour toutes les lignes ainsi que lespacement entre les lignes et lespacement entre les pions. Nous facilitons ainsi lajustement de lemplacement des pions en fonction de la taille des pions et des lments environnants du jeu :
// Constantes static const numPegs:uint = 5; static const numColors:uint = 5; static const maxTries:uint = 10; static const horizOffset:Number = 30; static const vertOffset:Number = 60; static const pegSpacing:Number = 30; static const rowSpacing:Number = 30;

156

ActionScript 3.0 pour les jeux

Il nous faut deux variables principales pour tenir le registre de ltat davancement dans le jeu. La premire est un tableau contenant la solution. Il sagira dun simple tableau de cinq nombres (par exemple 1, 4, 3, 1, 2). La seconde variable est turnNum, qui tient le registre du nombre de tentatives ralises par le joueur :
// Variables de jeu private var solution:Array; private var turnNum:uint;

Dans ce jeu, nous allons tenir un registre prcis de tous les objets dafchage que nous crons. Il y aura une ligne courante de cinq pions stocke dans currentRow. Le texte droite de chaque ligne de pions sera currentText. Le bouton droite des pions sera currentButton. En outre, nous utiliserons le tableau allDisplayObjects pour tenir le registre de tout ce que nous crons :
// Rfrences aux objets dafchage private var currentRow:Array; private var currentText:TextField; private var currentButton:DoneButton; private var allDisplayObjects:Array;

Chaque classe a sa fonction constructeur, qui possde le mme nom que la classe. Ici, nous ne lutiliserons cependant pas, car le jeu ne commence pas dans la premire image. Nous attendons que le joueur clique dabord sur le bouton Start. Nous incluerons donc cette fonction, mais sans y insrer de code :
public function Deduction() { }

Libre vous de voir si vous souhaitez inclure une fonction constructeur vide. Pour ma part, il marrive trs souvent de raliser aprs coup que je dois raliser quelque chose dans la fonction constructeur avant de naliser mon jeu ; dans le doute, je lajoute donc demble lorsque je commence une classe.

Dmarrer une nouvelle partie


Lorsquune nouvelle partie commence, le scnario principal appelle startGame an de crer la squence de cinq pions que recherche le joueur. Cette fonction cre le tableau de solution et y insre cinq nombres alatoires compris entre 1 et 5.

Chapitre 4

Jeux crbraux : Simon et dduction

157

La variable turnNum est positionne 0. Ensuite, la fonction createPegRow est appele pour faire le gros du travail :
// Crer la solution et afcher la premire ligne de pions public function startGame() { allDisplayObjects = new Array(); solution = new Array(); for(var i:uint=0;i<numPegs;i++) { // Alatoire, compris entre 1 et 5 var r:uint = uint(Math.oor(Math.random()*numColors)+1); solution.push(r); } turnNum = 0; createPegRow(); }

Crer une ligne de pions


Cest la fonction createPegRow qui ralise tout le travail qui consiste crer les cinq pions ainsi que le bouton et le texte ct. Nous lappellerons chaque fois quun tour commence. Elle cre dabord cinq nouvelles copies de lobjet Peg de la bibliothque. Chaque objet est plac lcran en fonction des valeurs des constantes pegSpacing, rowSpacing, horizOffset et vertOffset. Chaque objet est galement positionn limage 1, qui correspond au trou vide. La commande addEventListener fait ragir chaque pion un clic de souris. Nous activons aussi la proprit buttonMode des pions an que le curseur change quand lutilisateur les survole. La proprit pegNum est ajoute chaque pion lorsquil est cr, an de pouvoir identier le pion sur lequel le joueur a cliqu. Une fois que le pion est ajout lcran avec addChild, il est galement ajout allDisplayObjects. Ensuite, il est ajout currentRow, mais pas lui-mme. Au lieu de cela, il est ajout currentRow sous la forme dun petit objet avec les proprits peg et color. La premire est une rfrence au clip. La seconde est un nombre dnissant la couleur, ou labsence, du pion dans le trou :
// Crer une ligne de pions, plus le bouton DONE et le champ texte public function createPegRow() {

// Crer des pions et en faire des boutons currentRow = new Array(); for(var i:uint=0;i<numPegs;i++) { var newPeg:Peg = new Peg(); newPeg.x = i*pegSpacing+horizOffset;

158

ActionScript 3.0 pour les jeux

newPeg.y = turnNum*rowSpacing+vertOffset; newPeg.gotoAndStop(1); newPeg.addEventListener(MouseEvent.CLICK,clickPeg); newPeg.buttonMode = true; newPeg.pegNum = i; addChild(newPeg); allDisplayObjects.push(newPeg);

// Enregistrer les pions sous forme de tableau dobjets currentRow.push({peg: newPeg, color: 0}); }

Une fois que les cinq pions ont t crs, une copie du clip DoneButton est ajoute droite. Mais, tout dabord, une vrication est opre an de voir si le currentButton existe dj. Il nexiste pas la premire fois quune ligne de pions est cre, aussi, le bouton est cr et ajout la scne. Il obtient aussi un couteur vnementiel et est ajout allDisplayObjects. Lemplacement horizontal du bouton est dtermin par des constantes. Il doit se trouver un de plus sur la droite du dernier pion dans la ligne. Nous navons besoin de dnir que labscisse x du bouton lorsquil est cr car nous le dplaons simplement vers le bas de lcran avec chaque nouvelle ligne de pions ajoute. La position x nest dnie que cette fois, mais la position y lest chaque fois que la fonction createPegRow est appele :
pegSpacing // Ne crer le bouton DONE que si nous ne lavons pas dj fait if (currentButton == null) { currentButton = new DoneButton(); currentButton.x = numPegs*pegSpacing+horizOffset+pegSpacing; currentButton.addEventListener(MouseEvent.CLICK,clickDone); addChild(currentButton); allDisplayObjects.push(currentButton); } // Positionner le bouton DONE avec la ligne currentButton.y = turnNum*rowSpacing+vertOffset;

Ajouter le champ texte


Aprs le bouton vient le champ texte. Celui-ci est dcal droite dun pegSpacing et de la largeur du currentButton. Nous ne ralisons aucune mise en forme particulire, an de faire simple. la diffrence du bouton, un nouveau champ texte sera ajout chaque fois que nous crons une ligne de pions. Pour rsoudre le puzzle, les joueurs doivent pouvoir examiner toutes leurs prcdentes tentatives et les rsultats obtenus.

Chapitre 4

Jeux crbraux : Simon et dduction

159

Le currentButton est dni en tant que DoneButton au dbut de la classe. Il ne se voit cependant pas attribuer de valeur. Lorsque cette fonction sapprte la premire fois lutiliser, sa valeur est donc null. La plupart des objets sont positionns null au moment o ils sont crs. Les nombres sont cependant positionns zro et ne peuvent jamais ltre null.

Le champ texte commence par les instructions "Click on the holes to place pegs and click DONE" (cliquez sur les trous pour placer les pions et cliquez sur DONE). Il contiendra plus tard les rsultats de chaque tentative la n des tours :
// Crer le message texte ct des pions et du bouton currentText = new TextField(); currentText.x = numPegs*pegSpacing+horizOffset+pegSpacing*2+currentButton.width; currentText.y = turnNum*rowSpacing+vertOffset; currentText.width = 300; currentText.text = Click on the holes to place pegs and click DONE.; addChild(currentText); allDisplayObjects.push(currentText); }

Examinez la Figure 4.7 an de voir quoi ressemble lcran lorsque la premire createPegRow est appele. Vous verrez les cinq pions, suivis par le bouton, puis le champ texte.
Figure 4.7
Lorsque le jeu commence, la premire ligne de trous de pion est cre et le joueur doit oprer sa premire conjecture.

160

ActionScript 3.0 pour les jeux

Vrication des propositions du joueur


Lorsque le joueur clique sur un trou de pion, il fait dler en boucle les pions colors et revient un trou vide sil clique assez de fois. Pour savoir sur quel pion (Peg) le joueur a cliqu, nous examinerons event.currentTarget.pegNum. Nous aurons ainsi un index rechercher dans le tableau currentRow. De l, nous pourrons obtenir les proprits color et Peg.

Les couleurs sont numrotes de un cinq, le zro reprsentant labsence de pion. Les images dans les clips sont cependant numrotes en commenant 1. Limage 1 est le trou vide et les images 2 6 correspondent aux couleurs. Gardez-le lesprit lorsque vous examinez le code et lajout +1 dans linstruction gotoAndStop.

La couleur du Peg est stocke dans currentColor, une variable temporaire qui nest utilise que dans cette fonction. Si cest infrieur au nombre de couleurs disponibles, le Peg afche simplement la couleur suivante. Si la dernire couleur est dj afche, le Peg boucle pour afcher le trou vide, qui est la premire image de la page :
// Le joueur clique sur un pion public function clickPeg(event:MouseEvent) { // Dterminer le pion et rcuprer la couleur var thisPeg:Object = currentRow[event.currentTarget.pegNum]; var currentColor:uint = thisPeg.color; // Avancer couleur du pion dune unit, boucler de 5 0 if (currentColor < numColors) { thisPeg.color = currentColor+1 } else { thisPeg.color = 0; } // Afcher le pion ou labsence de pion thisPeg.peg.gotoAndStop(thisPeg.color+1); }

Pour jouer, lutilisateur dplace vraisemblablement le curseur sur chacun des cinq trous dans la ligne courante et clique le nombre requis de fois pour afcher la couleur de pion souhaite. Aprs avoir fait cela pour les cinq trous, le joueur poursuit en cliquant sur le bouton Done.

Chapitre 4

Jeux crbraux : Simon et dduction

161

valuer les dplacements du joueur


Lorsque le joueur clique sur le bouton Done, la fonction clickDone est appele. Elle dlgue ensuite lexcution la fonction calculateProgress :
// Le joueur clique sur le bouton DONE public function clickDone(event:MouseEvent) { calculateProgress(); }

La fonction calculateProgress soccupe de calculer dans quelle mesure la proposition du joueur correspond la solution. Les deux variables locales numCorrectSpot et numCorrectColor sont les principaux rsultats que nous cherchons calculer. Il est en fait trs facile de dterminer numCorrectSpot : nous parcourons en boucle chacun des Peg et dterminons si la couleur slectionne par le joueur correspond la solution. Si cest le cas, nous ajoutons 1 numCorrectSpot. Le calcul de numCorrectColor est dj plus complexe. Pour commencer, il faut ignorer tous les pions que lutilisateur a correctement placs pour se concentrer sur les pions incorrects, puis examiner les couleurs que le joueur a slectionnes et qui auraient pu aller autre part. Une solution astucieuse pour cela consiste tenir le registre de chacune des couleurs utilises par le joueur dans ces pions incorrects. En outre, tenez le registre des couleurs requises pour les pions incorrects. Nous ferons cela avec les tableaux solutionColorList et currentColorList. Chacun des lments dans ces tableaux correspondra une somme de chacune des couleurs trouves. Par exemple, si deux rouges (couleur 0), un vert (couleur 1) et un bleu (couleur 2) sont trouvs, le tableau rsultant sera [2,1,1,0,0]. 2+1+1=4. Puisquil y a cinq pions et que la somme fait quatre, nous devons avoir un pion correct et seuls quatre trous doivent tre rsolus. Ainsi, si [2,1,1,0,0] reprsente les couleurs utilises par le joueur dans les pions errons et [1,0,1,2,0] reprsente les couleurs requises dans ces emplacements, nous pouvons dterminer le nombre de couleurs correctes utilises aux mauvais emplacements en rcuprant simplement le nombre le plus petit des deux tableaux : [1,0,1,0,0]. Voyons cela couleur par couleur. Dans le premier tableau ([2,1,1,0,0]), le joueur place deux rouges. Mais le second tableau ([1,0,1,2,0]) montre que seul un rouge est requis. Le nombre minimal entre deux et un est un. Seul un rouge est hors de place. Le joueur a galement plac un vert. Mais le second tableau montre quaucun vert nest requis. Le plus petit nombre est donc zro. Le joueur a slectionn un bleu et un bleu est requis. En voil un autre dans le tableau. Le joueur a choisi zro jaune, mais deux sont requis. Le joueur a choisi zro violet et zro est requis. Voil un autre zro dans le tableau. Le plus petit est zro. Ainsi 1+0+1+0+0 = 2. Deux couleurs sont mal places. Le Tableau 4.2 prsente un autre aperu de ce calcul.

162

ActionScript 3.0 pour les jeux

Tableau 4.2 : Calcul des pions mal placs

Couleur
Rouge Vert Bleu Jaune Violet Total mal positionns

Choisie par lutilisateur


2 1 1 0 0

Correcte
1 0 1 2 0

Nombre de pions mal positionns


1 0 1 0 0 2

En plus de calculer le nombre total de pions corrects et de couleurs mal places, nous allons en proter pour dsactiver le mode bouton des pions en utilisant removeEventListener et en positionnant buttonMode false :
// Calcul du rsultat public function calculateProgress() { var numCorrectSpot:uint = 0; var numCorrectColor:uint = 0; var solutionColorList:Array = new Array(0,0,0,0,0); var currentColorList:Array = new Array(0,0,0,0,0); // Parcours en boucle des pions for(var i:uint=0;i<numPegs;i++) { // Ce pion est-il correct ? if (currentRow[i].color == solution[i]) { numCorrectSpot++; } else { // Pas de correspondance, mais enregistrer les couleurs pour le test suivant solutionColorList[solution[i]-1]++; currentColorList[currentRow[i].color-1]++; } // Dsactiver le mode bouton du pion currentRow[i].peg.removeEventListener(MouseEvent.CLICK,clickPeg); currentRow[i].peg.buttonMode = false; } // Obtenir le nombre correct de couleurs correctement positionnes for(i=0;i<numColors;i++) { numCorrectColor += Math.min(solutionColorList[i],currentColorList[i]); }

Chapitre 4

Jeux crbraux : Simon et dduction

163

Maintenant que nous connaissons le rsultat des tests, nous pouvons les afcher dans le champ texte qui contenait prcdemment les instructions :
// Afcher le rsultat currentText.text = Correct Spot: +numCorrectSpot+, Correct Color: +numCorrectColor;

Ensuite, nous souhaitons passer au turnNum et vrier si le joueur a trouv la solution. Si cest le cas, nous repassons le contrle la fonction gameOver. Par ailleurs, si le joueur a excd le nombre maximal de tentatives, nous passons le contrle la fonction gameLost. Si la partie nest pas termine, nous passons au tour suivant en appelant createPegRow :
turnNum++; if (numCorrectSpot == numPegs) { gameOver(); } else { if (turnNum == maxTries) { gameLost(); } else { createPegRow(); } } }

Fin de la partie
Si le joueur a trouv la solution, nous souhaitons lui indiquer que la partie est termine. Nous poursuivrons en crant une ligne de plus dans le jeu. Cette fois, il nest pas ncessaire dafcher les pions car la ligne prcdente que le joueur a complte contient maintenant la solution correspondante. La Figure 4.8 montre quoi ressemble lcran.

Indiquer que le joueur a gagn


La nouvelle ligne na besoin de contenir que le bouton et un nouveau champ texte. Le bouton sera reli de manire dclencher la fonction clearGame. Le champ texte suivant afchera "You Got It!" (trouv). Nous devons lajouter allDisplayObjects comme tout ce que nous crons dans le jeu :
// Le joueur a trouv la solution public function gameOver() { // Changer le bouton currentButton.y = turnNum*rowSpacing+vertOffset; currentButton.removeEventListener(MouseEvent.CLICK,clickDone); currentButton.addEventListener(MouseEvent.CLICK,clearGame);

164

ActionScript 3.0 pour les jeux

// Crer le message texte ct des pions et du bouton currentText = new TextField(); currentText.x = numPegs*pegSpacing+horizOffset+pegSpacing*2+currentButton.width; currentText.y = turnNum*rowSpacing+vertOffset; currentText.width = 300; currentText.text = "You got it!"; addChild(currentText); allDisplayObjects.push(currentText); }

Figure 4.8
La partie se termine lorsque le joueur trouve la solution.

Indiquer que le joueur a perdu


La fonction gameLost est analogue la fonction gameOver. Sa principale diffrence tient ce quelle doit crer une dernire ligne de pions an de rvler la solution au joueur qui donne sa langue au chat. La Figure 4.9 montre quoi pourrait ressembler lcran ce point. Ces nouveaux pions nont pas besoin dtre congurs comme des boutons. Ils doivent cependant tre congurs pour afcher la bonne couleur de pion.

Chapitre 4

Jeux crbraux : Simon et dduction

165

Figure 4.9
Le joueur a puis tous ses essais.

En outre, le bouton Done est modi an dappeler la fonction clearGame, comme dans gameOver. Un nouveau champ texte est cr, mais qui afche cette fois "You ran out of guesses" :
// Le joueur a atteint le nombre maximal de tours public function gameLost() { // Changer le bouton currentButton.y = turnNum*rowSpacing+vertOffset; currentButton.removeEventListener(MouseEvent.CLICK,clickDone); currentButton.addEventListener(MouseEvent.CLICK,clearGame); // Crer le message texte ct des pions et du bouton currentText = new TextField(); currentText.x = numPegs*pegSpacing+horizOffset+pegSpacing*2+currentButton.width; currentText.y = turnNum*rowSpacing+vertOffset; currentText.width = 300; currentText.text = "You ran out of guesses!"; addChild(currentText); allDisplayObjects.push(currentText); // Crer la ligne de pions nale pour afcher la rponse currentRow = new Array();

166

ActionScript 3.0 pour les jeux

for(var i:uint=0;i<numPegs;i++) { var newPeg:Peg = new Peg(); newPeg.x = i*pegSpacing+horizOffset; newPeg.y = turnNum*rowSpacing+vertOffset; newPeg.gotoAndStop(solution[i]+1); addChild(newPeg); allDisplayObjects.push(newPeg); } }

Lorsque la partie se termine, le bouton Done reste lcran dans la ligne nale. Sil clique dessus, le joueur est conduit lcran de n de partie du scnario principal, o il peut choisir de jouer nouveau. Avant de faire cela, nous devons cependant effacer tous les lments de jeu de la scne.

Effacer les lments du jeu


La suppression des objets dafchage est un processus plusieurs tapes que facilite grandement notre tableau allDisplayObjects. Chacun des objets dafchage que nous avons crs, quil sagisse dun clip, dun bouton ou dun champ texte, a t ajout ce tableau. Nous pouvons maintenant les supprimer en parcourant le tableau en boucle et en utilisant removeChild pour retirer lobjet de lcran :
// Supprimer tout pour aller lcran de n de partie public function clearGame(event:MouseEvent) { // Supprimer tous les objets dafchage for(var i in allDisplayObjects) { removeChild(allDisplayObjects[i]); }

Mme lcart de la scne, les objets existent toujours, en lattente dune commande addChild qui les replacerait lcran. Pour sen dbarrasser vritablement, nous devons supprimer toutes les rfrences ces objets. Nous faisons rfrence aux objets dafchage plusieurs endroits de notre code, dont le allDisplayObjects. Si nous le positionnons null, puis positionnons les variables currentText, currentButton et currentRow null galement, aucune des variables ne fait plus rfrence aucun de nos objets dafchage. Les objets sont ensuite supprims.

En ralit, lorsque vous supprimez toutes les rfrences un objet dafchage, vous le mettez disposition du "ramasse-miettes". Cela signie simplement que Flash peut supprimer ces objets de la mmoire tout moment. Comme il ny a plus de rfrence ces objets et aucun moyen de faire rfrence lun dentre eux si vous le souhaitez, vous pouvez pour votre part les considrer comme supprims. Flash ne se compliquera toutefois pas la vie les supprimer sur-lechamp ; il ne sy attellera que lorsquil aura quelques cycles processeur gaspiller pour cela.

Chapitre 4

Jeux crbraux : Simon et dduction

167

// Positionner toutes les rfrences dobjets dafchage null allDisplayObjects = null; currentText = null; currentButton = null; currentRow = null;

Pour nir, la fonction clearGame demande au scnario principal de se rendre limage gameover. Cest cet endroit que gure un bouton Play Again sur lequel le joueur peut cliquer. Tous les objets dafchage tant supprims, le jeu peut vritablement recommencer, avec de nouveaux objets dafchage :
// Demander au scnario principal davancer MovieClip(root).gotoAndStop("gameover"); }

La fonction clearGame est la fonction critique utilise pour crer un jeu dans le scnario principal qui peut tre effac et redmarr. Si on la compare au fonctionnement du jeu de Memory du Chapitre 3, le rsultat semble identique. Vous avez la certitude que, la deuxime fois que le joueur commence le jeu, il entame une partie entirement nouvelle, comme la premire fois. Lapproche utilise au Chapitre 3 est cependant un peu plus simple mettre en place parce que tous les objets dafchage sont instantanment et aisment supprims lorsque le clip disparat dans limage de n de partie.

Modier le jeu
Comme pour le jeu de Simon, lune des meilleures variantes du jeu de dduction consiste intervenir sur les graphismes du jeu. Vous pouvez utiliser toutes sortes dobjets pour les pions et mme crer une mise en scne pour les situer dans un contexte particulier. Par exemple, vous pouvez proposer au joueur de tenter douvrir un coffre-fort ou de dverrouiller une porte dans un jeu daventure. Notre utilisation des constantes permet aisment de proposer un nombre de tentatives plus lev dans ce jeu, de rduire ou daugmenter le nombre de pions ou de couleurs, etc. Si vous souhaitez proposer un plus grand nombre dessais, vous aurez sans doute besoin dagrandir la scne ou de rduire lespacement des lignes. Pour naliser ce jeu, jutiliserais dabord un objet TextFormat an de mettre en forme le message texte. Ensuite, jajouterais des instructions dans lcran dintroduction. Un bouton Restart (redmarre) dans limage du jeu pourrait aussi permettre au joueur de recommencer tout moment. Il pourrait tout simplement appeler clearGame an de supprimer tous les lments cran et conduire limage de n de partie. Pour rendre ce jeu plus proche du jeu de socit Mastermind, vous pourriez remplacer le message texte par des pions blancs et noirs. Lun dsignerait un pion correctement plac, lautre, une couleur correcte situe au mauvais emplacement. Noir, noir, blanc signierait ainsi deux pions corrects et une couleur correcte au mauvais emplacement.

5
Animation de jeu : jeux de tir et de rebond
Au sommaire de ce chapitre :

Animation de jeu Air Raid Casse-brique

170

ActionScript 3.0 pour les jeux

Jusqu prsent, nous navons cr que des jeux dont les lments restaient positionns un mme emplacement. Ces lments changaient et pouvaient tre modis par les actions de lutilisateur, mais ils ne se dplaaient pas. Dans ce chapitre, nous allons travailler avec des lments de jeu anims. Certains seront contrls par le joueur, dautres se dplaceront de manire autonome. Aprs avoir examin certains exemples danimation, nous crerons deux jeux. Le premier sappelle Air Raid, un jeu simple dans lequel vous contrlez un canon de DCA et tentez de toucher les avions qui traversent le ciel au-dessus de votre tte. Le second est un jeu de casse-brique o vous contrlez une raquette et renvoyez une balle en direction dun mur de briques qui disparaissent quand la balle les touche.

Animation de jeu
Codes sources http://ashgameu.com A3GPU05_Animation.zip Au Chapitre 2, nous avons examin deux types danimations principaux : les animations images et les animations temporelles. Nous nutiliserons dans ce chapitre que des animations temporelles, parce quelles sont plus ables et offrent des rsultats de meilleure apparence.

Animation temporelle
Lide de base de lanimation temporelle est de dplacer les objets cadence homogne, quelles que soient les performances du lecteur Flash. Un unique mouvement, que nous appellerons une tape, se produit chaque image. Une cadence dimages de 12 ips implique donc 12 tapes par seconde. Bien que les tapes danimation se produisent chaque image, il ne sagit pas dune animation dimage car nous dterminons la taille de chaque tape de manire temporelle. chaque tape, nous calculons le temps coul depuis ltape prcdente. Nous dplaons les lments du jeu en fonction de cette diffrence temporelle. Si la premire tape prend 84 millisecondes et la seconde, 90, nous dplaons les objets lgrement plus loin la seconde tape qu la premire. La Figure 5.1 prsente un diagramme de trois images du mouvement avec une animation temporelle.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

171

Figure 5.1
Lobjet avance de 400 pixels par seconde quelle que soit la cadence dimages.
Image 2

Image 3 Distance : 400 Temps : 1000 ms

Distance : 297 Temps : 740 ms Image 1 Distance : 127 Temps : 317 ms Image 0 Distance : 0 Tem s Temps : 0 ms

Lobjet la Figure 5.1 est suppos se dplacer de 400 pixels chaque seconde. Lanimation est congure pour une cadence dimages trs faible de 4 ips. Pour compliquer les choses, supposons que lordinateur manque totalement de ractivit, par exemple parce quil est occup par dautres applications ou une activit rseau. Il nest pas mme de proposer une cadence dimages constante ni mme de gnrer quatre images par seconde.

Lors du dveloppement danimations temporelles, il est judicieux de modier frquemment la cadence dimages de votre animation pendant vos tests. En gnral, jalterne entre 12 et 60 images par seconde. Mon but est dobtenir un jeu qui possde une excellente apparence 60 ips mais reste tout aussi jouable 12 ips. Si je relie accidentellement un lment de jeu la cadence dimages au lieu de la mesure temporelle, je remarque ainsi rapidement une considrable diffrence dans le jeu entre les deux cadences dimages.

Lorsque la premire image passe et quun vnement ENTER_FRAME dclenche la fonction danimation dans notre code, 317 millisecondes se sont coules. 4 images par seconde, seules 250 millisecondes auraient d scouler. Jusque-l, la cadence dimages est dj la trane. Mais, en utilisant la mesure temporelle de 317 millisecondes, nous pouvons calculer que lobjet aurait d se dplacer dune distance de 127 pixels. Cela fait 400 pixels par seconde multiplis par 0,317 seconde. la cadence dimages, lobjet se trouve ainsi exactement o il doit tre. La seconde image prend plus de temps encore, pour un total de 423 millisecondes supplmentaires. Voil en tout 740 millisecondes, ce qui place lobjet 297 pixels de distance.

172

ActionScript 3.0 pour les jeux

Ensuite, dans la dernire image de lexemple, 260 millisecondes supplmentaires scoulent. Cela nous porte un total exact de 1 000 millisecondes. La distance est donc de 400. Aprs 1 seconde, lobjet sest donc dplac de 400 pixels, en dpit du fait que lanimation a produit une cadence dimages irrgulire et nest pas parvenue gnrer 4 images par seconde. Si nous avions simplement fait avancer lobjet de 100 pixels par image, il se serait maintenant dplac de 300 pixels, nayant eu que 3 images pour avancer. Ce rsultat pourrait tre diffrent sur un autre ordinateur ou un autre moment sur le mme ordinateur, lorsque les performances seraient sufsantes pour produire 4 images par seconde.

Programmer des animations temporelles


Lastuce pour programmer des animations temporelles consiste surveiller prcisment le temps coul. En examinant la fonction getTimer, vous pouvez obtenir le nombre de millisecondes depuis que lanimation a commenc. La valeur brute de getTimer nest pas intressante en elle-mme. Ce qui compte, cest la diffrence temporelle entre les images. Par exemple, il peut falloir 567 millisecondes pour que votre animation sinitialise et place les lments lcran. Ainsi, la premire image se produit 567 et la seconde, 629. La diffrence est de 62 millisecondes : cest cette mesure qui nous permet de dterminer la distance quun objet doit avoir parcouru entre les images. Lanimation AnimationTest.a contient un clip de cercle simple qui illustre le principe de lanimation temporelle. Lanimation utilise AnimationTest.as comme script principal et AnimatedObject.as comme classe du clip. La classe AnimatedObject possde une fonction constructeur qui accepte des paramtres. Cela signie que, lorsque vous crez un nouveau AnimatedObject, vous devez passer des paramtres, comme ceci :
var myAnimatedObject:AnimatedObject = new AnimatedObject(100,150,5,-8);

Les quatre paramtres reprsentent lemplacement horizontal et vertical, puis la vitesse horizontale et verticale du clip. Voici la dclaration de classe, les dclarations de variable et la fonction AnimatedObject. Vous remarquerez les quatre paramtres, dnis simplement sous les noms x, y, dx, dy :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer; public class AnimatedObject extends MovieClip { private var speedX, speedY:Number; // Vitesse actuelle en pixels par seconde private var lastTime:int; // Mmoriser le temps de la dernire image

Chapitre 5

Animation de jeu : jeux de tir et de rebond

173

public function AnimatedObject(x,y,dx,dy) { // Dnir emplacement et vitesse this.x = x; this.y = y; speedX = dx; speedY = dy; lastTime = getTimer(); // Dplacer chaque image addEventListener(Event.ENTER_FRAME, moveObject); }

Lusage de dx et de dy pour le stockage de la "diffrence sur laxe x" et de la "diffrence sur laxe y" est une pratique assez courante. Dans ce chapitre et les suivants, nous utiliserons ces deux noms de variable assez souvent.

La fonction prend quatre paramtres et les applique. Les deux premiers sont utiliss pour dnir lemplacement du clip. Les deux autres sont stocks dans speedX et speedY.
addEventListener

Ensuite, la variable lastTime est initialise avec la valeur courante de getTimer(). Pour nir, permettra la fonction moveObject de sexcuter chaque image. La fonction moveObject calcule dabord le temps coul, puis lajoute lastTime. La valeur de est ensuite utilise pour calculer le dplacement.

timePassed

En ajoutant timePassed lastTime, vous vous assurez quaucun temps nest perdu dans lanimation. Si au lieu de cela vous positionnez lastTime getTimer() chaque tape de lanimation, vous risquez de perdre de petites tranches de temps entre le moment o timePassed est calcul et celui o lastTime se voit attribuer sa valeur.

Comme timePassed sexprime en millimes de seconde (millisecondes), nous le divisons par 1 000 pour obtenir la quantit multiplier par speedX et speedY. Par exemple, si timePassed vaut 100, cela quivaut 100/1000 ou 0,1 seconde. Si speedX vaut 23, lobjet se dplace de 23 0,1 ou de 2,3 pixels vers la droite :
// Dplacer en fonction de la vitesse public function moveObject(event:Event) { // Calcul du temps coul var timePassed:int = getTimer() - lastTime; lastTime += timePassed;

174

ActionScript 3.0 pour les jeux

// Mettre jour la position selon la vitesse et le temps this.x += speedX*timePassed/1000; this.y += speedY*timePassed/1000; } } }

Lun des moyens simples de tester cette classe AnimatedObject consiste utiliser une classe danimation principale comme ceci :
package { import ash.display.*; public class AnimationTest extends MovieClip {

public function AnimationTest() { var a:AnimatedObject = new AnimatedObject(100,150,5,-8); addChild(a); } } }

Ce code cre un clip 100, 150 qui se dplace une vitesse de 5 horizontalement et de 8 verticalement. La classe AnimatedObject nous a donc en fait permis dajouter un objet mouvant la scne laide de deux simples lignes de code. Un meilleur test de la classe AnimatedObject consiste ajouter plusieurs objets et les faire bouger au hasard dans toutes les directions. Voici une version de la classe principale qui se charge de cette tche :
package { import ash.display.*; public class AnimationTest extends MovieClip {

public function AnimationTest() { // Crer 50 objets positionns au hasard avec des vitesses alatoires for(var i:uint=0;i<50;i++) { var a:AnimatedObject = new AnimatedObject(Math.random()*550, Math.random()*400, getRandomSpeed(), getRandomSpeed()); addChild(a); } }

Chapitre 5

Animation de jeu : jeux de tir et de rebond

175

// Obtenir une vitesse comprise entre 70 et 100, positive ou ngative public function getRandomSpeed() { var speed:Number = Math.random()*70+30; if (Math.random() > .5) speed *= -1; return speed; } } }

Dans cette version de la classe, nous crons un nouvel AnimatedObject avec un emplacement et une vitesse alatoires. La position alatoire est cre en utilisant simplement Math.random. Pour la vitesse alatoire, jai cependant utilis une fonction spare qui retourne une valeur positive ou ngative comprise entre 70 et 100. Ce code sert viter que des objets se dplacent une vitesse proche de 0. La Figure 5.2 prsente cette animation lorsquelle sexcute la premire fois. Les objets sont parpills lcran.
Figure 5.2
Lanimation AnimationTest place cinquante objets alatoires sur la scne.

Vous pouvez vous amuser un peu avec cette classe an de crer des effets intressants. Par exemple, si tous les objets commencent au mme emplacement, vous obtiendrez un effet dexplosion. Vous pouvez galement ajuster le nombre dobjets cr et la cadence dimages de lanimation an de voir comment votre ordinateur parvient grer une forte charge danimation. prsent, utilisons cette technique dans un jeu qui combine trois diffrents types dobjets anims.

176

ActionScript 3.0 pour les jeux

Air Raid
Codes sources http://ashgameu.com A3GPU05_AirRaid.zip Air Raid est analogue certains anciens jeux darcade. La plupart dentre eux sinspiraient de scnes navales o le joueur commandait un sous-marin et tirait sur des bateaux qui striaient la surface de leau. Le plus ancien a probablement t Sea Wolf. Il proposait une vue subjective dans un priscope dune scne o vous deviez tirer sur des cibles. Il sagissait en fait dune version en jeu vido des jeux lectroniques Periscope, Sea Raider et Sea Devil.

Ces jeux de tir navals taient probablement les plus simples raliser aux premires heures de la programmation informatique, car les bateaux et les torpilles ont lintrt de se dplacer plus lentement que les avions et les canons anti-DCA.

Dans notre jeu, le joueur dplace une tourelle anti-DCA en bas de lcran laide des touches ches du clavier. Il tire vers le haut en direction des avions qui dlent et tente den atteindre autant que possible avec un quantit de munitions limite.

Conguration de lanimation et mthode


Loccasion est toute trouve de crer maintenant un jeu qui utilise plusieurs classes. Nous avons pour lessentiel trois diffrents types dobjets : des avions, une tourelle-canon et des balles. En crant une unique classe pour chacun de ces objets, nous pouvons crer le jeu tape par tape puis spcialiser le code pour chacun. Il nous faut trois clips pour accompagner les trois classes. Les clips AAGun et Bullet feront une image chacun. Le clip Airplane en contiendra plusieurs, avec un dessin davion diffrent dans chacune. La Figure 5.3 prsente ce clip. La sixime image la n contient un graphisme dexplosion que nous utiliserons lorsquun avion est touch. En plus des trois chiers de classe AAGun.as, Airplane.as et Bullet.as, il nous faut un chier de classe principale pour lanimation, AirRaid.as.

Avions volants
La classe ActionScript pour les avions ne sera pas trs diffrente quant sa structure de la classe AnimatedObject, vue prcdemment dans ce chapitre. Elle acceptera des paramtres dans la fonction constructeur pour dterminer la position de dpart et la vitesse de lavion. Elle utilisera

Chapitre 5

Animation de jeu : jeux de tir et de rebond

177

la mesure temporelle pour dterminer la diffrence entre les images. Elle utilisera un vnement ENTER_FRAME pour faire avancer lanimation.
Figure 5.3
Le clip Airplane contient cinq avions diffrents situs chacun dans une image.

Dclaration de classe et de variables


Le code qui suit correspond la dnition de la classe et des variables que la classe utilisera. Comme lavion ne volera quhorizontalement, il naura besoin que de dx, la vitesse horizontale :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer; public class Airplane extends MovieClip { private var dx:Number; // Vitesse et direction private var lastTime:int; // Temps danimation

La fonction constructeur
La fonction constructeur prendra trois paramtres : side (ct), speed (vitesse) et altitude. Le paramtre side sera soit "left" (gauche) soit "right" (droite) selon le ct de lcran do provient lavion. Le paramtre speed sera utilis pour dnir la variable dx. Si lavion vient de la droite de lcran, nous placerons automatiquement un signe moins devant la vitesse. Un avion progressant de gauche droite une vitesse de 80 aura donc une vitesse dx de 80. linverse, un avion progressant de droite gauche avec une vitesse de 80 aura une vitesse dx de 80.

178

ActionScript 3.0 pour les jeux

Laltitude nest quun nom un peu pompeux pour dsigner la position verticale de lavion. 0 correspondra au haut de lcran, 50 50 plus bas, etc. En plus de dnir lemplacement et dx, nous aurons galement besoin de renverser lavion an quil soriente dans la bonne direction. Cest ce que nous faisons en utilisant la proprit scaleX du clip. La valeur 1 renverse limage :
public function Airplane(side:String, speed:Number, altitude:Number) { if (side == left) { this.x = -50; // Dmarrer gauche dx = speed; // Voler de gauche droite this.scaleX = -1; // Renverser } else if (side == "right") { this.x = 600; // Dmarrer droite dx = -speed; // Voler de droite gauche this.scaleX = 1; // Ne pas renverser } this.y = altitude; // Position verticale // Congurer lanimation addEventListener(Event.ENTER_FRAME,movePlane); lastTime = getTimer(); }

La fonction Airplane se termine en positionnant le minuteur vnementiel et en initialisant la proprit lastTime comme nous lavons fait dans la classe AnimatedObject.

Dplacer lavion
La fonction movePlane calcule dabord le temps coul, puis dplace lavion en fonction du temps coul et de sa vitesse. Ensuite, elle vrie si lavion a termin son parcours de lcran. Si cest le cas, nous appelons la fonction deletePlane :
public function movePlane(event:Event) { // Calcul du temps coul var timePassed:int = getTimer()-lastTime; lastTime += timePassed; // Dplacer lavion this.x += dx*timePassed/1000; // Vrier sil est sorti de lcran if ((dx < 0) && (x < -50)) { deletePlane();

Chapitre 5

Animation de jeu : jeux de tir et de rebond

179

} else if ((dx > 0) && (x > 600)) { deletePlane(); } }

Supprimer les avions


La fonction deletePlane est une sorte de fonction autonettoyante, comme le montre le bloc de code suivant. Elle supprime lavion de la scne avec une commande removeChild. Elle supprime ensuite lcouteur de la fonction movePlane.

Il est toujours judicieux dinclure une fonction avec une classe qui supprime lobjet. La classe peut ainsi grer la suppression de ses propres couteurs et de toutes les commandes requises pour nettoyer les autres rfrences elle-mme.

Pour que lavion disparaisse compltement, nous devons indiquer la classe principale quil a termin son parcours. Nous commenons donc ici par appeler removePlane, une fonction de la classe du scnario principal. Cest le scnario principal qui a cr lavion au dpart et qui, se faisant, le stocke dans un tableau. La fonction removePlane, laquelle nous viendrons dans un instant, supprime lavion du tableau :
// Supprimer lavion de la scne et de la liste des avions public function deletePlane() { MovieClip(parent).removePlane(this); parent.removeChild(this); removeEventListener(Event.ENTER_FRAME,movePlane); }

Une fois que toutes les rfrences un objet ont t rinitialises ou supprimes, le lecteur Flash rclamera la mmoire utilise par lobjet.

Il y aura une seconde fonction pour supprimer lavion. Celle-ci sapparente deletePlane, mais elle grera le cas o lavion est touch par le tir du joueur. Elle interrompra aussi lvnement dimage et indiquera la classe principale de renvoyer lavion du tableau. Au lieu de supprimer lenfant de la scne, elle demandera cependant simplement au clip daller limage intitule "explode" et de poursuivre la lecture cet endroit.

180

ActionScript 3.0 pour les jeux

Le clip contient un graphisme dexplosion qui dmarre limage 6. Il se poursuit sur quelques images, puis atteint une image contenant une commande parent.removeChild(this); et une commande stop();. Ce code nalise la suppression de lavion, aprs un bref aperu de lexplosion pour le plaisir des yeux du joueur :
// Avion touch, afcher lexplosion public function planeHit() { removeEventListener(Event.ENTER_FRAME,movePlane); MovieClip(parent).removePlane(this); gotoAndPlay(explode); }

Vous pouvez faire durer lexplosion plus longtemps en rallongeant le nombre dimages entre limage "explosion" et la dernire image contenant le script. De la mme manire, vous pouvez placer une explosion anime dans ces images, sans quil soit ncessaire dajouter dautre code ActionScript.

Tester la classe Airplane


Cest le scnario principal qui se charge de crer les avions, mais galement de les supprimer. Nous crerons cette classe par la suite. Si nous souhaitons tester la classe Airplane, nous pouvons le faire avec une classe principale simple comme la suivante :
package { import ash.display.*; public class AirRaid extends MovieClip { public function AirRaid() { var a:Airplane = new Airplane("right",170,30); addChild(a); } } }

Si vous effectuez un test, il est judicieux dessayer diffrentes valeurs pour les paramtres. Par exemple, essayez "left" avec une vitesse de 30. Testez autant de valeurs quil le faut pour vous assurer que la classe Airplane fonctionne avant de passer la classe suivante.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

181

Tourelle mouvante
La classe qui contrle le canon anti-DCA (voir Figure 5.4) est un peu diffrente en ceci que le mouvement est contrl par les actions de lutilisateur. Nous pourrions utiliser la souris pour dnir la position de la tourelle, mais le jeu en deviendrait presque trop facile. Il sufrait dun mouvement de poignet pour passer dun ct lautre de lcran.
Figure 5.4
La tourelle anti-DCA est positionne de manire que son point dalignement se trouve au bout du canon.

Au lieu de cela, nous utiliserons donc les touches ches de gauche et de droite pour dplacer le canon. Comme les avions, nous ferons avancer la tourelle une vitesse dtermine vers la gauche ou la droite en fonction de la touche enfonce. Les touches ches seront en fait gres par la classe de lanimation principale et non par la classe AAGun. En effet, le clavier envoie par dfaut des vnements la scne et non un clip particulier. La classe de lanimation principale aura deux variables, leftArrow et rightArrow, qui seront positionnes true ou false. La classe AAGun examine simplement ces variables pour voir dans quelle direction dplacer le canon si celui-ci doit bouger :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer; public class AAGun extends MovieClip { static const speed:Number = 150.0; private var lastTime:int; // Temps danimation

182

ActionScript 3.0 pour les jeux

public function AAGun() { // Emplacement initial du canon this.x = 275; this.y = 340; // Mouvement addEventListener(Event.ENTER_FRAME,moveGun); }

Maintenant que lemplacement du canon a t dni et que lcouteur a t ajout, la fonction moveGun sexcute chaque image an de grer les ventuels mouvements :
public function moveGun(event:Event) { // Calculer la diffrence temporelle var timePassed:int = getTimer()-lastTime; lastTime += timePassed;

// Position actuelle var newx = this.x;

// Dplacement vers la gauche if (MovieClip(parent).leftArrow) { newx -= speed*timePassed/1000; }

// Dplacement vers la droite if (MovieClip(parent).rightArrow) { newx += speed*timePassed/1000; }

// Vrication des limites if (newx < 10) newx = 10; if (newx > 540) newx = 540;

// Repositionnement this.x = newx; } } }

Chapitre 5

Animation de jeu : jeux de tir et de rebond

183

En plus de dplacer le canon, vous remarquerez sous le commentaire "Vrication des limites" deux lignes qui soccupent de vrier le nouvel emplacement du canon an de sassurer quil ne sort pas sur les cts. Il vaut maintenant la peine de voir comment la classe principale gre les appuis sur les touches. Dans la fonction constructeur, deux appels addEventListener congurent ce dispositif :
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);

Les deux fonctions qui sont appeles dnissent les valeurs boolennes de leftArrow et rightArrow comme il se doit :
// Touche enfonce public function keyDownFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = true; } else if (event.keyCode == 39) { rightArrow = true; } }

La valeur de event.keyCode est un nombre qui correspond une touche du clavier. La touche 37 est la touche che de gauche et la touche 39, celle de droite. Les touches 38 et 40 sont les touches ches du haut et du bas, que nous utiliserons dans dautres chapitres.

// Touche relche public function keyUpFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = false; } else if (event.keyCode == 39) { rightArrow = false; } }

Le mouvement du canon est donc produit par un effort conjoint de la classe principale et de la classe AAGun. La classe principale gre lentre clavier et la classe AAGun soccupe du mouvement.

184

ActionScript 3.0 pour les jeux

Il reste une dernire partie dans la classe AAGun qui correspond la fonction deleteGun. Nous ne lutiliserons que lorsquil sera temps de supprimer le canon de la scne an de passer limage de n de partie (gameover) :
// Supprimer de lcran et supprimer les vnements public function deleteGun() { parent.removeChild(this); removeEventListener(Event.ENTER_FRAME,moveGun); }

Il est important de toujours penser utiliser removeEventListener pour se dbarrasser des vnements dimage et de minuteur. Sans cela, ces vnements continueront se produire mme aprs que vous aurez pens avoir supprim lobjet parent.

Les balles tires en lair


Les balles sont probablement les plus simples des objets mouvants. Dans ce jeu, le graphisme qui les reprsente est en fait une grappe de balles (voir Figure 5.5).
Figure 5.5
Le point dalignement du groupe de balles se trouve en bas, de sorte quen dmarrant au niveau du canon elles se trouvent juste au-dessus des canons.

Elles commenceront lemplacement du canon et se dplaceront vers le haut jusqu atteindre la partie suprieure de lcran. Nous avons dj vu dans les classes Airplane et AAGun tout le code de la classe Bullet.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

185

La fonction constructeur accepte une valeur x et une valeur y de dpart, ainsi quune vitesse. La vitesse sera applique verticalement et non horizontalement comme pour les avions :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer;

public class Bullet extends MovieClip { private var dy:Number; // Vitesse verticale private var lastTime:int;

public function Bullet(x,y:Number, speed: Number) { // Dnition de la position de dpart this.x = x; this.y = y; // Rcuprer la vitesse dy = speed; // Congurer lanimation lastTime = getTimer(); addEventListener(Event.ENTER_FRAME,moveBullet); }

public function moveBullet(event:Event) { // Calculer le temps coul var timePassed:int = getTimer()-lastTime; lastTime += timePassed;

// Dplacer la balle this.y += dy*timePassed/1000;

// La balle a pass le haut de lcran if (this.y < 0) { deleteBullet(); } }

186

ActionScript 3.0 pour les jeux

La fonction removeBullet, comme la fonction removePlane, se trouvera dans la classe principale. Elle aura charge de supprimer les balles lorsquelles atteignent le haut de lcran :
// Supprimer la balle de la scne et de la liste des balles public function deleteBullet() { MovieClip(parent).removeBullet(this); parent.removeChild(this); removeEventListener(Event.ENTER_FRAME,moveBullet); } } }

Pour lancer une balle, le joueur appuie sur la barre despace. Nous devons modier keyDownFunction dans la classe AirRaid de manire accepter les espaces et les passer une fonction qui gre la cration dune nouvelle balle (Bullet) :
// Touche enfonce public function keyDownFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = true; } else if (event.keyCode == 39) { rightArrow = true; } else if (event.keyCode == 32) { reBullet(); } }

Le code de touche 32 dsigne la barre despace. Pour retrouver les correspondances entre les codes et les touches, consultez laide de Flash en tapant "Touches du clavier et valeurs de code" dans le champ Rechercher.

La fonction reBullet passe lemplacement du canon et une vitesse la nouvelle Bullet. Elle ajoute aussi la nouvelle Bullet au tableau bullets an de pouvoir en tenir le registre pour la dtection de collision ultrieure :
public function reBullet() { var b:Bullet = new Bullet(aagun.x,aagun.y,-300); addChild(b); bullets.push(b); }

Chapitre 5

Animation de jeu : jeux de tir et de rebond

187

Maintenant que nous avons des avions, un canon anti-DCA et des objets Bullet, il est temps de combiner tous ces lments avec la classe principale AirRaid.

La classe du jeu
La classe AirRaid contient toute la logique du jeu. Cest cet endroit que nous allons crer les objets de jeu initiaux, vrier les collisions et grer le score. Une fois que la partie sera lance, le jeu ressemblera lcran prsent la Figure 5.6.
Figure 5.6
Le jeu Air Raid avec un canon anti-DCA, une balle en mouvement et deux avions en vol.

Dclaration de classe
La classe requiert les classes standard que nous avons utilises jusque-l, et notamment un accs getTimer et aux champs texte :
package { import ash.display.*; import ash.events.*; import ash.utils.Timer; import ash.text.TextField;

188

ActionScript 3.0 pour les jeux

Parmi les variables dont nous avons besoin pour la classe gurent des rfrences au canon et les tableaux qui rfrencent les avions et les balles que nous avons crs :
public class AirRaid extends MovieClip { private var aagun:AAGun; private var airplanes:Array; private var bullets:Array;

Les deux variables suivantes sont des valeurs true ou false qui permettent de surveiller lusage que fait le joueur des touches ches de gauche et de droite. Elles doivent tre rendues publiques parce que lobjet aagun y accdera an de dterminer sil faut se dplacer :
public var leftArrow, rightArrow:Boolean;

Vous pouvez inclure plus dune variable dans une ligne de dnition de variable. Cette technique fonctionne bien lorsque vous avez de petits groupes de variables lies et du mme type. Les variables leftArrow et rightArrow sont ici un bon exemple de ce type dapplication.

La variable suivante, nextPlane, sera un Timer. Nous lutiliserons pour dterminer quel moment lavion suivant doit apparatre :
private var nextPlane:Timer;

Pour nir, nous avons deux variables de mmorisation du score. La premire tient le registre du nombre de coups tirs et la seconde, du nombre davions touchs par le joueur :
private var shotsLeft:int; private var shotsHit:int;

Il nexiste pas de fonction constructeur AirRaid pour ce jeu car celui-ci ne commence pas la premire image. Au lieu de cela, nous en aurons une appele startAirRaid qui sera appele depuis le scnario principal dans limage play. La fonction commence par dnir le nombre de coups restants en le xant 20 et par mettre le score zro :
public function startAirRaid() { // Initialisation du score shotsLeft = 20; shotsHit = 0; showGameScore();

Ensuite, le canon anti-DCA est cr et ajout la scne sous le nom doccurrence aagun :
// Cration du canon aagun = new AAGun(); addChild(aagun);

Chapitre 5

Animation de jeu : jeux de tir et de rebond

189

Nous devons galement crer les tableaux qui contiendront les balles et les avions :
// Cration des tableaux dobjets airplanes = new Array(); bullets = new Array();

Nous avons besoin de deux couteurs pour savoir quelle touche che a t enfonce, lun pour les vnements dappui sur les touches et lautre pour les vnements de relchement des touches :
// couter le clavier stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);

Nous avons besoin dun couteur vnementiel ENTER_FRAME pour dclencher la fonction checkForHits. Il sagira de la trs importante dtection de collision entre les balles et les avions :
// Rechercher les collisions addEventListener(Event.ENTER_FRAME,checkForHits);

Nous devons maintenant lancer le jeu en plaant des avions en lair. Cest le rle de la fonction setNextPlane, que nous examinerons sous peu :
// Faire voler des avions setNextPlane(); }

Crer un nouvel avion


Il faudra crer priodiquement de nouveaux avions, des instants plus ou moins alatoires. Pour cela, nous utiliserons un Timer et dclencherons sous peu un appel la fonction newPlane. La fonction setNextPlane crera le Timer avec un seul vnement et le congurera pour 1 2 secondes de dlai :
public function setNextPlane() { nextPlane = new Timer(1000+Math.random()*1000,1); nextPlane.addEventListener(TimerEvent.TIMER_COMPLETE,newPlane); nextPlane.start(); }

Lorsque le Timer expire, il appelle newPlane an de crer un nouvel avion et de le mettre en piste. Les trois paramtres de lobjet Airplane sont calculs alatoirement avec plusieurs rsultats de fonction Math. random(). Ensuite, lavion est cr et ajout la scne. Il est galement ajout au tableau airplanes. Pour nir, la fonction setNextPlane est appele de nouveau an de planier lavion suivant :
public function newPlane(event:TimerEvent) { // Ct, vitesse et altitude alatoires if (Math.random() > .5) { var side:String = left; } else {

190

ActionScript 3.0 pour les jeux

side = right; } var altitude:Number = Math.random()*50+20; var speed:Number = Math.random()*150+150;

// Crer un avion var p:Airplane = new Airplane(side,speed,altitude); addChild(p); airplanes.push(p);

// Dnir le temps pour lavion suivant setNextPlane(); }

Dtection de collision
La fonction la plus intressante de tout le jeu est la fonction checkForHits. Elle examine toutes les balles et tous les avions an de dterminer si lun dentre eux entre en collision.

Vous remarquerez que nous parcourons les tableaux en boucle reculons. Nous procdons ainsi pour ne pas nous emmler les pinceaux lorsque nous supprimons un lment dun tableau. Si nous progressions vers lavant, nous pourrions supprimer llment 3 du tableau, ce qui ferait de lancien lment 4 le nouvel lment 3. Ds lors, en avanant pour rechercher llment 4, nous sauterions un lment.

Nous utiliserons hitTestObject pour voir si les rectangles dencadrement des deux clips se chevauchent. Si cest le cas, nous raliserons plusieurs choses. Tout dabord, nous appellerons planeHit, qui entamera la destruction de lavion. Ensuite, nous supprimerons la balle. Nous augmenterons la somme des avions touchs et rafcherons le code du jeu. Enn, nous cesserons dexaminer les collisions pour cet avion et passerons la balle suivante dans la liste :
// Vrication des collisions public function checkForHits(event:Event) { for(var bulletNum:int=bullets.length-1;bulletNum>=0;bulletNum--){ for (var airplaneNum:int=airplanes.length-1;airplaneNum>=0;airplaneNum--) { if (bullets[bulletNum].hitTestObject(airplanes[airplaneNum])) { airplanes[airplaneNum].planeHit(); bullets[bulletNum].deleteBullet(); shotsHit++; showGameScore();

Chapitre 5

Animation de jeu : jeux de tir et de rebond

191

break; } } } if ((shotsLeft == 0) && (bullets.length == 0)) { endGame(); } }

la n de la fonction, nous vrierons si la partie est termine. Cest le cas lorsquil ne reste plus de munitions et que la dernire balle a quitt lcran ou a touch un avion.

Gestion de lentre clavier


Les deux fonctions suivantes grent les appuis sur les touches. Nous les avons rencontres toutes les deux auparavant :
// Touche enfonce public function keyDownFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = true; } else if (event.keyCode == 39) { rightArrow = true; } else if (event.keyCode == 32) { reBullet(); } } // Touche relche public function keyUpFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = false; } else if (event.keyCode == 39) { rightArrow = false; } }

Pour crer une nouvelle balle lorsque le joueur appuie sur la barre despace, nous crons simplement lobjet et lalimentons en lui fournissant lemplacement du canon et la vitesse de la balle (dans le cas prsent, 300 pixels par seconde).

192

ActionScript 3.0 pour les jeux

Nous ajoutons la balle au tableau bullets et soustrayons une unit shotsLeft. Nous mettrons galement jour le score. Vous remarquerez quavant que quoi que ce soit ne se passe nous vrions shotsLeft an de nous assurer que le joueur possde encore des munitions tirer. Cette vrication vite que le joueur ne rcupre quelques balles supplmentaires la n du jeu :
// Nouvelle balle cre public function reBullet() { if (shotsLeft <= 0) return; var b:Bullet = new Bullet(aagun.x,aagun.y,-300); addChild(b); bullets.push(b); shotsLeft--; showGameScore(); }

Autres fonctions
Nous avons maintenant appel showGameScore plusieurs fois. Cette petite fonction place simplement shotsHit et shotsLeft dans des champs texte sur la scne. Il sagit non pas de champs texte que nous avons crs dans le code mais de champs que jai placs manuellement dans la scne de lanimation dexemple. Je ne souhaitais pas encombrer cet exemple avec du code TextField et TextFormat :
public function showGameScore() { showScore.text = String("Score: "+shotsHit); showShots.text = String("Shots Left: "+shotsLeft); }

Si je nai pas cr les champs texte dans le code, jai cependant besoin de linstruction import ash.text.TextField; au dbut de la classe. Cette bibliothque est ncessaire non seulement pour crer les champs texte, mais galement pour y accder.

Les deux fonctions suivantes suppriment simplement un lment dun tableau. La boucle forin est utilise pour parcourir le tableau et la commande splice, pour supprimer llment une fois quil est trouv. La commande break est utilise pour quitter la boucle une fois la correspondance trouve. Nous avons besoin dune fonction pour supprimer un avion du tableau airplanes et dune autre pour supprimer une balle du tableau bullets :
// Retirer un avion du tableau public function removePlane(plane:Airplane) { for(var i in airplanes) {

Chapitre 5

Animation de jeu : jeux de tir et de rebond

193

if (airplanes[i] == plane) { airplanes.splice(i,1); break; } } } // Retirer une balle du tableau public function removeBullet(bullet:Bullet) { for(var i in bullets) { if (bullets[i] == bullet) { bullets.splice(i,1); break; } } }

Nous pourrions utiliser une unique fonction en lieu et place de removePlane et de removeBullet. Cette unique fonction se verrait passer la fois le tableau et llment trouver. En utilisant des fonctions spares, nous prenons des dispositions en prvision du dveloppement futur du jeu, o la suppression des avions et des balles pourrait avoir dautres effets. Par exemple, la suppression dun avion pourrait tre le signal pour appeler setNewPlane au lieu que cette opration se produise juste aprs quun avion eut t cr.

Nettoyage aprs la partie


Lorsquune partie se termine, il reste des lments de jeu lcran. Nous savons que toutes les balles sont parties parce quil sagit dune condition qui a d tre remplie pour que la partie se termine. Les avions et le canon sont en revanche toujours l. Nous navons pas stock tous les objets dafchage dans un unique tableau comme nous lavions fait pour le jeu de dduction du prcdent chapitre. Au lieu de cela, nous les avons placs dans le tableau airplanes, la variable aagun et le tableau bullets, que nous savons tre maintenant vide. Aprs avoir supprim les avions et le canon, nous devons galement supprimer les couteurs clavier et lcouteur vnementiel checkForHits. Le Timer nextPlane doit galement tre nettoy. Ensuite, nous pouvons passer limage gameover sans quaucun lment de jeu ne trane alentour :
// La partie est termine, supprimer les clips public function endGame() { // Supprimer les avions for(var i:int=airplanes.length-1;i>=0;i--) { airplanes[i].deletePlane();

194

ActionScript 3.0 pour les jeux

} airplanes = null; aagun.deleteGun(); aagun = null; stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpFunction); removeEventListener(Event.ENTER_FRAME,checkForHits); nextPlane.stop(); nextPlane = null; gotoAndStop("gameover"); }

Aprs cette fonction, vous aurez besoin de deux accolades supplmentaires an de refermer la classe et le paquetage. Lun des intrts de lutilisation de champs texte crs manuellement dans le scnario principal au lieu de champs ActionScript tient ce quils resteront pour limage gameover. Le joueur pourra ainsi voir son score dans la dernire image.

Modier le jeu
Lanimation AirRaid.a contient les mmes scripts dimage et boutons que lanimation Deduction. a du prcdent chapitre. Limage intro contient un bouton Start et limage gameover, un bouton Play Again. Limage intermdiaire est appele play. Dans ce jeu, jai galement ajout des instructions limage intro. La Figure 5.7 prsente la premire image avec ses instructions, son titre, son bouton Start et les champs texte en bas qui seront utiliss dans le jeu. Ce jeu peut tre amlior en ajoutant plus davions ou en amliorant le graphisme des avions. Larrireplan et le canon peuvent aussi tre redessins. Dans le code, vous pouvez faire varier la frquence dapparition des avions et leur vitesse de dplacement. Vous pourriez mme acclrer ces mouvements mesure que la partie progresse. Vous pouvez galement changer le nombre de munitions dont dispose le joueur. Dautres modications plus radicales pourraient amener changer entirement le thme du jeu. Vous pouvez recrer lun de ces anciens jeux de sous-marin en transformant les avions en bateaux et le canon en priscope de tir. Dans ce cas-l, je ralentirais personnellement la vitesse des balles et utiliserait des graphismes darrire-plan labors pour donner plus de profondeur la scne.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

195

Figure 5.7
Limage intro contient des instructions et un bouton Start.

Casse-brique
Codes sources http://ashgameu.com A3GPU05_PaddleBall.zip

Air Raid impliquait un simple mouvement une dimension pour une varit dobjets et des collisions qui conduisaient dtruire les objets. Ce nouveau jeu de casse-brique (en anglais, Paddle Ball) inclut des mouvements diagonaux et des collisions qui provoquent des rebonds. Le casse-brique a t popularis par lancien jeu vido Breakout. Des versions de ce jeu apparaissent souvent sur Internet et sont mme devenues des standards sur bien des tlphones portables et des iPod.

La version dorigine de Breakout pour Atari, en 1976, a t dveloppe par Steve Jobs et Steve Wozniak, avant quils ne fondent Apple Computer. La conception compacte de puce de Wozniak pour le jeu na pas fonctionn avec le processus de fabrication dAtari et a donc t abandonne. Des versions de Breakout sont apparues en srie dans de nombreuses versions du systme Mac OS. Aujourdhui encore, elles sont incluses dans la plupart des iPod.

196

ActionScript 3.0 pour les jeux

Dans cette version du jeu de casse-brique, le joueur contrle en bas de lcran une raquette quil peut dplacer gauche et droite laide de la souris. Le principal lment actif du jeu est une balle qui peut rebondir sur les cts, les murs et en haut mais qui le en bas de lcran si la raquette ne la renvoie pas. En haut de lcran se trouve un certain nombre de briques rectangulaires que le joueur doit liminer en dirigeant la balle vers elle avec la raquette.

Congurer lanimation
Lanimation est organise comme Air Raid et Deduction. La premire image sappelle intro et la troisime, gameover. Elles contiennent chacune des boutons pour dmarrer un nouveau jeu et des instructions dans la premire. Limage du milieu est intitule play. Cest cet endroit que se trouve le jeu. Nous avons dessin ici une bordure, un champ texte au milieu pour les messages tels que "Click to Start" (cliquez pour commencer) et un autre en bas droite pour indiquer au joueur le nombre de balles restantes. La Figure 5.8 prsente ces trois lments sur fond noir.
Figure 5.8
Le champ texte du milieu est intitul gameMessage et celui du bas droite, ballsLeft.

La bibliothque dans ce clip est galement un peu plus encombre que dans les jeux que nous avons examins jusque-l. La Figure 5.9 prsente la bibliothque avec le nom de classe des clips auxquels nos scripts accderont. Vous remarquerez quil y a un clip Brick et un clip Brick Graphic ainsi quun clip Paddle et un clip Paddle Graphic. Le second lment de chaque paire est contenu dans le premier. Le clip Brick Graphic est ainsi le seul et unique lment dans Brick. Lintrt de cette approche tient ce quelle nous permet aisment dappliquer un ltre ces lments. Un ltre, comme le ltre Biseau que nous utiliserons ici, peut tre appliqu dans linspecteur des proprits du

Chapitre 5

Animation de jeu : jeux de tir et de rebond

197

clip. Comme Brick et Paddle seront tous deux crs par ActionScript, nous ne pouvons cependant pas leur appliquer ces ltres de cette manire. Voil pourquoi nous avons un Brick Graphic lintrieur de Brick. Le clip Brick Graphic se verra appliquer le ltre. Ensuite, nous pourrons crer une copie de Brick en ActionScript sans le moindre souci.
Figure 5.9
La bibliothque compte sept lments, dont la balle, les briques et la raquette.

Nous pourrions appliquer le ltre avec le code ActionScript galement, mais il faudrait du code supplmentaire qui ne concerne pas vritablement le jeu. Lautre raison pour laquelle il est prfrable de conserver les rglages de ltre en dehors du code ActionScript tient ce que ces lments peuvent tre laisss au soin dun artiste graphiste qui travaille avec le programmeur. Il est plus simple pour les artistes de crer des graphismes et dappliquer des ltres que de dpendre du programmeur pour cela.

La Figure 5.10 prsente le clip Brick, avec le clip Brick Graphic lintrieur. Vous pouvez galement voir linspecteur des proprits avec les paramtres de ltre.

Dnition de classe
la diffrence du jeu Air Raid, celui-ci utilise une unique classe ActionScript pour tout contrler. Cette classe a besoin de renfort, notamment avec getTimer, la classe Rectangle et la classe TextField :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer; import ash.geom.Rectangle; import ash.text.TextField;

198

ActionScript 3.0 pour les jeux

Figure 5.10
Un ltre Biseau est utilis pour transformer des rectangles simples en graphismes plus sophistiqus.

De nombreuses constantes doivent tre considres dans ce jeu. La liste suivante sexplique relativement bien delle-mme. Elle inclut les positions et dimensions de nombreux lments dans le jeu, comme la balle, les murs et la raquette :
public class PaddleBall extends MovieClip { // Constantes environnementales private const ballRadius:Number = 9; private const wallTop:Number = 18; private const wallLeft:Number = 18; private const wallRight:Number = 532; private const paddleY:Number = 380; private const paddleWidth:Number = 90; private const ballSpeed:Number = .2; private const paddleCurve:Number = .005; private const paddleHeight:Number = 18;

Les deux seuls objets qui se dplacent dans ce jeu sont la balle et la raquette. En outre, nous avons besoin dun tableau pour stocker les briques :
// Objets cls private var paddle:Paddle; private var ball:Ball; // Briques private var bricks:Array;

Chapitre 5

Animation de jeu : jeux de tir et de rebond

199

Nous utiliserons deux variables pour surveiller la vlocit de la balle : ballDX et ballDY. Nous aurons galement besoin dune variable lastTime, comme dans Air Raid :
// Vlocit de la balle private var ballDX:Number; private var ballDY:Number; // Minuteur de lanimation private var lastTime:uint;

La vlocit est une mesure combinant vitesse et direction. Une variable comme dx mesure la vitesse horizontale dun objet. Mais une combinaison de variables comme dx et dy mesure la fois la vitesse et la direction : autrement dit, la vlocit. Sinon un jeu peut enregistrer la vitesse dans une variable (pixels par seconde) et la direction dans une autre (un vecteur ou un angle). Combines, ces valeurs reprsentent la vlocit.

Une dernire variable dnit le nombre de balles restantes. Il sagit du premier jeu que nous ayons cr qui donne au joueur un certain nombre de chances, ou de vies, avant que la partie ne soit termine. Le joueur a trois balles utiliser lorsquil joue. Lorsquil manque la troisime, la partie se termine :
// Nombre de balles restantes private var balls:Number;

Il ny aura pas de fonction constructeur pour ce jeu car nous attendrons la deuxime image pour dmarrer. Nous laissons donc de ct la fonction PaddleBall.

Dmarrer le jeu
Lorsque le jeu est dmarr, la raquette, les briques et la balle sont cres. La cration du motif de briques est dlgue une autre fonction. Nous lexaminerons ensuite. Le nombre de balles est x trois et le message de jeu initial est plac dans le champ texte. lastTime est galement positionn zro. Nous ne procdions pas ainsi auparavant, puisque nous lui attribuions la valeur de getTimer. Je mexpliquerai sur ce point lorsque nous en viendrons aux fonctions danimation qui utilisent lastTime. Deux couteurs sont dnis. Le premier appelle simplement la fonction moveObjects chaque image. Le second est un couteur vnementiel plac dans la scne pour capturer les clics de souris. Nous allons demander au joueur de cliquer pour dmarrer (message "Click to Start").

200

ActionScript 3.0 pour les jeux

Nous devons donc capturer ce clic et lutiliser en excutant newBall :


public function startPaddleBall() { // Crer la raquette paddle = new Paddle(); paddle.y = paddleY; addChild(paddle); // Crer les briques makeBricks(); balls = 3; gameMessage.text = "Click To Start"; // Congurer lanimation lastTime = 0; addEventListener(Event.ENTER_FRAME,moveObjects); stage.addEventListener(MouseEvent.CLICK,newBall); }

La fonction makeBricks cre une grille de briques. Il y aura huit colonnes en largeur et cinq lignes en hauteur. Nous utiliserons une boucle imbrique avec des variables x et y pour crer lensemble des quarante briques. Les positions de chaque brique correspondent des espaces de 60 pixels verticalement et 20 horizontalement, avec un dcalage de 65 et 50 pixels :
// Crer la collection de briques public function makeBricks() { bricks = new Array(); // Crer une grille de briques, 5 verticalement et 8 horizontalement for(var y:uint=0;y<5;y++) { for(var x:uint=0;x<8;x++) { var newBrick:Brick = new Brick(); // Les espacer harmonieusement newBrick.x = 60*x+65; newBrick.y = 20*y+50; addChild(newBrick); bricks.push(newBrick); } } }

Chapitre 5

Animation de jeu : jeux de tir et de rebond

201

Lors de la cration de fonctions dorganisation de ce type, ne craignez pas deffectuer quelques exprimentations avec les nombres an dobtenir le rsultat dsir. Par exemple, jai test diffrents nombres dans la fonction makeBricks jusqu obtenir une disposition des briques qui ait bonne apparence. Jaurais videmment pu calculer lespacement et le dcalage sur papier auparavant, mais il tait plus simple et plus rapide de procder quelques essais aviss.

ActionScript est un excellent environnement pour lexprimentation et la dcouverte. Vous navez pas besoin de prvoir les moindres dtails avant de taper la premire ligne de code. Lun des avantages lis au fait de dlguer la cration des briques sa propre fonction tient ce que vous pouvez la remplacer par une fonction qui produit diffrents motifs de briques. Cette fonction pourrait mme rcuprer dans une base de donnes un schma dnissant la disposition des diffrents murs de briques. Tous les changements que vous apportez au motif sont isols dans un unique appel makeBricks. Il est donc aussi ais de travailler avec un second programmeur qui soccupe de la disposition des briques pendant que vous travaillez sur la logique du jeu lui-mme. La Figure 5.11 prsente le jeu au dbut, avec la balle, la raquette et les briques. Vous pouvez galement voir les murs, qui ont un simple rle esthtique. La balle rebondira sur les murs invisibles que nous avons crs en dnissant wallLeft, wallRight et wallTop.
Figure 5.11
Tous les lments de jeu apparaissent au tout dbut du jeu.

202

ActionScript 3.0 pour les jeux

Lancer une nouvelle balle


Lorsque le jeu commence, il ny a pas de balle. Au lieu de cela, le message "Click to Start" apparat et le joueur doit cliquer sur la scne. Cette action appelle newBall, qui cre un nouvel objet Ball et dnit sa position et ses proprits associes. Pour commencer, newBall sassure que ball vaut null. Cette prcaution empche lutilisateur de cliquer sur lcran pendant que la balle est dj en jeu. Ensuite, le champ texte gameMessage est effac :
public function newBall(event:Event) { // Ne pas excuter ce code sil y a dj une balle if (ball != null) return; gameMessage.text = ;

Une nouvelle balle est cre au centre exact de lcran, en utilisant le point mi-chemin entre wallLeft et wallRight et entre wallTop et la position verticale de la raquette :
// Crer la balle, la centrer ball = new Ball(); ball.x = (wallRight-wallLeft)/2+wallLeft; ball.y = 200;//(paddleY-wallTop)/2+wallTop; addChild(ball);

La vlocit de la balle est dnie la verticale exacte, la vitesse dnie par la constante ballSpeed :
// vlocit de la balle ballDX = 0; ballDY = ballSpeed;

La variable balls est rduite dune unit et le champ texte en bas droite est modi an dafcher le nombre de balles restantes. lastTime est en outre repositionn zro an que le chronomtreur de lanimation recommence zro :
// Utiliser une balle balls--; ballsLeft.text = "Balls: "+balls; // Rinitialiser lanimation lastTime = 0; }

La fonction newBall sera utilise au dbut du jeu et galement pour lancer une nouvelle balle en cours de partie.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

203

Animation du jeu et dtection des collisions


Jusque-l, le code du jeu a t plutt simple. Les choses se compliquent cependant lorsque lon considre les objets mouvants. La balle doit dtecter les collisions avec la raquette et avec les briques. Elle doit ensuite ragir ces collisions de manire approprie. Lcouteur vnementiel pour ENTER_FRAME appelle moveObjects chaque image. Cette fonction dlgue ensuite le travail deux autres fonctions, movePaddle et moveBall :
public function moveObjects(event:Event) { movePaddle(); moveBall(); }

Mouvement de la raquette
La fonction movePaddle est trs simple. Elle positionne simplement la proprit x de la raquette en lui attribuant lemplacement de mouseX. Elle utilise cependant aussi Math.min et Math.max pour restreindre lemplacement aux cts gauche et droit de la scne.

Les proprits mouseX et mouseY retournent lemplacement du curseur par rapport lobjet dafchage courant. Dans le cas prsent, il sagirait de la classe principale, qui quivaut la scne. Si nous examinions mouseX et mouseY depuis lintrieur dune classe de clip, nous serions contraints dajuster les rsultats ou dexaminer plutt stage.mouseX et stage.mouseY.
public function movePaddle() { // Faire correspondre la valeur horizontale avec la souris var newX:Number = Math.min(wallRight-paddleWidth/2, Math.max(wallLeft+paddleWidth/2, mouseX)); paddle.x = newX; }

Mouvement de la balle
Cest moveBall, la fonction qui dplace la balle, qui obtient la part du lion en matire de code. Le mouvement de base est comparable celui des objets mouvants du jeu Air Raid. En revanche, les collisions sont bien plus complexes. La fonction commence par une vrication de ball an de sassurer quelle ne vaut pas null. Si cest le cas, nous sommes entre deux balles et le reste peut tre ignor :
public function moveBall() { // Ne pas excuter ce code si entre deux balles if (ball == null) return;

204

ActionScript 3.0 pour les jeux

Rappelez-vous que nous avons initialis la variable lastTime zro au lieu de lui attribuer la valeur de getTimer. Nous avons procd ainsi an que le temps requis pour crer les objets du jeu et dessiner lcran la premire fois ne soit pas utilis pour dterminer la quantit de la premire tape danimation. Par exemple, sil faut 500 millisecondes pour que le jeu commence, getTimer() moins lastTime vaudra 500 millisecondes ou plus. La balle ferait ainsi un sacr bond avant que le joueur nait mme la chance de pouvoir ragir.

Lune des raisons pour lesquelles ce jeu prend une demi-seconde environ pour commencer tient son usage des ltres Biseau. Cette opration ralentit le dbut du jeu pour gnrer les modications de la reprsentation visuelle des briques et de la raquette. Elle ne ralentit en revanche pas le jeu ensuite.

En faisant commencer lastTime zro, nous pouvons le reconnatre ici dans la fonction danimation et obtenir une nouvelle valeur pour lastTime. Cela signie que, la premire fois dans la fonction, timePassed vaudra en toute vraisemblance zro. Ce nest pas un problme et nous pouvons en revanche ainsi nous assurer que le minuteur de lanimation ne tourne pas tant que nous nen sommes pas au point dappeler moveBall la premire fois :
// Calcul du nouvel emplacement pour la balle if (lastTime == 0) lastTime = getTimer(); var timePassed:int = getTimer()-lastTime; lastTime += timePassed; var newBallX = ball.x + ballDX*timePassed; var newBallY = ball.y + ballDY*timePassed;

Dtection des collisions


Pour dmarrer notre dtection des collisions, nous rcuprerons le rectangle de la balle. En fait, nous allons obtenir deux versions diffrentes du rectangle : le rectangle actuel de la balle, appel oldBallRect, et le rectangle de la balle si elle devait terminer son mouvement sans contrainte, appel newBallRect.

Lobjet Rectangle est un parfait exemple dobjet capable dapporter des complments dinformation partir des donnes dont vous lalimentez. Vous lui fournissez une position x et y et une largeur et une hauteur, mais vous pouvez lui demander des informations interprtes comme les bords suprieur, infrieur, gauche et droit du rectangle. Vous pouvez obtenir des objets Point pour les coins (par exemple, bottomRight pour le coin infrieur droit). Nous utiliserons les cts suprieur, infrieur, gauche et droit du rectangle dans nos calculs.

Notre manire de calculer oldBallRect et newBallRect consiste utiliser les positions x et y, plus ou moins le rayon de la balle (ballRadius). Par exemple, ball.x-ballRadius nous donne la position x et ballRadius*2 nous donne la largeur.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

205

Nous calculons le rectangle de la raquette (paddleRect) de la mme manire :


var oldBallRect = new Rectangle(ball.x-ballRadius, ball.y-ballRadius, ballRadius*2, ballRadius*2); var newBallRect = new Rectangle(newBallX-ballRadius, newBallY-ballRadius, ballRadius*2, ballRadius*2); var paddleRect = new Rectangle(paddle.x-paddleWidth/2, paddle.y-paddleHeight/2, paddleWidth, paddleHeight);

Maintenant que nous avons ces trois rectangles disposition, nous pouvons les utiliser pour voir si la balle a touch la raquette. Cela se produit lorsque le bas de la balle franchit le haut de la raquette. Il est cependant plus dur quil ny parat de dterminer ce moment. Nous ne souhaitons pas simplement savoir si le bas de la balle a pass le bas de la raquette. Nous souhaitons savoir que cela vient tout juste de se passer, exactement cette tape de lanimation. La vritable question poser est donc la suivante : le bas de la balle a-t-il franchi le haut de la raquette et le bas de la balle se trouvait-il prcdemment au-dessus du haut de la raquette ? Si ces deux conditions sont runies, la balle vient juste de franchir la raquette. La Figure 5.12 illustre ce problme de manire graphique.
Figure 5.12
Le diagramme prsente la balle limage prcdente et la balle telle quelle se positionnerait si son mouvement ntait pas frein. La balle a franchi la raquette et doit tre dvie.
oldBallRect.bottom

paddleRect.top

newBallRect.bottom

Un autre test doit tre ralis. Nous devons savoir si lemplacement horizontal de la balle correspond celui de la raquette. Ainsi, si le ct droit de la balle est suprieur au ct gauche de la raquette et si par ailleurs le ct gauche de la balle est infrieur au ct droit de la raquette, nous avons effectivement une collision. En cas de collision, la balle doit tre dvie vers le haut. Il suft pour cela dinverser la direction de ballDY. En outre, il convient de dnir un nouvel emplacement pour la balle. Celle-ci ne peut tout de mme pas rester lintrieur de la raquette telle quelle sy trouve maintenant (voir Figure 5.12). La distance au-del du haut de la raquette est donc calcule et la balle est dvie vers le haut de deux fois cette distance (voir Figure 5.13).
// Collision avec la raquette if (newBallRect.bottom >= paddleRect.top) { if (oldBallRect.bottom < paddleRect.top) { if (newBallRect.right > paddleRect.left) { if (newBallRect.left < paddleRect.right) {

206

ActionScript 3.0 pour les jeux

// Rebond newBallY -= 2*(newBallRect.bottom - paddleRect.top); ballDY *= -1; // Calcul du nouvel angle ballDX = (newBallX-paddle.x)*paddleCurve; } }

Figure 5.13
La balle avance lgrement dans la raquette et se trouve donc place la mme distance lcart de la raquette.

Nouvel emplacement du bas

Dviation = 2 distance du dpassement

Distance du dpassement

Emplacement prvu du bas

Si la vitesse verticale de la balle est simplement inverse, la vitesse horizontale ballDX se voit pour sa part attribuer une toute nouvelle valeur. Cette valeur est dtermine par la distance partir du centre de la raquette. Elle est multiplie par une constante paddleCurve. Lide est ici que le joueur doit diriger la balle ; sil se contente de toucher la balle avec le plat de la raquette, celle-ci ne prendra pas dautre angle que celui avec lequel elle a commenc. Le jeu serait impossible jouer. Leffet de ce systme est que la balle rebondit vers le haut et le bas au centre de la raquette et part avec un angle de plus en plus prononc mesure que lon sapproche de ses extrmits. Si la balle a pass la raquette, il ny a pas de retour possible. Nous ne supprimons cependant pas tout de suite la balle. Nous lautorisons plutt continuer jusqu ce quelle atteigne le bas de lcran, aprs quoi elle est nalement supprime.

Lun des moyens courants de reprsenter ce principe consiste faire apparatre une lgre courbe sur la partie suprieure de la raquette. Cet effet suggre au joueur leffet produit lorsque la balle frappe la raquette. Comme ce comportement a t adopt dans tous les jeux de cassebrique depuis, la plupart des joueurs le prsupposent quoi quil en soit.

Chapitre 5

Animation de jeu : jeux de tir et de rebond

207

Sil sagit de la dernire balle, la partie est termine et la fonction endGame est appele. Sinon le champ gameMessage est rempli avec le texte "Click For Next Ball". Comme la variable ball est positionne null, la fonction moveBall nagit plus sur rien et la fonction newBall accepte le clic suivant comme un dclencheur pour crer une nouvelle balle. Nous pouvons et devons quitter cette fonction maintenant avec une commande return. Inutile de vrier les collisions avec les murs ou les briques si la balle a disparu :
} else if (newBallRect.top > 400) { removeChild(ball); ball = null; if (balls > 0) { gameMessage.text = Click For Next Ball; } else { endGame(); } return; } }

Ensuite, nous testons les collisions avec les trois murs. Ces vrications sont plus simples parce que la balle ne doit jamais dpasser lun dentre eux. Dans chaque cas, la vitesse verticale ou horizontale est inverse et lemplacement de la balle est altr de la mme manire que pour les collisions avec la raquette, de sorte que la balle ne se trouve jamais "dans" les murs :
// Collision avec le mur suprieur if (newBallRect.top < wallTop) { newBallY += 2*(wallTop - newBallRect.top); ballDY *= -1; } // Collisions avec le mur gauche if (newBallRect.left < wallLeft) { newBallX += 2*(wallLeft - newBallRect.left); ballDX *= -1; } // Collisions avec le mur droit if (newBallRect.right > wallRight) { newBallX += 2*(wallRight - newBallRect.right); ballDX *= -1; }

208

ActionScript 3.0 pour les jeux

Pour calculer la collision avec les briques, nous devons parcourir en boucle toutes les briques et les vrier une une. Pour chacune dentre elles, nous crons un brickRect an de pouvoir accder aux bords suprieur, infrieur, gauche et droit de la brique aussi facilement quavec la balle.

Normalement, lorsque vous souhaitez parcourir en boucle un tableau dobjets an de vrier sil y a une collision, vous devez le faire en sens inverse, an de pouvoir supprimer des objets dans la liste sans en sauter aucun. Cette fois, nous pouvons avancer normalement car, une fois que la balle entre en collision avec une brique, nous cessons de rechercher des collisions (une seule collision doit en effet se produire la fois).

Il est ais de dtecter une collision avec une brique, mais dj plus difcile dy ragir. Comme nous avons un Rectangle pour la balle et un pour la brique, nous pouvons utiliser la fonction intersects pour voir si le nouvel emplacement de la balle se trouve lintrieur dune brique. Si cest le cas, il faut dterminer quel ct de la brique a t touch. Une srie de tests compare les cts de la balle aux cts opposs des briques. Lorsquun ct chevauch a t trouv, la balle est dvie dans la direction approprie et son emplacement est ajust :
// Collision avec les briques for(var i:int=bricks.length-1;i>=0;i--) { // Rcupration du rectangle de la brique var brickRect:Rectangle = bricks[i].getRect(this); // Y a-t-il une collision avec une brique ? if (brickRect.intersects(newBallRect)) { // La balle frappe le ct gauche ou droit if (oldBallRect.right < brickRect.left) { newBallX += 2*(brickRect.left - oldBallRect.right); ballDX *= -1; } else if (oldBallRect.left > brickRect.right) { newBallX += 2*(brickRect.right - oldBallRect.left); ballDX *= -1; } // La balle frappe le haut ou le bas if (oldBallRect.top > brickRect.bottom) { ballDY *= -1; newBallY += 2*(brickRect.bottom-newBallRect.top); } else if (oldBallRect.bottom < brickRect.top) { ballDY *= -1; newBallY += 2*(brickRect.top - newBallRect.bottom); }

Chapitre 5

Animation de jeu : jeux de tir et de rebond

209

Si la balle est entre en collision avec une brique, cette dernire doit tre supprime. En outre, si le tableau bricks est vide, la partie est termine. Nous souhaitons galement utiliser return ici parce que, si la partie est termine, il nest pas ncessaire de dnir lemplacement de la balle la n de cette fonction ou de rechercher dautres collisions :
// Supprimer la brique removeChild(bricks[i]); bricks.splice(i,1); if (bricks.length < 1) { endGame(); return; } } } // Dnir nouvelle position ball.x = newBallX; ball.y = newBallY; }

Lun des aspects importants de ce jeu tient ce quil existe deux modes de jeu vritables : le premier concerne le cas o la balle est en jeu et le deuxime, celui o le joueur doit cliquer sur lcran pour crer une nouvelle balle. Le code dtermine le mode en cours en examinant la valeur de ball. Si elle vaut null, le jeu se trouve dans le deuxime mode.

Fin de partie
La partie se termine dans deux cas de gure : lorsque le joueur perd la dernire balle ou lorsque la balle atteint la dernire brique. Comme dans Air Raid, nous utilisons la fonction endGame pour nettoyer tous les clips restants. Nous positionnons galement les rfrences ces clips null an que le lecteur Flash puisse les supprimer de la mmoire. Il est important de sassurer que la balle nest pas dj partie car elle le sera si la fonction endGame est appele lorsque la dernire balle est perdue. Nous devons galement supprimer les couteurs, la fois celui qui appelle moveObjects chaque image et celui qui coute les clics de souris :
function endGame() { // Supprimer la raquette et les briques removeChild(paddle); for(var i:int=bricks.length-1;i>=0;i--) { removeChild(bricks[i]);

210

ActionScript 3.0 pour les jeux

} paddle = null; bricks = null; // Supprimer la balle if (ball != null) { removeChild(ball); ball = null; }

// Supprimer les couteurs removeEventListener(Event.ENTER_FRAME,moveObjects); stage.removeEventListener(MouseEvent.CLICK,newBall); gotoAndStop(gameover); }

la n du code, noubliez pas les accolades fermantes an de refermer la classe et le paquetage.

Modier le jeu
Ce jeu a vraiment besoin de sons. Vous pouvez les ajouter facilement en utilisant les exemples du jeu de Memory du Chapitre 3. Un bon dpart pourrait consister en proposer un pour la frappe sur la raquette et un autre lorsque la balle atteint une brique. Il serait aussi intressant den mettre lorsque la balle touche les murs ou lorsque la balle est manque. Il pourrait galement tre intressant dafcher des briques de couleurs diffrentes, par exemple en utilisant plusieurs images dans le clip Brick Graphic puis en accdant chaque fois limage approprie. Chaque ligne pourrait se voir ainsi attribuer sa propre couleur. Le calcul du score est intressant, mais il ne tmoigne pas clairement dune relle progression dans le jeu. Il fonctionnerait mieux si vous pouviez crer plusieurs niveaux. Les autres niveaux pourraient tre congurs en augmentant progressivement la vitesse de la balle ou en prsentant dautres dispositions pour les briques. Lorsque le joueur a dtruit toutes les briques, il serait intressant de faire disparatre la balle et dafcher un message invitant le joueur cliquer pour accder au niveau suivant. En cliquant, le joueur ferait ainsi apparatre non seulement une nouvelle balle mais galement un nouveau groupe de briques.

6
Puzzles dimages et puzzles coulissants
Au sommaire de ce chapitre :

Manipuler des images bitmap Jeu de puzzle coulissant Jeu de puzzle classique

212

ActionScript 3.0 pour les jeux

Il existe toute une gamme de jeux qui utilisent des photographies ou des dessins dtaills. Les puzzles sont assez nouveaux dans lunivers des ordinateurs car il a fallu attendre la moiti des annes 1990 pour que les ordinateurs grand public soient dots de capacits graphiques sufsantes pour afcher des images de qualit. Flash peut importer un certain nombre de formats dimage diffrents. Il ne se contente pourtant pas de les importer. Vous pouvez en fait accder aux donnes bitmap et manipuler les images. On peut ainsi dcouper des images et les utiliser dans des puzzles.

Flash prend en charge les formats de chier JPG, GIF et PNG. Le format JPG est idal pour les photographies parce quil compresse bien les donnes dimage et permet de dterminer la quantit de compression utiliser au moment de crer le chier. Le format GIF est un autre format compress qui convient mieux aux dessins incluant un nombre limit de couleurs. Le format PNG propose une trs bonne compression et une excellente qualit pleine rsolution. Tous ces formats peuvent tre crs par Fireworks ou Photoshop dAdobe, qui sont fournis avec Flash dans certains packs dAdobe.

Examinons rapidement les notions fondamentales lies limportation et la manipulation des images. Ensuite, nous tudierons deux jeux qui utilisent des pices de jeu provenant dimages importes et dcoupes en morceaux.

Manipuler des images bitmap


Codes sources http://ashgameu.com A3GPU06_Bitmap.zip Avant de pouvoir samuser avec une image bitmap, il faut commencer par limporter. Vous pouvez galement utiliser une image bitmap dans la bibliothque en lui attribuant simplement un nom de classe et en y accdant de cette manire. Limportation dune image bitmap externe est cependant bien plus souple pour presque tous les usages.

Charger une image bitmap


Lobjet Loader est une version spciale du Sprite qui rcupre ses donnes partir dune source externe. Vous aurez besoin de lapparier avec un URLRequest, qui gre laccs aux chiers rseau. Voici une classe trs simple qui charge un unique chier JPG et le positionne lcran. Aprs avoir cr un nouveau Loader et un nouveau URLRequest, nous les apparions avec la commande load.

Chapitre 6

Puzzles dimages et puzzles coulissants

213

Le processus complet ne prend que trois lignes de code. Ensuite, nous utilisons addChild pour ajouter lobjet Loader la scne, exactement comme pour un objet dafchage normal tel quun Sprite :
package { import ash.display.*; import ash.net.URLRequest; public class BitmapExample extends MovieClip { public function BitmapExample() { var loader:Loader = new Loader(); var request:URLRequest = new URLRequest("myimage.jpg"); loader.load(request); addChild(loader); } } }

La Figure 6.1 prsente une image bitmap charge de cette manire. Elle est positionne dans le coin suprieur gauche de lcran. Comme lobjet Loader agit la manire dun objet dafchage normal, nous pouvons galement dnir sa position x et y de manire la centrer lcran ou la situer o nous le voulons.
Figure 6.1
Cette image bitmap a t charge partir dun chier externe mais se comporte maintenant comme un objet dafchage normal.

214

ActionScript 3.0 pour les jeux

Si URLRequest est au dpart destin au travail sur les serveurs Web, il fonctionnera tout aussi bien sur votre disque dur pour vos tests.

Ce mcanisme peut tre utile pour charger des images dintroduction ou dinstruction dans un jeu. Par exemple, le logo de votre entreprise peut apparatre dans lcran dintroduction en utilisant ce simple jeu de commandes. Au lieu dincorporer votre logo dans chaque jeu Flash, vous pouvez avec un unique chier logo.png utiliser un Loader et un URLRequest pour limporter et lafcher. Ds lors, vous naurez plus qu modier directement votre chier logo.png pour que tous vos jeux utilisent le nouveau logo.

Dcomposer une image bitmap en morceaux


Le chargement et lafchage dune simple image bitmap sont utiles, mais nous devons encore nous plonger dans les donnes et extraire les pices du puzzle de limage pour crer les jeux du reste de ce chapitre. La premire modication que nous devons apporter lexemple simple prcdent consiste reconnatre le moment auquel limage bitmap a ni de se charger et o nous pouvons commencer la manipuler. Nous utiliserons pour cela un couteur Event.COMPLETE. Nous lajouterons lobjet Loader et pourrons ensuite placer tout notre code de manipulation dans la fonction loadingDone quil appellera.

En plus dEvent.COMPLETE, vous pouvez galement obtenir le rapport davancement du tlchargement dune image. Examinez la documentation Flash concernant URLRequest an dobtenir dautres exemples de suivi du chargement et dcouvrir mme des moyens de capturer et de grer les erreurs.

Voici le dbut de la nouvelle classe. Nous aurons besoin de la classe ash.geom par la suite. Jai galement plac le code de chargement dans sa propre fonction appele loadBitmap, an quil soit ais reporter dans les autres jeux du chapitre :
package { import ash.display.*; import ash.events.*; import ash.net.URLRequest; import ash.geom.*; public class BitmapExample extends MovieClip { public function BitmapExample() { loadBitmap("testimage.jpg"); }

Chapitre 6

Puzzles dimages et puzzles coulissants

215

// Rcuprer limage partir dune source externe public function loadBitmap(bitmapFile:String) { var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingDone); var request:URLRequest = new URLRequest(bitmapFile); loader.load(request); }

Lorsque limage est compltement charge, nous appelons la fonction loadingDone. Celle-ci soccupe en premier lieu de crer un nouvel objet Bitmap. Elle prend pour cela les donnes de event.target. loader.content (autrement dit, la proprit content de lobjet Loader original) :
private function loadingDone(event:Event):void { // Rcuprer les donnes charges var image:Bitmap = Bitmap(event.target.loader.content);

Nous pouvons obtenir la largeur et la hauteur de limage bitmap en accdant aux proprits width et height de la variable image maintenant quelle contient le contenu. Notre but est dobtenir la largeur et la hauteur de chacune des pices du puzzle. Pour cet exemple, nous aurons six colonnes et quatre lignes. La largeur totale divise par six nous donne donc la largeur de chaque pice. La hauteur totale divise par quatre nous donne la hauteur de chaque pice :
// Calculer la largeur et la hauteur de chaque pice var pieceWidth:Number = image.width/6; var pieceHeight:Number = image.height/4;

prsent, nous parcourons en boucle les six colonnes et les quatre lignes an de crer chaque pice du puzzle :
// Parcours en boucle de toutes les pices for(var x:uint=0;x<6;x++) { for (var y:uint=0;y<4;y++) {

La cration des pices du puzzle sopre en crant dabord un nouvel objet Bitmap. Nous spcions la largeur et la hauteur pour en crer une. Ensuite, nous utilisons copyPixels pour copier une section de limage dorigine dans la proprit bitmapData de la pice de puzzle. La commande copyPixels prend trois paramtres de base : limage partir de laquelle copier les donnes, le Rectangle spciant la partie de limage obtenir et le Point, qui dnit lendroit o le morceau de limage ira dans la nouvelle image bitmap :
// Crer une image bitmap de nouvelle pice de puzzle var newPuzzlePieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth,pieceHeight)); newPuzzlePieceBitmap.bitmapData.copyPixels(image.bitmapData,new Rectangle(x*pieceWidth, y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0));

216

ActionScript 3.0 pour les jeux

Notre but en soi nest pas davoir une image bitmap. Nous souhaitons avoir un Sprite afcher lcran. Nous en crons donc un nouveau et y ajoutons limage bitmap. Ensuite, nous ajoutons le Sprite la scne :
// Crer un nouveau sprite et y ajouter les donnes bitmap var newPuzzlePiece:Sprite = new Sprite(); newPuzzlePiece.addChild(newPuzzlePieceBitmap); // Ajouter la scne addChild(newPuzzlePiece);

Pour nir, nous devons dnir lemplacement des sprites. Nous souhaitons les positionner lcran en fonction de leur colonne et de leur ligne, en ajoutant 5 pixels pour crer un espacement blanc entre les pices. Nous dcalons galement les positions horizontale et verticale de toutes les pices de 20 pixels. La Figure 6.2 prsente les vingt-quatre pices du puzzle.
// Dnition de lemplacement newPuzzlePiece.x = x*(pieceWidth+5)+20; newPuzzlePiece.y = y*(pieceHeight+5)+20; } } }

Figure 6.2
Limage importe est dcompose en vingt-quatre pices qui sont espaces dans lcran.

Chapitre 6

Puzzles dimages et puzzles coulissants

217

Maintenant que nous savons comment crer un ensemble de pices de puzzle partir dune image importe, nous pouvons commencer crer les jeux qui utilisent ces pices. Pour commencer, nous allons crer un simple puzzle coulissant. Nous crerons un jeu de puzzle plus complexe par la suite.

Jeu de puzzle coulissant


Codes sources http://ashgameu.com A3GPU06_SlidingPuzzle.zip Il est surprenant quun jeu comme le jeu de puzzle coulissant ait mme exist avant les ordinateurs. Le jeu physique qui a prcd sa version informatique tait compos dun petit carr en plastique de taille rduite contenant gnralement quinze pices bloques par de petits rails et des rainures entrecroiss. Il fallait faire glisser lune des pices de plastique vers le seizime emplacement inoccup puis en faire glisser un autre vers le nouvel emplacement vide, et ainsi de suite. Ce processus se poursuivait jusqu ce que le puzzle se trouve entirement reconstitu. La version physique du jeu utilisait gnralement non pas une image mais plutt des nombres allant de 1 15. Do son nom de baptme : le puzzle-15.

Le problme avec ce jeu en plastique tenait ce que les carrs coinaient souvent, ce qui frustrait le joueur, parfois accapar dbloquer les pices rcalcitrantes. En outre, une fois le puzzle rsolu, il fallait dplacer alatoirement les carrs sans regarder pendant un long moment an de rtablir une conguration un tant soit peu alatoire.

La version informatique de ce jeu fonctionne beaucoup mieux. Pour commencer, vous pouvez proposer diffrents jeux de carrs comme image. Vous pouvez proposer une nouvelle image chaque fois, en offrant la possibilit aux joueurs de dcouvrir limage mesure que le puzzle se complte. En outre, lordinateur peut alatoirement disposer les pices du puzzle au dbut de chaque jeu. Et tout cela sans se pincer les doigts. Dans notre version du jeu de puzzle coulissant, nous utilisons un nombre variable de pices dcoupes dans limage. En outre, un mlange alatoire des carrs sopre au dbut du jeu. Nous animons galement les pices qui se dplacent dun endroit un autre an quelles paraissent glisser. Nous reconnaissons enn le moment o la solution est trouve.

218

ActionScript 3.0 pour les jeux

Congurer lanimation
Ce jeu utilise la mme structure trois images que nous avons utilise aux deux derniers chapitres, avec les images intro, play et gameover. Des instructions sont aussi proposes dans la premire image. Le seul graphisme requis est celui de limage elle-mme. Il sagira dun chier dimage JPG externe appel slidingimage.jpg. Nous lui donnerons une taille de 400 pixels par 300.

La taille dimage et la compression doivent tre prises en compte lors de la cration dune image pour un jeu de ce type. Les trois images utilises dans ce chapitre font moins de 34 Ko. Chacune fait 400 300 avec une compression JPEG 80 %. On pourrait aisment produire une image vingt fois plus lourde avec une compression sans perte comme celle des chiers PNG, mais ce niveau de qualit nest pas ncessaire et ne ferait que ralentir le temps de tlchargement pour le joueur.

Rappelez-vous que nous allons dcouper limage du puzzle puis supprimer la pice en bas droite. Le joueur a besoin de cet espace vide pour oprer ses dplacements. Il est donc prfrable de choisir une image qui ne contient rien dimportant en bas droite.

Congurer la classe
Le jeu de puzzle coulissant a besoin des classes URLRequest et geom pour grer limage. Nous utiliserons galement un objet Timer pour lanimation du glissement :
package { import ash.display.*; import ash.events.*; import ash.net.URLRequest; import ash.geom.*; import ash.utils.Timer;

Il y a tout un tas de constantes dnir pour ce jeu, commencer par lespacement entre les pices et le dcalage gnral de toutes les pices. Nous dciderons galement du nombre de pices dcouper dans limage, qui est ici de 4 3 :
public class SlidingPuzzle extends MovieClip { // Espacement entre les pices et dcalage static const pieceSpace:Number = 2; static const horizOffset:Number = 50; static const vertOffset:Number = 50; // Nombre de pices static const numPiecesHoriz:int = 4; static const numPiecesVert:int = 3;

Chapitre 6

Puzzles dimages et puzzles coulissants

219

Le nombre de colonnes et de lignes dans le puzzle devrait approximativement correspondre aux dimensions de limage. Dans le cas prsent, nous savons quil sagit dimages de 400 pixels sur 300 et nous crons un puzzle de 4 3. Les pices feront donc 100 pixels sur 100. On peut parfaitement crer des pices rectangulaires, comme un puzzle 4 4 avec des pices de 100 pixels sur 75, mais il semble tout de mme prfrable de conserver des pices plutt carres.

Pour disposer le puzzle de manire alatoire au dbut de la partie, nous allons oprer une srie de dplacements alatoires. Nous reviendrons sur ce point par la suite. En attendant, nous devons stocker le nombre de dplacements alatoires dans une constante an de pouvoir le changer facilement :
// tapes du mlange alatoire static const numShufe:int = 200;

Les pices du puzzle glisseront avec uidit en utilisant un Timer. Nous dciderons du nombre dtapes et de la dure requise pour que le mouvement de glissement sachve :
// tapes et temps de lanimation static const slideSteps:int = 10; static const slideTime:int = 250;

La largeur et la hauteur des pices du puzzle seront calcules en fonction des constantes numPiecesHoriz et numPiecesVert et de la taille de limage. Nous rcuprerons ces valeurs juste aprs que limage aura t charge :
// Taille des pices private var pieceWidth:Number; private var pieceHeight:Number;

Il nous faut un tableau pour stocker les pices du puzzle. Nous y stockerons non pas simplement les rfrences aux nouveaux sprites mais un petit objet contenant lemplacement de la pice du puzzle dans le puzzle ni ainsi que la rfrence au sprite :
// Pices du jeu private var puzzleObjects:Array;

Nous aurons besoin dun grand nombre de variables pour grer le jeu et les mouvements. Pour commencer, nous avons blankPoint, un objet Point indiquant lemplacement vide dans le puzzle. Lorsque le joueur clique sur une pice qui lui est adjacente, Flash dplace la pice pour la loger dans lespace vide. slidingPiece contient une rfrence la pice qui se dplace. slideDirection et le Timer slideAnimation permettront de paramtrer cette animation :
// Suivi des dplacements private var blankPoint:Point; private var slidingPiece:Object; private var slideDirection:Point; private var slideAnimation:Timer;

220

ActionScript 3.0 pour les jeux

Lorsque le joueur clique sur le bouton Start, il est conduit la seconde image, qui appelle startSlidingPuzzle. la diffrence des fonctions constructeurs dautres jeux, celle-ci ne fait pas grand-chose. Cest quen attendant que limage soit charge il ny pas grand-chose faire. La variable blankPoint est positionne au coin infrieur droit en utilisant certaines des constantes. Ensuite, loadBitmap est appele avec le nom du chier dimage :
public function startSlidingPuzzle() { // Lespace vide se trouve en bas droite blankPoint = new Point(numPiecesHoriz-1,numPiecesVert-1); // Charger limage bitmap loadBitmap("slidingpuzzle.jpg"); }

Rappelez-vous que le dcompte dans les tableaux et les boucles ActionScript commence zro. La pice en haut gauche correspond donc 0,0. La pice en bas droite correspond donc un de moins que le nombre de pices en largeur, soit numPiecesHoriz-1. Si un puzzle fait quatre pices en largeur et trois en hauteur, la pice en bas droite correspondra donc 3,2, soit numPiecesHoriz-1,numPiecesVert-1.

Charger limage
La fonction loadBitmap est identique celle utilise dans lexemple prcdent de ce chapitre :
// Rcuprer limage bitmap partir dune source externe public function loadBitmap(bitmapFile:String) { var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingDone); var request:URLRequest = new URLRequest(bitmapFile); loader.load(request); }

La fonction loadingDone prend dans le cas prsent une importance bien plus grande que dans lexemple antrieur. Maintenant que limage a t charge, il est possible dobtenir la largeur et la hauteur, ce qui nous indique la largeur et la hauteur individuelles de chaque pice. Nous pouvons dnir ces variables puis appeler makePuzzlePieces pour oprer le dcoupage.

Chapitre 6

Puzzles dimages et puzzles coulissants

221

Pour nir, shufePuzzlePieces mlange le puzzle et le prpare pour le joueur :


// Chargement termin, procder au dcoupage public function loadingDone(event:Event):void { // Crer une nouvelle image pour contenir limage bitmap charge var image:Bitmap = Bitmap(event.target.loader.content); pieceWidth = image.width/numPiecesHoriz; pieceHeight = image.height/numPiecesVert; // Dcoupage des pices du puzzle makePuzzlePieces(image.bitmapData); // Mlange des pices shufePuzzlePieces(); }

Dcouper limage bitmap en morceaux


Si notre prcdent exemple dcoupait limage en diffrentes pices, il navait pas construire tous les objets de donnes requis pour les rendre utiles dans un jeu. La fonction makePuzzlePieces se charge de cette tche en crant le tableau puzzleObjects. Une fois que le sprite de pice de puzzle est cr et que sa position est dnie, la variable temporaire newPuzzleObject est cre. Trois proprits sont associes newPuzzleObject. La premire est currentLoc, un objet Point qui indique o la pice de puzzle se trouve actuellement. 0,0 dsignera ainsi lemplacement en haut gauche et 3,2, lemplacement en bas droite. De manire similaire, homeLoc contient aussi un Point. Il sagit toutefois de lemplacement original (et nal) pour la pice. Il ne changera pas durant le jeu et fournit un point de rfrence an que nous puissions dterminer le moment o chaque pice est retourne son emplacement appropri.

Lune des autres approches possibles pourrait tre ici de stocker les proprits currentLoc et homeLoc des sprites, puis de ne stocker que les sprites dans le tableau. Dans le premier cas, les trois valeurs seraient puzzleObjects[x].currentLoc, puzzleObjects[x].homeLoc et puzzleObjects[x].piece. Dans le dernier, les mmes donnes seraient puzzleObjects[x]. currentLoc, puzzleObjects[x].homeLoc et puzzleObjects[x] (sans le .piece car llment dans le tableau est le sprite). Pour ma part, je prfre crer mon propre tableau dobjets an de massurer quActionScript peut rapidement obtenir les informations sans avoir examiner lobjet Sprite tout entier chaque fois.

222

ActionScript 3.0 pour les jeux

Nous avons galement une proprit piece de newPuzzleObject. Cette proprit contient une rfrence au sprite de la pice. Nous stockerons toutes les variables newPuzzleObject que nous crons dans le tableau puzzleObjects :
// Dcouper limage bitmap en pices public function makePuzzlePieces(bitmapData:BitmapData) { puzzleObjects = new Array(); for(var x:uint=0;x<numPiecesHoriz;x++) { for (var y:uint=0;y<numPiecesVert;y++) { // Ignorer lespace vide if (blankPoint.equals(new Point(x,y))) continue; // Crer limage bitmap et le sprite de la nouvelle pice de puzzle var newPuzzlePieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth, pieceHeight)); newPuzzlePieceBitmap.bitmapData.copyPixels(bitmapData, new Rectangle(x*pieceWidth,y*pieceHeight, pieceWidth,pieceHeight),new Point(0,0)); var newPuzzlePiece:Sprite = new Sprite(); newPuzzlePiece.addChild(newPuzzlePieceBitmap); addChild(newPuzzlePiece); // Dnir lemplacement newPuzzlePiece.x = x*(pieceWidth+pieceSpace) + horizOffset; newPuzzlePiece.y = y*(pieceHeight+pieceSpace) + vertOffset; // Crer lobjet stocker dans le tableau var newPuzzleObject:Object = new Object(); newPuzzleObject.currentLoc = new Point(x,y); newPuzzleObject.homeLoc = new Point(x,y); newPuzzleObject.piece = newPuzzlePiece; newPuzzlePiece.addEventListener(MouseEvent.CLICK,clickPuzzlePiece); puzzleObjects.push(newPuzzleObject); } } }

Chaque pice de puzzle rcupre son propre couteur vnementiel lcoute des clics de souris, qui appelle clickPuzzlePiece.

Chapitre 6

Puzzles dimages et puzzles coulissants

223

ce stade, toutes les pices sont en place, mais elles ne sont pas mlanges. Si nous ne les mlangions pas du tout, le jeu commencerait avec le puzzle dispos comme il lest la Figure 6.3.
Figure 6.3
Le puzzle coulissant non mlang. La pice en bas droite a t supprime an de crer un espace dans lequel les autres pices peuvent coulisser.

Mlanger les pices


Une fois que les pices du puzzle sont en place, il faut les mlanger. Lide est de crer un "puzzle en dsordre" an que le joueur puisse relever le d de le redisposer correctement. Lun des moyens de crer ce dsordre consiste placer toutes les pices des emplacements alatoires. Ce nest cependant pas ainsi quil faut procder. Si vous placez les pices alatoirement, il est assez probable que vous vous retrouviez avec une disposition qui ne permettra jamais de replacer correctement les pices. La Figure 6.4 prsente un tel cas de gure.
Figure 6.4
En inversant simplement les pices 15 et 14, nous crons un puzzle impossible rsoudre.

1 5 9

2 6

3 7

4 8

10 11 12

13 15 14

224

ActionScript 3.0 pour les jeux

Au lieu de placer alatoirement chacune des pices, nous commencerons donc par le puzzle termin et procderons des dplacements alatoires jusqu ce que la grille paraisse compltement alatoire. La fonction shufePuzzlePieces opre une boucle et appelle shufeRandom un certain nombre de fois. Cest ici shufeRandom qui se charge du vritable travail :
// Crer un certain nombre de dplacements alatoires public function shufePuzzlePieces() { for(var i:int=0;i<numShufe;i++) { shufeRandom(); } }

Pour crer un dplacement alatoire, nous allons examiner toutes les pices du puzzle. Ensuite, nous dterminerons quels dplacements sont possibles et les placerons dans un tableau. Nous choisirons enn un dplacement au hasard dans ce tableau et procderons la modication correspondante. La cl du mcanisme sera la fonction validMove, que nous allons examiner ensuite. La fonction shufeRandom, aprs avoir slectionn un dplacement alatoire, appelle movePiece, la mme fonction que nous utilisons lorsque le joueur clique pour oprer un dplacement :
// Dplacement alatoire public function shufeRandom() { // Parcours en boucle pour trouver les dplacements valides var validPuzzleObjects:Array = new Array(); for(var i:uint=0;i<puzzleObjects.length;i++) { if (validMove(puzzleObjects[i]) != none) { validPuzzleObjects.push(puzzleObjects[i]); } } // Slection dun dplacement alatoire var pick:uint = Math.oor(Math.random()*validPuzzleObjects.length); movePiece(validPuzzleObjects[pick],false); }

La fonction validMove prend en paramtre une rfrence un puzzleObject. En utilisant la proprit currentLoc de cette pice de puzzle, elle peut dterminer si la pice se trouve ct de lemplacement vide. Tout dabord, elle regarde au-dessus de la pice de puzzle. Dans ce cas, les valeurs x de la pice et de lemplacement vide doivent se correspondre. Si cest effectivement le cas, cest au tour des positions verticales (y) dtre compares. blankPoint.y doit faire un de moins que currentLoc.y pour le puzzleObject. Si tout cela se conrme, la valeur "up" est retourne, qui indique la fonction appelant validMove que cette pice possde effectivement un dplacement valide : "up" (vers le haut).

Chapitre 6

Puzzles dimages et puzzles coulissants

225

Vous remarquerez que la dclaration de la fonction validMove stipule quelle retourne une chane. Cest le sens de la portion ": String" dans la premire ligne du code qui suit. Il est toujours judicieux dindiquer le type de donnes retourn par vos fonctions. Vous aiderez ainsi le lecteur Flash optimiser ses performances.

Les dplacements vers le bas, la gauche et la droite sont ensuite examins. Si aucun de ces dplacements ne ne se rvle valide, la valeur "none" est retourne, an dindiquer quil nexiste pas de dplacement valide pour cette pice du puzzle :
public function validMove(puzzleObject:Object): String { // Lemplacement vide est-il au-dessus ? if ((puzzleObject.currentLoc.x == blankPoint.x) && (puzzleObject.currentLoc.y == blankPoint.y+1)) { return up; } // Lemplacement vide est-il en dessous ? if ((puzzleObject.currentLoc.x == blankPoint.x) && (puzzleObject.currentLoc.y == blankPoint.y-1)) { return down; } // Lemplacement vide est-il gauche ? if ((puzzleObject.currentLoc.y == blankPoint.y) && (puzzleObject.currentLoc.x == blankPoint.x+1)) { return "left"; } // Lemplacement vide est-il droite ? if ((puzzleObject.currentLoc.y == blankPoint.y) && (puzzleObject.currentLoc.x == blankPoint.x-1)) { return "right"; } // Aucun dplacement nest valide return "none"; }

Aprs le mlange, la partie commence avec toutes les pices en dsordre, comme le montre la Figure 6.5.

226

ActionScript 3.0 pour les jeux

Figure 6.5
Le jeu peut maintenant commencer avec les pices mlanges.

La question de savoir combien de fois il faut mlanger les pices na pas de rponse dnitive. Jai personnellement opt pour deux cents dplacements alatoires, car cela semblait convenir. Si vous choisissez moins, la solution sera plus facile. Si vous choisissez un nombre de dplacements trop lev, vous constaterez une pause au dbut du jeu pendant lopration de mlange.

Ragir aux clics du joueur


Lorsque le joueur clique, la fonction clickPuzzlePiece sexcute. Lvnement qui lui est pass possde un currentTarget qui correspond une pice dans la liste puzzleObjects. Une boucle rapide permet de trouver la pice correspondante et la fonction movePiece est appele :
// Lutilisateur a cliqu sur une pice du puzzle public function clickPuzzlePiece(event:MouseEvent) { // Trouver la pice clique et la dplacer for(var i:int=0;i<puzzleObjects.length;i++) { if (puzzleObjects[i].piece == event.currentTarget) { movePiece(puzzleObjects[i],true); break; } } }

Chapitre 6

Puzzles dimages et puzzles coulissants

227

Vous remarquerez que, lorsque la fonction shufeRandom a appel movePiece, elle a utilis false comme second paramtre. Lorsque clickPuzzlePiece a appel movePiece, elle a en revanche utilis true comme second paramtre. Le second paramtre est slideEffect, qui possde la valeur true ou la valeur false. Si la valeur est
true, un objet Timer est cr an de dplacer progressivement la pice en un court instant. Si la valeur

est false, la pice se dplace immdiatement. Nous souhaitions que les pices se dplacent immdiatement dans le cas du mlange mais, quand le joueur est en pleine partie, quil puisse proter de cette animation. La dcision nest en fait pas ralise lintrieur de movePiece. movePiece se contente en ralit dappeler validMove et de dterminer si le dplacement se fait vers le haut, le bas, la gauche ou la droite. Ensuite, elle appelle movePieceInDirection avec les mmes valeurs puzzleObject et slideEffect, ainsi que de nouvelles valeurs dx et dy en fonction de la direction du mouvement.

La fonction movePiece utilise la structure switch dActionScript pour oprer le branchement vers un bloc de code parmi quatre possibles. Linstruction switch sapparente une srie dinstructions ifthen mais ne requiert la variable teste que dans la ligne switch. Chaque branche dmarre avec le mot-cl case et la valeur correspondant ce cas. Chaque branche doit se terminer par une commande break.

// Dplacement dune pice dans lespace vide public function movePiece(puzzleObject:Object, slideEffect:Boolean) { // Dterminer le sens vers lespace vide switch (validMove(puzzleObject)) { case "up": movePieceInDirection(puzzleObject,0,-1,slideEffect); break; case "down": movePieceInDirection(puzzleObject,0,1,slideEffect); break; case "left": movePieceInDirection(puzzleObject,-1,0,slideEffect); break; case "right": movePieceInDirection(puzzleObject,1,0,slideEffect); break; } }

228

ActionScript 3.0 pour les jeux

La fonction movePieceInDirection change instantanment la proprit currentLoc de la pice et la variable blankPoint. Ce mcanisme permet de grer le cas o le joueur ralise un autre mouvement avant que lanimation ne soit termine. La pice et le blankPoint se trouvent ainsi dj vritablement au bon emplacement. Lanimation na ds lors de vocation questhtique :
// Dplacer la pice dans lespace vide public function movePieceInDirection(puzzleObject:Object, dx,dy:int, slideEffect:Boolean) { puzzleObject.currentLoc.x += dx; puzzleObject.currentLoc.y += dy; blankPoint.x -= dx; blankPoint.y -= dy;

Sil doit y avoir une animation, la fonction startSlide est appele pour la congurer. Sans cela, la pice du puzzle est dplace immdiatement vers le nouvel emplacement :
// Animer ou non if (slideEffect) { // Lancer animation startSlide(puzzleObject,dx*(pieceWidth+pieceSpace), dy*(pieceHeight+pieceSpace)); } else { // Aucune animation, dplacer seulement puzzleObject.piece.x = puzzleObject.currentLoc.x*(pieceWidth+pieceSpace) + horizOffset; puzzleObject.piece.y = puzzleObject.currentLoc.y*(pieceHeight+pieceSpace) + vertOffset; } }

Animer le glissement
Le glissement anim se ralise en lanant un objet Timer et en dplaant la pice du puzzle par tapes. Selon les constantes au dbut de la classe, il doit y avoir dix tapes, espaces chacune de 250 millisecondes. La fonction startSlide commence par congurer certaines variables an de surveiller lanimation. La pice du puzzle dplacer est slidingPiece. slideDirection est un objet Point dont dx et dy reprsentent le sens du dplacement. Il sagit de (1,0), (1,0), (0,1) ou (0,1) selon le sens dans lequel se dplace la pice.

Chapitre 6

Puzzles dimages et puzzles coulissants

229

Ensuite, le Timer est cr et deux couteurs lui sont associs. Lcouteur TimerEvent.TIMER dplace la pice tandis que lcouteur TimerEvent.TIMER_COMPLETE appelle slideDone pour raliser lanimation :
// Conguration dun glissement public function startSlide(puzzleObject:Object, dx, dy:Number) { if (slideAnimation != null) slideDone(null); slidingPiece = puzzleObject; slideDirection = new Point(dx,dy); slideAnimation = new Timer(slideTime/slideSteps,slideSteps); slideAnimation.addEventListener(TimerEvent.TIMER,slidePiece); slideAnimation.addEventListener(TimerEvent.TIMER_COMPLETE,slideDone); slideAnimation.start(); }

Toutes les 250 millisecondes, la pice de puzzle se dplace dune fraction de la distance an de se rapprocher de sa destination nale. Vous remarquerez galement que la premire ligne de startSlide correspond un appel potentiel slideDone. Cet appel seffectue si une nouvelle animation de glissement est sur le point de commencer alors que la premire na pas ni de se raliser. Dans ce cas, la prcdente est rapidement termine par un unique appel slideDone qui place la pice mouvante son emplacement nal et laisse donc la place pour lanimation du nouveau glissement.

Il sagit cette fois dun type danimation diffrent de lanimation temporelle utilise au Chapitre 5. Le mouvement de glissement anim nest pas ici un lment critique du jeu. Il na de vertu questhtique. Il est donc judicieux de le placer en dehors du reste de la logique du jeu, avec son propre minuteur temporaire. Nous navons pas nous soucier de lhomognit des performances, car elles naffectent pas le jeu.

// Avancer dune tape dans le glissement public function slidePiece(event:Event) { slidingPiece.piece.x += slideDirection.x/slideSteps; slidingPiece.piece.y += slideDirection.y/slideSteps; }

Lorsque le Timer a termin, lemplacement de la pice du puzzle est dni de manire sassurer que la pice se trouve exactement o elle doit tre. Le minuteur slideAnimation est ensuite supprim.

230

ActionScript 3.0 pour les jeux

Cest galement le moment dappeler puzzleComplete an de voir si chaque pice se trouve au bon endroit. Si cest le cas, nous appelons clearPuzzle et le scnario principal passe limage gameover :
// Fin du glissement public function slideDone(event:Event) { slidingPiece.piece.x = slidingPiece.currentLoc.x*(pieceWidth+pieceSpace) + horizOffset; slidingPiece.piece.y = slidingPiece.currentLoc.y*(pieceHeight+pieceSpace) + vertOffset; slideAnimation.stop(); slideAnimation = null; // Vrier si le puzzle est termin if (puzzleComplete()) { clearPuzzle(); gotoAndStop(gameover); } }

Fin de partie et nettoyage


Il est trs facile de dterminer si la partie est termine. Il suft pour cela dexaminer chaque pice et de comparer currentLoc avec homeLoc. Grce la fonction equals de la classe Point, cela peut se faire en une tape. Si toutes les pices se trouvent dans leur emplacement dorigine, la fonction renvoie la valeur true :
// Vrier si toutes les pices sont en place public function puzzleComplete():Boolean { for(var i:int=0;i<puzzleObjects.length;i++) { if (!puzzleObjects[i].currentLoc.equals(puzzleObjects[i].homeLoc)) { return false; } } return true; }

Vient ensuite la fonction de nettoyage du jeu. Tous les sprites de pice de puzzle se dbarrassent de leurs vnements MouseEvent.CLICK et sont supprims, aprs quoi le tableau puzzleObjects est

Chapitre 6

Puzzles dimages et puzzles coulissants

231

rinitialis null. Comme les pices du puzzle sont les seuls objets du jeu qui ont t crs, il ny a rien de plus faire :
// Supprimer toutes les pices du puzzle public function clearPuzzle() { for (var i in puzzleObjects) { puzzleObjects[i].piece.addEventListener(MouseEvent.CLICK, clickPuzzlePiece); removeChild(puzzleObjects[i].piece); } puzzleObjects = null; }

Modier le jeu
Le jeu est plutt simple jouer et peu de variantes sont susceptibles de lamliorer. Vous pouvez cependant amliorer le programme lui-mme en offrant la possibilit de slectionner limage de manire dynamique. La page Web pourrait ainsi passer elle-mme le nom de limage. Et vous pourriez proposer un jeu qui utilise diffrentes images selon la page Web ou selon le jour. Ce jeu peut galement tre rendu progressif. Aprs que chaque puzzle est termin, un nouveau niveau peut tre propos. Le nom de chier de limage et les variables numPiecesHoriz et numPiecesVert peuvent tre passs en paramtres startSlidingPuzzle. Au lieu daccder limage gameover une fois le puzzle termin, vous pourriez ainsi passer au niveau suivant avec un puzzle plus grand et plus difcile recomposer.

Puzzle classique
Codes sources http://ashgameu.com A3GPU06_JigsawPuzzle.zip Les puzzles classiques se sont populariss au XVIIIe sicle. cette poque, on les construisait en bois et laide dune vritable scie (do leur nom anglais, jigsaw puzzle ou puzzle-scie). Aujourdhui, ces puzzles sont faits en carton avec une presse dcouper. Les puzzles modernes peuvent tre trs sophistiqus. Certains atteignent jusqu 24 000 pices. Les puzzles pour ordinateur se sont populariss sur le Web et dans les jeux de CD ds la n des annes 1990. Dans ce chapitre, nous allons crer un jeu de puzzle simple en utilisant des pices rectangulaires dcoupes dans une image importe.

232

ActionScript 3.0 pour les jeux

Dans notre jeu de puzzle, nous allons dcouper les pices comme pour le jeu de puzzle coulissant. Au lieu de les placer dans des endroits particuliers lcran, nous les disposerons cependant cette fois de manire compltement alatoire. Le joueur pourra alors faire librement glisser les pices lcran. La difcult principale pour la programmation de ce jeu est damener les pices se "coller" lorsque le joueur les positionne cte cte.

La plupart des jeux de puzzle prennent la peine de crer des pices de puzzle qui possdent lapparence des pices traditionnelles du jeu en carton, avec des embouts entrecroiss. Cette fonctionnalit esthtique peut tre ralise avec Flash mais uniquement en utilisant un certain nombre doutils de dessin vectoriel et de manipulation dimages bitmap. Nous nous en tiendrons ici des pices rectangulaires an de nous concentrer avant tout sur le code.

Congurer la classe
Lanimation du puzzle classique est tout fait identique celle du puzzle coulissant. Elle contient trois images et la seconde appelle startJigsawPuzzle. Les mmes instructions import sont en outre requises :
package { import ash.display.*; import ash.events.*; import ash.net.URLRequest; import ash.geom.*; import ash.utils.Timer;

Les variables numPiecesHoriz et numPiecesVert sont listes tout en haut de la classe. Ces constantes ont toutes les chances dtre modies parce que vous pouvez faire varier le nombre de pices dun puzzle classique pour crer diffrents niveaux de difcult. Nous allons crer un puzzle de 8 6 pour cet exemple :
public class JigsawPuzzle extends MovieClip { // Nombre de pices const numPiecesHoriz:int = 8; const numPiecesVert:int = 6;

La largeur et la hauteur des pices seront dcides aprs que limage aura t importe et que le programme aura pu en connatre la taille :
// Taille des pices var pieceWidth:Number; var pieceHeight:Number;

Chapitre 6

Puzzles dimages et puzzles coulissants

233

Comme pour le puzzle coulissant, nous stockons toutes les pices du puzzle sous forme dobjets dans le tableau puzzleObjects :
// Pices du jeu var puzzleObjects:Array;

Cest ce point que le jeu de puzzle classique prend un autre chemin que celui du puzzle coulissant. Au lieu de placer les pices du puzzle directement sur la scne, nous les plaons dans deux sprites. Le sprite selectedPieces contiendra toutes les pices de puzzle qui sont actuellement dplaces. Le sprite otherPieces contiendra tout le reste.

La technique qui consiste placer des groupes dobjets dafchage lintrieur de sprites est un excellent moyen de regrouper des objets similaires. Comme vous le verrez dans la suite de cet exemple, vous pouvez utiliser addChild pour dplacer un objet dafchage dun sprite un autre.

// Deux niveaux de sprite var selectedPieces:Sprite; var otherPieces:Sprite;

Lorsque le joueur slectionne une pice faire glisser, il se peut quil slectionne une unique pice ou un groupe de pices relies. Au lieu dune unique variable pointant vers la pice dplace, nous avons donc besoin dun tableau pour stocker une ou plusieurs pices :
// Pices dplaces var beingDragged:Array = new Array();

La fonction constructeur du jeu, en plus dappeler loadBitmap, cre les deux sprites dont nous avons besoin et les ajoute la scne. Lordre dans lequel ces sprites sont ajouts est important parce que nous souhaitons que le sprite selectedPieces se trouve au-dessus du sprite otherPieces :
// Chargement de limage et conguration des sprites public function startJigsawPuzzle() { // Chargement de limage bitmap loadBitmap(jigsawimage.jpg); // Conguration des deux sprites otherPieces = new Sprite(); selectedPieces = new Sprite(); addChild(otherPieces); addChild(selectedPieces); // selected on top }

234

ActionScript 3.0 pour les jeux

Chargement et dcoupage de limage


Limage est charge de la mme manire que pour le puzzle coulissant. Je ne reviendrai ainsi pas sur la fonction loadBitmap parce quelle est identique la prcdente.

Chargement de limage bitmap


La fonction loadingDone nest pas si loigne de lancienne non plus. Une fois limage importe et les valeurs pieceWidth et pieceHeight calcules, nous appelons makePuzzlePieces pour dcouper limage. Il y a une diffrence importante concernant notre manire de procder ici avec les calculs de pieceWidth et pieceHeight. La fonction Math.oor est utilise avec une division par dix pour restreindre les nombres de la largeur et de la hauteur des multiples de dix. Ainsi, si nous choisissions sept pices dans la largeur pour 400 pixels, nous aurions 57,14 pixels pour chaque pice. Nous utiliserons cependant une grille de 10 10 pour permettre aux joueurs de caler cte cte les pices plus aisment. En arrondissant cela 50, nous nous assurons que les largeurs et hauteurs saligneront sur une grille de 10 10. Nous reviendrons sur ce point lorsque nous construirons la fonction lockPieceToGrid par la suite. Pour nir, nous ajoutons deux couteurs vnementiels. Le premier est un vnement ENTER_FRAME pour le mouvement des pices durant leur dplacement. Le second est un vnement MOUSE_UP sur la scne. Il sert obtenir les vnements de relchement de souris qui signalent la n du dplacement. Lutilisateur clique sur une pice pour commencer la faire glisser et lvnement MOUSE_DOWN agit sur la pice elle-mme. Pourtant, ensuite, lorsque le dplacement est termin, nous ne pouvons pas compter sur le fait que la souris se trouve toujours sur la mme pice ni mme sur une pice quelconque. Il est possible que le joueur dplace le curseur rapidement et que celui-ci se trouve lgrement lcart des pices. Les vnements de souris sont reconduits vers la scne ; il est donc plus sr de placer un couteur MOUSE_UP sur la scne an de sassurer que nous en soyons notis.
// Fin du chargement de limage bitmap, dcoupage private function loadingDone(event:Event):void { // Crer nouvelle image pour contenir les donnes bitmap charges var image:Bitmap = Bitmap(event.target.loader.content); pieceWidth = Math.oor((image.width/numPiecesHoriz)/10)*10; pieceHeight = Math.oor((image.height/numPiecesVert)/10)*10; // Placer les donnes bitmap charges dans limage var bitmapData:BitmapData = image.bitmapData; // Dcouper en pices de puzzle makePuzzlePieces(bitmapData); // Congurer les vnements de mouvement et de relchement de souris addEventListener(Event.ENTER_FRAME,movePieces); stage.addEventListener(MouseEvent.MOUSE_UP,liftMouseUp); }

Chapitre 6

Puzzles dimages et puzzles coulissants

235

Dcouper les pices du puzzle


Le principe de base pour la dcoupe des pices est identique dans ce jeu. Nous naurons cependant pas besoin de dnir demplacement pour les pices parce quelles seront disposes de manire alatoire un peu plus tard. Une fois que les sprites sont crs, ils sont ajouts otherPieces, le sprite du dessous parmi les deux sprites que nous avons crs. Les lments puzzleObject sont aussi lgrement diffrents. Au lieu de currentLoc et homeLoc, nous naurons que loc, un objet Point qui nous indique quel endroit appartient la pice de puzzle dans le puzzle complet. 0,0 correspond par exemple la pice suprieure gauche. Nous avons aussi ajout une proprit dragOffset aux pices du puzzle. Nous lutilisons pour positionner chaque pice la distance approprie du curseur pendant le dplacement :
// Dcouper limage bitmap en pices private function makePuzzlePieces(bitmapData:BitmapData) { puzzleObjects = new Array(); for(var x:uint=0;x<numPiecesHoriz;x++) { for (var y:uint=0;y<numPiecesVert;y++) { // Crer la nouvelle image bitmap de pice de puzzle et le sprite var newPuzzlePieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth, pieceHeight)); newPuzzlePieceBitmap.bitmapData.copyPixels(bitmapData,new Rectangle (x*pieceWidth,y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0)); var newPuzzlePiece:Sprite = new Sprite(); newPuzzlePiece.addChild(newPuzzlePieceBitmap); // Placer dans le sprite du bas otherPieces.addChild(newPuzzlePiece); // Crer des objets stocker dans le tableau var newPuzzleObject:Object = new Object(); newPuzzleObject.loc = new Point(x,y); // location in puzzle newPuzzleObject.dragOffset = null; // offset from cursor newPuzzleObject.piece = newPuzzlePiece; newPuzzlePiece.addEventListener(MouseEvent.MOUSE_DOWN,clickPuzzlePiece); puzzleObjects.push(newPuzzleObject); } } // Rendre les emplacements des pices alatoires shufePieces(); }

236

ActionScript 3.0 pour les jeux

La fonction shufe slectionne des emplacements alatoires pour toutes les pices du puzzle. Nous ne nous proccupons pas de savoir si les pices se retrouvent les unes sur les autres ni comment elles sont rparties. Le but est que les pices se retrouvent comme si elles taient tombes de la bote. La Figure 6.6 prsente un exemple de cette rpartition alatoire.
Figure 6.6
Les pices du puzzle sont alatoirement disposes lcran.

// Emplacements alatoires pour les pices public function shufePieces() { // Slectionner x et y alatoires for(var i in puzzleObjects) { puzzleObjects[i].piece.x = Math.random()*400+50; puzzleObjects[i].piece.y = Math.random()*250+50; } // Verrouiller toutes les pices sur une grille 10x10 lockPiecesToGrid(); }

La dernire ligne de shufePieces appelle lockPieceToGrid. Cette fonction parcourt en boucle toutes les pices du puzzle et les dplace vers lemplacement le plus proche dune grille de 10 10. Par exemple, si une pice se trouve 43,87, elle est dplace 40,90.
lockPieceToGrid est utilise parce quil sagit dun moyen simple de permettre au joueur de rapprocher une pice dune autre sans avoir laligner au pixel prs pour que les pices se "collent" lune lautre. Normalement, si une pice se trouve ne serait-ce qu un pixel dune autre, elle ne sy colle pas.

Chapitre 6

Puzzles dimages et puzzles coulissants

237

En plaant toutes les pices sur une grille de 10 10, nous les amenons se coller parfaitement entre elles ds quelles se trouvent moins de dix pixels les unes des autres.
// Prendre toutes les pices et les aligner sur la grille 10x10 public function lockPiecesToGrid() { for(var i in puzzleObjects) { puzzleObjects[i].piece.x = 10*Math.round(puzzleObjects[i].piece.x/10); puzzleObjects[i].piece.y = 10*Math.round(puzzleObjects[i].piece.y/10); } }

Comme nous utilisons des pices de puzzle qui sont des multiples de dix en largeur et en hauteur, il est prfrable dutiliser une image source dont les dimensions sont elles-mmes des multiples de dix. Une image de 400 300, par exemple, serait utilise compltement. Une image de 284 192 perdra en revanche une partie droite et en bas pour pouvoir se limiter des pices dont les dimensions sont des multiples de dix.

Faire glisser les pices du puzzle


Lorsquun joueur clique sur une pice du puzzle, plusieurs choses doivent se passer avant que la pice ne puisse se dplacer avec le curseur. La premire consiste dterminer sur quelle pice lutilisateur a cliqu.

Trouver la pice sur laquelle le joueur a cliqu


Cette opration seffectue en parcourant en boucle les puzzleObjects jusqu trouver lun dentre eux dont la proprit piece correspond event.currentTarget. Cette pice est ensuite ajoute un tableau beingDragged vide. La valeur dragOffset de cette pice est en outre calcule en fonction de la distance entre lemplacement du clic et celui du sprite. Le sprite est dplac du sprite otherPieces du dessous vers le sprite selectedPieces du dessus. Un appel addChild suft cela. Ds lors que le joueur fait glisser la pice du puzzle, celle-ci otte au-dessus des autres, qui restent en dessous dans le sprite otherPieces :
public function clickPuzzlePiece(event:MouseEvent) { // Emplacement du clic var clickLoc:Point = new Point(event.stageX, event.stageY); beingDragged = new Array();

238

ActionScript 3.0 pour les jeux

// Trouver la pice sur laquelle lutilisateur a cliqu for(var i in puzzleObjects) { if (puzzleObjects[i].piece == event.currentTarget) { // this is it // Ajouter la liste des pices dplaces beingDragged.push(puzzleObjects[i]); // Calculer le dcalage du curseur puzzleObjects[i].dragOffset = new Point(clickLoc.x puzzleObjects[i].piece.x, clickLoc.y puzzleObjects[i].piece.y); // Dplacer du sprite du dessous celui du dessus selectedPieces.addChild(puzzleObjects[i].piece); // Trouver les autres pices colles celle-ci ndLockedPieces(i,clickLoc); break; } } }

Trouver les pices lies


Le plus intressant lorsque le joueur clique sur une pice est lappel ndLockedPieces. Cest que la pice sur laquelle le joueur a cliqu nest pas forcment isole. Elle peut tre dj jointe dautres pices du puzzle suite aux prcdents dplacements. Toutes les pices jointes celle sur laquelle lutilisateur a cliqu doivent galement tre ajoutes la liste beingDragged. Pour dterminer si une pice est colle une autre, il faut suivre une srie dtapes. Ce processus commence en crant une liste ordonne de toutes les pices lexception de celle sur laquelle lutilisateur a cliqu. Cette liste est trie en fonction de la distance par rapport la pice clique.

La commande sortOn est un puissant outil pour trier des listes dobjets. supposer que le tableau ne contienne que des objets similaires possdant chacun la mme proprit de tri, vous pouvez rapidement et aisment trier la liste. Par exemple, le tableau [{a: 4, b: 7}, {a: 3, b:12}, {a: 9, b: 17}] peut tre tri sur a en utilisant simplement myArray.sortOn("a");.

Le code qui suit cre un tableau avec les proprits dist et num pour chacun de ses lments. La premire correspond la distance entre la pice et celle sur laquelle lutilisateur a cliqu. La seconde correspond au numro de la pice dans puzzleObjects :
// Trouver les pices qui doivent se dplacer ensemble public function ndLockedPieces(clickedPiece:uint, clickLoc:Point) { // Obtenir la liste des objets puzzle trie par la distance lobjet cliqu var sortedObjects:Array = new Array();

Chapitre 6

Puzzles dimages et puzzles coulissants

239

for (var i in puzzleObjects) { if (i == clickedPiece) continue; sortedObjects.push( {dist: Point.distance(puzzleObjects[clickedPiece].loc,puzzleObjects[i].loc), num: i}); } sortedObjects.sortOn(dist ,Array.DESCENDING);

Maintenant que nous avons un tableau de pices tri, nous pouvons le parcourir en boucle et vrier chaque pice an de voir si elle est lie la pice slectionne. Pour commencer, nous vrions la position x et y de la pice. Nous souhaitons voir si la pice est correctement positionne par rapport la slection. Par exemple, si les pices font 50 de large et 50 de haut et si la pice originale se trouve 170,240, la pice directement gauche doit se trouver 120,240. La pice un cran plus loin gauche doit tre 70,240, et ainsi de suite. La Figure 6.7 prsente quelques exemples de pices qui se relient et ne se relient pas. la Figure 6.7, lexemple du haut prsente deux pices proches lune de lautre, mais pas sufsamment pour se relier. Lexemple suivant prsente des pices parfaitement positionnes, mais entre lesquelles il manque une pice de liaison. La pice gauche se trouve exactement la bonne distance de celle de droite, mais les pices ne se relient pas parce quelles ne se trouvent pas cte cte et que la pice qui doit les unir est manquante. Le troisime exemple prsente deux pices relies. Elles sont adjacentes et distance parfaite. Le quatrime est similaire, avec cette fois trois pices relies.
Figure 6.7
Les deux exemples du haut ne se relient pas, contrairement aux deux du bas.

La premire tape consiste donc voir si la pice examine est correctement place. La seconde tape consiste voir si elle est relie aux pices trouves jusque-l. Ce travail est dlgu la fonction isConnected, que nous allons examiner dans un instant.

240

ActionScript 3.0 pour les jeux

Si la pice est effectivement relie, nous pouvons lajouter la liste beingDragged, positionner sa proprit dragOffset et lajouter au sprite selectedPieces. Tout cela peut tre plac dans une boucle do an de pouvoir rpter le processus plusieurs fois. Il est possible davoir un ensemble de pices lies sous la forme dun U et que lutilisateur ait souhait saisir ce groupe par lune des extrmits du U. Cela signierait que lautre bout du U ne serait pas reconnu comme une pice lie. En revanche, si nous parcourons en boucle les pices non lies nouveau, le U sera trouv. Nous pouvons donc dnir une variable Boolean appele oneLineFound et la positionner true lorsque nous trouvons un lien. Si nous parcourons toutes les pices non lies sans trouver de lien, il faut en conclure que nous les avons toutes. Sans cela, nous continuons effectuer la boucle :
do { var oneLinkFound:Boolean = false; // Examiner chaque objet en commenant par le plus proche for(i=sortedObjects.length-1;i>=0;i--) { var n:uint = sortedObjects[i].num; // actual object number // Calculer la position relative lobjet cliqu var diffX:int = puzzleObjects[n].loc.x - puzzleObjects[clickedPiece].loc.x; var diffY:int = puzzleObjects[n].loc.y - puzzleObjects[clickedPiece].loc.y; // Voir si cet objet est correctement plac // pour tre li celui cliqu if (puzzleObjects[n].piece.x == (puzzleObjects[clickedPiece].piece.x + pieceWidth*diffX)) { if (puzzleObjects[n].piece.y == (puzzleObjects[clickedPiece].piece.y + pieceHeight*diffY)) { // Voir si cet objet est adjacent un objet dj slectionn if (isConnected(puzzleObjects[n])) { // Ajouter la liste de slection et dnir dcalage beingDragged.push(puzzleObjects[n]); puzzleObjects[n].dragOffset = new Point(clickLoc.x puzzleObjects[n].piece.x, clickLoc.ypuzzleObjects[n].piece.y); // Passer vers le sprite du haut selectedPieces.addChild(puzzleObjects[n].piece); // Lien trouv, supprimer du tableau oneLinkFound = true; sortedObjects.splice(i,1); } } } } } while (oneLinkFound); }

Chapitre 6

Puzzles dimages et puzzles coulissants

241

La cl de la fonction isConnected tient au fait que nous avons dj tri la liste de pices en fonction de leur distance vis--vis de la premire. Cest important, car nous devons progresser en nous cartant de la pice de dpart pour notre recherche de nouvelles pices relies. mesure que nous examinons chaque nouvelle pice, les pices entre la pice considre et la pice de dpart auront selon toute probabilit dj t examines et ajoutes au tableau beingDragged. Cela minimise le nombre de fois o nous aurons parcourir le tableau des pices. Par exemple, si lutilisateur a cliqu sur la pice 2,0 et que nous examinions ensuite 0,0, nous pouvons en dduire quelle nest pas relie parce que 1,0 ne fait pas partie de beingDragged. Ensuite, nous examinons 1,0 et constatons quelle est relie, mais il est trop tard pour ajouter 0,0 car nous lavons dj examine. Nous devons donc examiner 1,0 en premier parce quelle est plus proche, puis 0,0, qui est plus loigne.

Si vous pensez que ce processus est compliqu, considrez quil serait gnralement effectu en utilisant un processus de calcul appel rcursivit. On parle de rcursivit lorsquune fonction sappelle elle-mme. Cest aussi un casse-tte pour bien des dbutants en informatique. Jai donc cr les mthodes de ce chapitre an dviter spciquement la rcursivit.

Dterminer si les pices sont relies


La fonction isConnected rcupre la diffrence entre la position horizontale et verticale de la pice examine et de chaque pice dj dans beingDragged. Si elle constate quelle se trouve un cran de distance horizontalement ou verticalement (mais pas les deux la fois), elle est effectivement relie :
// Prend un objet et dtermine sil est directement ct de celui dj slectionn public function isConnected(newPuzzleObject:Object):Boolean { for(var i in beingDragged) { var horizDist:int = Math.abs(newPuzzleObject.loc.x - beingDragged[i].loc.x); var vertDist:int = Math.abs(newPuzzleObject.loc.y - beingDragged[i].loc.y); if ((horizDist == 1) && (vertDist == 0)) return true; if ((horizDist == 0) && (vertDist == 1)) return true; } return false; }

Dplacer les pices


Nous savons enn quelles pices doivent tre dplaces. Elles se trouvent maintenant toutes soigneusement dans beingDragged, qui est utilis par movePieces dans chaque image pour les repositionner toutes :
// Dplacer toutes les pices slectionnes en fonction de lemplacement de la souris public function movePieces(event:Event) {

242

ActionScript 3.0 pour les jeux

for (var i in beingDragged) { beingDragged[i].piece.x = mouseX - beingDragged[i].dragOffset.x; beingDragged[i].piece.y = mouseY - beingDragged[i].dragOffset.y; } }

Terminer le mouvement
Lorsque le joueur relche la souris, le glissement sinterrompt. Nous devons dplacer toutes les pices du sprite selectedPieces vers le sprite otherPieces. Nous appellerons aussi lockPiecesToGrid an de nous assurer quelles peuvent tre mises en correspondance avec les pices qui nont pas t dplaces.

Lorsque la fonction addChild est utilise pour ramener les pices vers le sprite otherPieces, les pices sont replaces au-dessus de toutes les autres pices cet endroit. Ce principe fonctionne bien parce que nous ottons dj au-dessus. Leffet de superposition est ainsi conserv.

// La scne envoie vnement de relchement de souris, n du dplacement public function liftMouseUp(event:MouseEvent) { // Caler toutes les pices sur la grille lockPiecesToGrid(); // Ramener les pices dans le sprite du dessous for(var i in beingDragged) { otherPieces.addChild(beingDragged[i].piece); } // Nettoyer le tableau des pices dplaces beingDragged = new Array(); // Voir si la partie est termine if (puzzleTogether()) { cleanUpJigsaw(); gotoAndStop(gameover); } }

Chapitre 6

Puzzles dimages et puzzles coulissants

243

Fin de partie
Lorsque la souris est relche, nous devons galement vrier si la partie est termine. Pour cela, nous pouvons parcourir en boucle toutes les pices du puzzle et comparer leurs positions avec celle de la premire pice en haut gauche. Si toutes se trouvent dans la position correcte par rapport cette premire, nous savons que le puzzle est termin :
public function puzzleTogether():Boolean { for(var i:uint=1;i<puzzleObjects.length;i++) { // Obtenir la position relative au premier objet var diffX:int = puzzleObjects[i].loc.x - puzzleObjects[0].loc.x; var diffY:int = puzzleObjects[i].loc.y - puzzleObjects[0].loc.y; // Voir si cet objet est correctement plac // Pour tre reli au premier if (puzzleObjects[i].piece.x != (puzzleObjects[0].piece.x + pieceWidth*diffX)) return false; if (puzzleObjects[i].piece.y != (puzzleObjects[0].piece.y + pieceHeight*diffY)) return false; } return true; }

La fonction de nettoyage obligatoire tire parti de notre systme deux sprites. Nous pouvons tout simplement les supprimer de la scne et positionner les variables qui les rfrencent null. Nous devons aussi positionner puzzleObjects et beginDragged null, ainsi que supprimer les vnements ENTER_FRAME et MOUSE_UP :
public function cleanUpJigsaw() { removeChild(selectedPieces); removeChild(otherPieces); selectedPieces = null; otherPieces = null; puzzleObjects = null; beingDragged = null; removeEventListener(Event.ENTER_FRAME,movePieces); stage.removeEventListener(MouseEvent.MOUSE_UP,liftMouseUp); }

244

ActionScript 3.0 pour les jeux

Modier le jeu
Les dveloppeurs de jeu ont trouv de nombreux moyens de rendre les puzzles sur ordinateur plus intressants que leurs quivalents physiques. Si vous vous tes dj amus crer des ltres bitmap en ActionScript, loccasion peut tre trouve dexploiter cette technique ici. Lajout de nons, dombres portes ou de biseaux aux pices peut rellement contribuer leur donner de lallure. Vous pouvez galement ajouter une rotation des pices an de compliquer le puzzle. Les pices peuvent tre pivotes de 90, 180 ou 270 degrs et doivent tre ramenes 0 pour crer le puzzle. Vous devez videmment permettre au joueur de faire pivoter les pices aprs les avoir relies, ce qui requiert du code assez complexe pour pouvoir faire pivoter en bloc les pices colles les unes aux autres. Ne vous risquez dans une telle aventure que si vous avez atteint le grade de ceinture noire en programmation ActionScript.

7
Direction et mouvement : astrodes
Au sommaire de ce chapitre :

Utiliser Math pour faire pivoter et dplacer des objets Air Raid II Space Rocks

246

ActionScript 3.0 pour les jeux

Les jeux prsents au Chapitre 5 faisaient appel un mouvement horizontal et vertical simple. Le dplacement le long de laxe horizontal ou vertical est trs facile programmer. Malheureusement, les jeux darcade se rvlent plus exigeants. Un grand nombre de jeux requirent que vous donniez la possibilit au joueur de tourner et de se dplacer. Par exemple, les jeux de conduite proposent la fois un mouvement de volant et un mouvement vers lavant. Les jeux dans lespace le requirent galement et peuvent mme permettre au joueur de tirer des projectiles dans la direction o pointe le vaisseau.

Utiliser Math pour faire pivoter et dplacer des objets


Codes sources http://ashgameu.com A3GPU07_RotationMath.zip La combinaison de la rotation et du mouvement requiert des calculs plus complexes que les simples oprations daddition, de soustraction, de multiplication et de division. Il faut utiliser des fonctions trigonomtriques fondamentales comme le sinus, le cosinus et larctangente. Si vous ntes pas fort en mathmatiques, nayez crainte : ActionScript va prendre en charge lessentiel du boulot.

Les fonctions Sin et Cos


Au Chapitre 5, nous avons utilis des variables comme dx et dy pour dnir la diffrence des positions horizontales et verticales. Un objet dont la variable dx valait 5 et la variable dy valait 0 se dplaait de 5 pixels vers la droite et de 0 vers le haut ou le bas. Comment en revanche dterminer les valeurs de dx et dy si nous ne connaissons que langle de rotation dun objet ? Supposons que le joueur ait la possibilit de faire tourner un objet, comme une voiture, dans nimporte quelle direction. Il fait pointer sa voiture lgrement vers le bas et la droite. Ensuite, il avance. Vous devez dans ce cas modier les proprits x et y de la voiture, mais vous ne connaissez que langle de rotation de la voiture.

La proprit rotation de nimporte quel objet dafchage correspond un nombre compris entre 180 et 180, cest--dire au nombre de degrs de lobjet par rapport son degr de rotation 0 dorigine. Vous pouvez modier la rotation exactement comme les valeurs demplacement x et y. La rotation peut aussi tre plus prcise, par exemple en spciant un angle de 23,76 degrs. Si vous souhaitez tourner lentement, vous pouvez donc ajouter 0,01 cette proprit chaque image ou chaque priode temporelle.

Chapitre 7

Direction et mouvement : astrodes

247

Cest ici quentrent en jeu les fonctions Math.cos et Math.sin. Elles permettent de calculer dx et dy en nutilisant quun angle. La Figure 7.1 prsente la logique mathmatique de Math.cos et Math.sin. Il sagit dun graphique de cercle. Math.cos et Math.sin nous permettent de trouver nimporte quel point sur le cercle en fonction dun angle donn.
Figure 7.1
Ce graphique dun cercle montre la relation entre un angle et lemplacement x et y dun point sur le cercle.
0,-1 4 1.5*pi 4.71 270

-1,0

0,0 1*pi 3.14 180 1.0 radians 57 degrs

1,0

.5*pi 1.57 90 2 0,1

.54,.84

Si langle en question est 0, Math.cos et Math.sin retournent respectivement 1.0 et 0.0. Nous obtenons ainsi le point numro 1, dont la valeur de x est 1.0 et la valeur de y est 0.0. Un objet ayant pivot de 0 degr se dplace donc du centre du cercle vers le point 1. Si lobjet pointe 90 degrs, Math.cos et Math.sin retournent respectivement 0.0 et 1.0. Il sagit du point numro 2. Un objet pivot de 90 degrs se dplace donc droit vers le bas. Vous pouvez voir de la mme manire o conduisent les angles de 180 et 270 degrs : le premier tout droit gauche et le second directement vers le haut.

La Figure 7.1 prsente les radians sous forme de multiples de pi, les radians bruts et les degrs. Les radians et les degrs sont deux moyens diffrents de mesurer les angles. Un cercle complet fait 360 degrs, ce qui correspond 2 pi radians. Pi vaut approximativement 3,14, de sorte que 360 degrs = 6,26 radians.

248

ActionScript 3.0 pour les jeux

ActionScript utilise la fois des degrs et des radians. Les degrs sont utiliss par la proprit rotation des objets. Les radians sont utiliss par les fonctions mathmatiques comme Math.cos et Math.sin. Nous effectuerons donc constamment la conversion dune unit de mesure vers lautre. Ces quatre directions sont faciles dterminer sans utiliser Math.cos et Math.sin. Cest cependant pour les angles intermdiaires que nous dpendons vritablement de ces fonctions trigonomtriques. Le cinquime point se trouve un angle denviron 57 degrs. On peut difcilement se passer cette fois de Math.cos et Math.sin pour dterminer quel emplacement du cercle il correspond. Le rsultat est 0.54 dans la direction x et 0.84 dans la direction y. Si un objet devait se dplacer dun pixel vers lavant tout en pointant 57 degrs, nous nous retrouverions donc au niveau du point 5.

Il est important de comprendre que ces 5 points (comme tous les autres points sur le cercle) se trouvent une distance exactement identique du centre. Le problme pour atteindre ces points concerne donc non pas la vitesse de lobjet mais la direction emprunte. Lautre point important retenir est que Math.cos et Math.sin retournent toujours des valeurs comprises entre 1,0 et 1,0. Elles partent du principe que le cercle fait 1,0 unit en rayon. Ainsi, si un objet se trouve 57 degrs et se dplace de 1,0 unit, il atteint 0.54, 0.84. Si sa vitesse est 5, nous multiplions en revanche ce rsultat par 5 et obtenons 2.70, 4.20.

Utiliser Cos et Sin pour piloter une voiture


Considrons un exemple simple pour expliquer lutilisation de ces fonctions trigonomtriques. Les animations MovingCar.a et MovingCar.as proposent un jeu de simulation de conduite lmentaire. Une voiture est place au milieu de lcran et le joueur peut utiliser les touches ches de gauche et de droite pour tourner ainsi que la touche che du haut pour avancer. La Figure 7.2 prsente la voiture lcran.
Figure 7.2
Cet exemple simple de simulation de conduite permet au joueur de tourner et davancer.

Chapitre 7

Direction et mouvement : astrodes

249

Nous utiliserons du code analogue celui du jeu Air Raid du Chapitre 5. Nous ferons appel trois variables boolennes, leftArrow, rightArrow et upArrow. Toutes ces variables seront positionnes true lorsque le joueur appuiera sur la touche correspondante et false lorsquil la relchera.

Utiliser Math pour faire pivoter et dplacer des objets


Voici le dbut de la classe, avec les couteurs et le code qui gre les touches ches. Vous remarquerez que nous navons besoin daucune instruction import supplmentaires pour utiliser les fonctions Math. Celles-ci font partie de la bibliothque ActionScript standard :
package { import ash.display.*; import ash.events.*;

public class MovingCar extends MovieClip { private var leftArrow, rightArrow, upArrow: Boolean;

public function MovingCar() {

// Dplacer chaque image addEventListener(Event.ENTER_FRAME, moveCar);

// Ragir aux vnements de touche stage.addEventListener(KeyboardEvent.KEY_DOWN,keyPressedDown); stage.addEventListener(KeyboardEvent.KEY_UP,keyPressedUp); }

// Positionner les variables de touche true public function keyPressedDown(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = true; } else if (event.keyCode == 39) { rightArrow = true; } else if (event.keyCode == 38) { upArrow = true; } }

250

ActionScript 3.0 pour les jeux

// Positionner les variables de touche false public function keyPressedUp(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = false; } else if (event.keyCode == 39) { rightArrow = false; } else if (event.keyCode == 38) { upArrow = false; } }

La fonction moveCar est appele chaque image. Elle examine chacune des valeurs boolennes et dtermine si lune dentre elles vaut true. Dans le cas des touches ches de gauche et de droite, la proprit rotation du clip car est modie et la voiture est pivote.

Vous remarquerez que nous nutilisons pas une animation temporelle cette fois. Vous inuerez donc sur la vitesse de rotation et de dplacement si vous modiez la cadence dimages de lanimation.

Si la touche che du haut est enfonce, nous appelons la fonction moveForward :


// Tourner ou avancer la voiture public function moveCar(event:Event) { if (leftArrow) { car.rotation -= 5; } if (rightArrow) { car.rotation += 5; } if (upArrow) { moveForward(); } }

Voil o nous utilisons nos calculs mathmatiques. Si la touche che du haut est enfonce, nous calculons dabord langle en radians de la voiture. Nous connaissons la rotation de la voiture, mais elle sexprime en degrs. Pour convertir les degrs en radians, nous divisons notre rsultat par 360 (le nombre de degrs dans un cercle) puis multiplions deux fois par pi (le nombre de radians dans un cercle).

Chapitre 7

Direction et mouvement : astrodes

251

Nous utiliserons souvent cette conversion. Il vaut donc la peine de la dcomposer pour plus de clart : 1. Diviser par 360 pour convertir la valeur comprise entre 0 et 360 en une valeur comprise entre 0 et 1,0. 2. Multiplier par 2 pi pour convertir la valeur comprise entre 0 et 1,0 en une valeur comprise entre 0 et 6,28.
radians = 2 * pi * (degrees / 360)

linverse, lorsque nous souhaitons effectuer la conversion des radians en degrs, nous procdons de la manire suivante : 1. Diviser par 2 pi pour convertir la valeur comprise entre 0 et 6,28 en une valeur comprise entre 0 et 1,0. 2. Multiplier par 360 pour convertir la valeur comprise entre 0 et 1,0 en une valeur comprise entre 0 et 360.
degrees = 360 * radians / (2 * pi)

Comme les degrs et les radians mesurent des angles, les valeurs se rptent elles-mmes tous les 360 degrs ou 2 pi radians. Ainsi, 0 degr quivaut 360 degrs, de mme que 90 et 450. Il en va de mme avec les valeurs ngatives. Par exemple, 270 degrs quivalent 90 degrs. En fait, la proprit rotation de nimporte quel objet retourne toujours une valeur comprise entre 180 et 180, qui quivaut pi et -pi radians.

Maintenant que nous avons langle en radians, nous le fournissons Math.cos et Math.sin pour obtenir les valeurs dx et dy pour le mouvement. Nous multiplions en outre le tout par speed, une valeur que nous avons dnie prcdemment dans la fonction. Cette action dplace la voiture de 5 pixels par image au lieu de 1 pixel par image. Pour nir, nous changeons les proprits x et y de la voiture an de la dplacer rellement :
// Claculer vitesse x et y et dplacer la voiture public function moveForward() { var speed:Number = 5.0; var angle:Number = 2*Math.PI*(car.rotation/360); var dx:Number = speed*Math.cos(angle); var dy:Number = speed*Math.sin(angle); car.x += dx; car.y += dy; } } }

252

ActionScript 3.0 pour les jeux

Jouez avec lanimation MovingCar.a. Faites tourner la voiture diffrents angles et appuyez sur la touche che du haut pour la voir avancer. Reprsentez-vous les fonctions Math.cos et Math.sin qui traduisent langle en une quantit horizontale et verticale de mouvement. Ensuite, amusez-vous. Appuyez sur les touches ches de gauche et du haut en mme temps pour faire tourner la voiture en cercle. Cela revient tourner le volant de votre voiture en mme temps que vous acclrez. La voiture continue tourner. Si lon oublie lacclration un instant, on obtient une amusante petite simulation de conduite. Au Chapitre 12, nous crerons une vritable simulation de conduite complexe au cur duquel mcanisme gureront toujours ces oprations avec Math.cos et Math.sin.

Calculer un angle partir dun emplacement


Si Math.sin et Math.cos vous permettent dobtenir les coordonnes x et y dun angle, nous devrons aussi occasionnellement obtenir un angle partir dun ensemble de coordonnes x et y. Pour cela, nous devons utiliser un calcul darctangente. La fonction ActionScript pour cela est Math.atan2. La Figure 7.3 montre comment la fonction arctangent fonctionne. Le Point 1 est situ 6,5 sur la grille. Pour trouver son angle, nous prenons la distance y et la distance x et les fournissons Math. atan2. Le rsultat sera 0,69 radian, soit environ 40 degrs.
Figure 7.3
Les angles de ces deux points peuvent tre dtermins en utilisant Math.atan2.
0,-1

-9,-3 2

-1,0

10,0 Angle 1 = Math.atan2(6,5) Angle 2 = Math.atan2(-3,-9)

5,6

Chapitre 7

Direction et mouvement : astrodes

253

Le second point se trouve 9,3. En fournissant ces valeurs Math.atan2, nous obtenons 2,82 radians, soit 162 degrs (qui quivaut 198 degrs). La fonction Math.atan2 produit un rsultat toujours compris entre 180 et 180.

Il existe aussi une fonction Math.atan. Elle prend un paramtre : le rapport entre la distance y et la distance x. Vous lutiliseriez donc de la manire suivante : Math.atan(dy/dx). Il sagit de la fonction mathmatique arctangente classique. Le problme est que vous ne savez pas si le rsultat est en avanant ou en reculant. Par exemple, 5/3 quivaut 5/3. Lun correspond 121 degrs, lautre, 60 degrs. La fonction Math.atan retourne 60 degrs dans les deux cas. La fonction Math.atan2 fournit la diffrence langle appropri.

Crons un exemple simple en utilisant une che. Vous le trouverez dans les chiers source PointingArrow.a et PointingArrow.as. La che est situe au centre de lcran (emplacement 275,200). Examinez la Figure 7.4. Vous remarquerez que le point dalignement du clip se trouve au centre de la che. Lorsque vous faites pivoter un clip, il tourne autour de ce point. Vous remarquerez en outre que la che pointe directement vers la droite. Une rotation de 0 correspond cette direction. Tout objet cr dans le seul but de pivoter doit donc tre cr en tant ainsi tourn vers la droite.
Figure 7.4
Il est plus simple de faire pivoter des objets tourns vers la droite, avec le centre du clip au centre de la rotation.

254

ActionScript 3.0 pour les jeux

Cette che pointe "vers" le curseur. Nous avons donc un point dorigine pour la che 275,200 et un point de destination de lemplacement du curseur. Comme il est facile de dplacer le curseur et de changer mouseX et mouseY, il sagit dun moyen rapide dexprimenter Math.atan2. La classe concise suivante provenant de PointingArrow.as appelle une fonction chaque image. Cette fonction calcule les valeurs dx et dy partir des distances entre le curseur et lemplacement de la che. Elle utilise ensuite Math.atan2 pour calculer langle en radians. Elle le convertit en degrs et attribue le rsultat la proprit rotation de la che :
package { import ash.display.*; import ash.events.*;

public class PointingArrow extends MovieClip {

public function PointingArrow() { addEventListener(Event.ENTER_FRAME, pointAtCursor); }

public function pointAtCursor(event:Event) { // Rcuprer lemplacement relatif de la souris var dx:Number = mouseX - pointer.x; var dy:Number = mouseY - pointer.y;

// Dterminer langle, le convertir en degrs var cursorAngle:Number = Math.atan2(dy,dx); var cursorDegrees:Number = 360*(cursorAngle/(2*Math.PI));

// Pointer vers le curseur pointer.rotation = cursorDegrees; } } }

Lorsque vous excutez cette animation, la che pointe tout moment vers le curseur (voir Figure 7.5). tout le moins, mouseX et mouseY se mettent jour, ce qui ne se produit que lorsque le curseur survole lanimation Flash. Maintenant que vous savez comment utiliser la trigonomtrie pour observer et contrler les positions et le mouvement des objets, nous pouvons les appliquer des jeux.

Chapitre 7

Direction et mouvement : astrodes

255

Figure 7.5
La che pointe vers le curseur lorsque celui-ci survole lanimation.

Combins lun lautre, ces deux exemples simples peuvent produire dintressants rsultats. Par exemple, que se passe-t-il si la voiture devait tre guide par la position de la souris vis--vis de la voiture ? Elle pointerait vers la souris et lorsque vous vous dplaceriez, savancerait vers la souris tout moment. Autrement dit, elle pourchasserait la souris. Que se passerait-il donc si le joueur devait piloter une voiture comme dans le premier exemple et quune seconde voiture pointait vers la souris et avanait par elle-mme ? La seconde voiture viendrait pourchasser la premire ! Le site http://ashgameu.com en propose un exemple.

Air Raid II
Codes sources http://ashgameu.com A3GPU07_AirRaid2.zip Dans le jeu Air Raid du Chapitre 5, vous dplaciez un canon dans un sens et dans lautre en utilisant les touches ches. Ce mouvement vous permettait de cibler diffrentes parties du ciel alors que vous tiriez vers le haut. Grce Math.sin et Math.cos, nous pouvons maintenant modier ce jeu de manire immobiliser le canon tout en lui permettant de modier son angle pour atteindre diffrentes cibles.

256

ActionScript 3.0 pour les jeux

Modier le canon
La premire chose faire est de modier le clip AAGun an davoir des canons pivotants. Nous allons sparer compltement du clip la base de la tourelle et la placer dans son propre clip, AAGunBase. Les canons resteront dans AAGun, mais nous les recentrerons an que le point de pivot se trouve au centre et que les canons pointent vers la droite (voir Figure 7.6).
Figure 7.6
Les canons doivent pointer vers la droite pour correspondre aux valeurs cos et sin.

Lide est de modier le moins possible le jeu Air Raid dorigine. Nous allons prendre les mmes valeurs pour les appuis sur les touches ches et les utiliser pour modier la proprit rotation de AAGun, au lieu de la valeur y.

Vous pourriez aussi utiliser un autre jeu de touches pour dnir la rotation (par exemple, A et S ou la touche Commande et le point). Ensuite, utilisez les touches ches pour dplacer le canon : vous aurez alors une arme qui se dplace latralement et dont les canons peuvent pivoter.

Nous dnissons encore les valeurs x et y de la mitraillette, mais galement la valeur rotation en la xant 90. Cette valeur de 90 signie que la mitraillette commence en pointant vers le haut. Nous

Chapitre 7

Direction et mouvement : astrodes

257

restreindrons la valeur de la rotation tout comme nous avons restreint le mouvement horizontal dans la premire version du jeu Air Raid. Cette fois, les valeurs seront comprises entre 170 et20 degrs, ce qui correspond un angle de 50 degrs vers la gauche ou la droite de la verticale. Voici donc notre nouveau code AAGun.as. Recherchez les lignes dans le code suivant qui impliquent la variable newRotation et la proprit rotation :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer; public class AAGun extends MovieClip { static const speed:Number = 150.0; private var lastTime:int; // Temps de lanimation public function AAGun() { // Emplacement initial de la mitraillette this.x = 275; this.y = 340; this.rotation = -90; // Mouvement addEventListener(Event.ENTER_FRAME,moveGun); } public function moveGun(event:Event) { // Calculer le temps coul var timePassed:int = getTimer()-lastTime; lastTime += timePassed; // Position actuelle var newRotation = this.rotation; // Pivoter gauche if (MovieClip(parent).leftArrow) { newRotation -= speed*timePassed/1000; } // Pivoter droite if (MovieClip(parent).rightArrow) { newRotation += speed*timePassed/1000; }

258

ActionScript 3.0 pour les jeux

// Vrier les limites if (newRotation < -170) newRotation = -170; if (newRotation > -20) newRotation = -20; // Repositionner this.rotation = newRotation; } // Supprimer de lcran et supprimer les vnements public function deleteGun() { parent.removeChild(this); removeEventListener(Event.ENTER_FRAME,moveGun); } } }

Vous remarquerez que la valeur speed xe 150 reste la mme. Il serait normalement fort probable que le passage du mouvement horizontal au mouvement de rotation requierre une adaptation de la valeur de vitesse mais, dans le cas prsent, la valeur de 150 fonctionne dans les deux cas.

Changer les balles


La classe Bullets.as doit changer pour que les balles se dplacent vers le haut en suivant un angle au lieu dtre parfaitement verticales. Le graphisme doit changer galement. Les balles doivent pointer vers la droite et tre centres sur le point dalignement. La Figure 7.7 prsente le nouveau clip Bullet. La classe doit changer an dajouter les variables de mouvement dx et dy. Ces variables seront calcules partir de langle auquel la balle a t tire, qui est un nouveau paramtre pass dans la fonction Bullet. En outre, la balle doit commencer une certaine distance du centre de la mitraillette ; dans le cas prsent, elle doit tre 40 pixels du centre. Les valeurs Math.cos et Math.sin sont toutes deux utilises pour calculer la position dorigine de la balle et calculer les valeurs dx et dy. En outre, la rotation du clip Bullet sera dnie pour correspondre la rotation de la mitraillette. Les balles commenceront donc juste au-dessus de la n du canon, en pointant vers lextrieur du canon, et continueront de se dplacer en sloignant avec le mme angle :
package { import ash.display.*; import ash.events.*; import ash.utils.getTimer;

Chapitre 7

Direction et mouvement : astrodes

259

Figure 7.7
Le nouveau clip Bullet recentre le graphisme et le fait pointer vers la droite.

public class Bullet extends MovieClip { private var dx,dy:Number; // Vitesse private var lastTime:int; public function Bullet(x,y:Number, rot: Number, speed: Number) { // Dnir position de dpart var initialMove:Number = 35.0; this.x = x + initialMove*Math.cos(2*Math.PI*rot/360); this.y = y + initialMove*Math.sin(2*Math.PI*rot/360); this.rotation = rot; // Obtenir la vitesse dx = speed*Math.cos(2*Math.PI*rot/360); dy = speed*Math.sin(2*Math.PI*rot/360); // Congurer lanimation lastTime = getTimer(); addEventListener(Event.ENTER_FRAME,moveBullet);

260

ActionScript 3.0 pour les jeux

} public function moveBullet(event:Event) { // Calculer le temps coul var timePassed:int = getTimer()-lastTime; lastTime += timePassed; // Dplacer la balle this.x += dx*timePassed/1000; this.y += dy*timePassed/1000; // La balle a dpass le haut de lcran if (this.y < 0) { deleteBullet(); } } // Supprimer la balle de la scne et de la liste public function deleteBullet() { MovieClip(parent).removeBullet(this); parent.removeChild(this); removeEventListener(Event.ENTER_FRAME,moveBullet); } } }

Changements apports AirRaid2.as


Des changements doivent tre apports la classe principale an de sadapter aux nouvelles versions de AAGun et Bullet. Considrons chaque changement. Nous allons crer une nouvelle classe appele AirRaid2.as et changer la classe du document de lanimation an de pointer sur cette classe. Noubliez pas aussi de changer la dnition de classe en haut du code en remplaant AirRaid par AirRaid2. Dans les dnitions de variable de la classe, nous devons ajouter le nouveau clip AAGunBase ainsi que conserver le clip AAGun :
private var aagun:AAGun; private var aagunbase:AAGunBase;

Chapitre 7

Direction et mouvement : astrodes

261

Dans startAirRaid, nous devons tenir compte du fait que la mitraillette est maintenant reprsente par deux clips. AAGunBase ne possde pas de classe soi : nous devons faire correspondre sa position avec celle de AAGun.

Vous pouvez aussi supprimer compltement AAGunBase en utilisant un graphisme diffrent ou caler les canons sur un graphisme qui fait partie de larrire-plan.

// Crer la mitraillette aagun = new AAGun(); addChild(aagun); aagunbase = new AAGunBase(); addChild(aagunbase); aagunbase.x = aagun.x; aagunbase.y = aagun.y;

Le seul autre changement ncessaire doit tre opr dans la fonction reBullet. Cette fonction doit passer la rotation de la mitraillette la classe Bullet, an quelle connaisse la direction dans laquelle tirer la balle. Nous ajouterons donc ce troisime paramtre de manire le faire correspondre au troisime paramtre dans la fonction Bullet qui cre une nouvelle balle :
var b:Bullet = new Bullet(aagun.x,aagun.y,aagun.rotation,300);

Si nous crions ce jeu de toutes pices, nous pourrions mme ne pas inclure les deux premiers paramtres qui se rfrent la position de la mitraillette. Puisque celle-ci ne se dplace plus, elle restera en effet la mme position. Comme nous avions dj du code qui soccupait de relier le point de dpart de la balle la position de la mitraillette, nous pouvons le conserver ici et tirer parti du fait quun seul emplacement dans le code sert dterminer la position de la mitraillette.

Nous sommes parvenus changer la classe AirRaid2.as. En fait, si nous navions pas eu besoin pour des raisons esthtiques dajouter AAGunBase lanimation, nous naurions eu que ce dernier changement oprer dans AirRaid2.as. Ce point illustre bien la exibilit dActionScript lorsque vous utilisez une classe diffrente pour chaque lment mouvant. Nous avons maintenant un jeu Air Raid II entirement transform qui utilise une mitraillette pivotante mais stationnaire.

262

ActionScript 3.0 pour les jeux

Space Rocks
Codes sources http://ashgameu.com A3GPU07_SpaceRocks.zip

Lun des jeux vido les plus classiques de tous les temps sest appel Asteroids. Ce jeu darcade vectoriel a t commercialis par Atari en 1979. Ces graphismes se limitaient de simples lignes unies, il mettait des sons plus que rudimentaires et lon pouvait aisment tricher et gagner. Malgr cela, il se rvlait tout fait captivant. Le joueur contrlait un petit vaisseau. Vous pouviez tourner, tirer et voler dans lcran. Face vous se trouvaient quelques grands astrodes qui se dplaaient vitesse variable et dans des directions alatoires. Vous pouviez les faire clater en astrodes plus petits en tirant dessus. Les astrodes les plus petits disparaissaient lorsque lon tirait dessus. Si un astrode vous touchait, vous perdiez une vie. Nous allons construire un jeu qui fonctionne selon le mme principe, avec un vaisseau, des astrodes et des missiles. Nous utiliserons mme lune des fonctionnalits les plus avances du jeu original : un bouclier de protection.

lments du jeu et conception


Avant de commencer, nous devons dcider quoi ressemblera notre jeu Space Rocks. Nous naurons pas besoin de crer un document de conception complet, mais quelques listes nous aideront rester concentrs mesure que nous construisons le jeu de toutes pices. Les lments du jeu sont un vaisseau, des astrodes et des missiles. Chacune des variantes est prsente la Figure 7.8. Examinons les capacits du vaisseau. Voici une liste de ce que le vaisseau peut faire :

Il apparat au milieu de lcran au dpart, en position stationnaire. Il tourne gauche lorsque la touche che de gauche est enfonce. Il tourne droite lorsque la touche che de droite est enfonce. Il acclre vers lavant lorsque la touche che du haut est enfonce. Il se dplace en fonction de sa vlocit. Il gnre un bouclier lorsque la touche Z est enfonce.

Chapitre 7

Direction et mouvement : astrodes

263

Figure 7.8
Les lments du jeu pour Space Rocks.
Vaisseau avec propulseur

Bouclier et vaisseau

Astrodes : trois variantes de trois tailles diffrentes

Icnes de bouclier et de vaisseau

Le vaisseau lance un missile. Voici ce que font les missiles :

Ils sont crs lorsque le joueur appuie sur la barre despace. Leur vlocit et leur position sont dtermines par lemplacement et la rotation du vaisseau. Ils se dplacent en fonction de leur vlocit.

Voici maintenant ce que font les astrodes : Ils ont une vlocit et une vitesse de dpart alatoires. Ils se dplacent en fonction de leur vlocit. Ils pivotent avec une vitesse de rotation dnie. Ils possdent trois tailles diffrentes : grande, moyenne et petite.

Les collisions font lessentiel de ce jeu. Il en existe deux types : celle du missile avec un astrode et celle dun astrode avec le vaisseau. Lorsquun missile et un astrode entrent en collision, lastrode dorigine est supprim. Sil sagissait dun astrode version "grand", deux astrodes de taille moyenne apparaissent au mme emplacement. Sil sagissait dune version "moyen", deux "petits" astrodes apparaissent au mme emplacement. Les petits astrodes se contentent de disparatre, sans tre remplacs par aucun. Le missile est galement supprim aprs la collision. Lorsquun astrode entre en collision avec le vaisseau, il se comporte comme si un missile lavait touch. Le vaisseau est pour sa part supprim. Le joueur a trois vies. Sil ne sagit pas de la dernire vie du joueur, celui-ci obtient un autre vaisseau qui apparat au centre de lcran au bout de deux secondes.

264

ActionScript 3.0 pour les jeux

Si le joueur dtruit tous les astrodes et quil nen reste plus lcran, le niveau est termin. Aprs un court dlai, une nouvelle vague dastrodes apparat, un peu plus rapide que la prcdente.

Dans la plupart des versions des annes 1970 du jeu Asteroids, il existait une vitesse maximale limite des astrodes. Cette contrainte permettait aux joueurs experts de jouer indniment ou tout le moins jusqu ce que le patron de la salle de jeux les en chasse ou que maman leur rappelle trs fermement quil tait lheure de dner.

Parmi les autres actions possibles du joueur, lune consiste gnrer un bouclier. Lappui sur la touche Z cre un bouclier autour du vaisseau pendant 3 secondes. Ce bouclier permet au vaisseau de traverser des astrodes sans se dtruire. Les joueurs nont cependant que trois boucliers par vie et doivent les utiliser avec prcaution. Lun des aspects importants du jeu tient ce que le vaisseau et les astrodes bouclent leur parcours autour de lcran lorsquils se dplacent. Si lun dentre eux quitte lcran gauche, il rapparat droite. Sil le quitte par le bas, il rapparat en haut. Les missiles, pour leur part, vont jusquau bord de lcran puis disparaissent.

Dnir les graphismes


Il nous faut un vaisseau, des astrodes et un missile pour crer ce jeu. Le vaisseau est llment le plus complexe. Il doit avoir un tat normal, un tat avec un propulseur activ et une animation dexplosion lorsquil est touch. Il a aussi besoin dun bouclier qui le recouvre de temps autre. La Figure 7.9 prsente un clip du vaisseau qui explose. Plusieurs images sont utilises. La premire correspond au vaisseau sans les gaz et la seconde, au vaisseau avec ses gaz activs. Le reste des images consiste en une courte animation dexplosion. Les boucliers correspondent en ralit un autre clip plac lintrieur du clip du vaisseau. Ce clip est prsent la fois sur la premire (sans gaz) et la deuxime (avec gaz) image. Nous dsactiverons le bouclier en attribuant la valeur false sa proprit visible. Lorsque nous en aurons besoin, nous le ractiverons en attribuant cette fois la valeur true la proprit visible. Les astrodes correspondront en fait une srie de clips. Il en existera trois pour les trois tailles : Rock_Big, Rock_Medium et Rock_Small. Les trois clips auront leur tour trois images reprsentant les variantes des astrodes. Nous viterons ainsi que tous les astrodes se ressemblent. La Figure 7.10 prsente le clip Rock_Big dans lequel vous remarquerez les images-cls qui contiennent les trois variantes dans le scnario. Le missile est llment le plus simple. Il sagit simplement dun petit point jaune. Deux autres clips sont aussi utiliss : ShipIcon et ShieldIcon. Il sagit de versions miniatures du vaisseau et du bouclier. Nous les utiliserons pour afcher le nombre de vaisseaux et de boucliers restants.

Chapitre 7

Direction et mouvement : astrodes

265

Figure 7.9
Dans cette image du vaisseau, le bouclier et les gaz sont tous deux activs.

Figure 7.10
Chaque clip des astrodes inclut trois variantes de la mme taille.

266

ActionScript 3.0 pour les jeux

Le scnario principal est congur de la manire habituelle : trois images, avec celle du milieu qui appelle startSpaceRocks. Il nous suft maintenant de crer le code ActionScript pour donner vie au jeu.

Congurer la classe
Nous allons placer tout le code dans un chier de classe SpaceRocks.as. Il sagira du plus long chier de classe que nous ayons cr jusque-l. Lavantage li au fait dutiliser un unique chier de classe tient ce que tout le code se trouve conserv dans un endroit. Linconvnient tient ce quil peut devenir long et difcile manier. Pour simplier les choses, nous allons dcomposer le code en plus petites sections, chacune traitant un lment de lcran diffrent. Pour commencer, examinons cependant la dclaration de classe. La classe requiert les importations habituelles pour grer lensemble des objets et structures :
package { import ash.display.*; import ash.events.*; import ash.text.*; import ash.utils.getTimer; import ash.utils.Timer; import ash.geom.Point;

Un certain nombre de constantes permettent dajuster le comportement et la difcult du jeu. Les vitesses sont toutes mesures avec des units cales sur les millisecondes, de sorte que la vitesse de rotation du vaisseau (shipRotationSpeed) est une vitesse plutt rapide de 0,1/1000 soit 100 degrs par seconde. Les missiles se dplacent 200 pixels par seconde et les propulseurs acclrent le vaisseau 150 pixels par seconde par seconde.

La vitesse est mesure en unit de distance par temps, par exemple en pixels par seconde. Lacclration dsigne la variation de vitesse au cours du temps : le nombre de pixels par seconde dont la vitesse change par seconde. Voil pourquoi il faut crire : pixels par seconde par seconde.

La vitesse des astrodes dpend du niveau. Elle est de 0,03 plus 0,02 fois le niveau, soit 0,05 pour le premier niveau, 0,07 pour le second, etc.

Chapitre 7

Direction et mouvement : astrodes

267

Nous dnissons aussi le rayon du vaisseau, qui est peu prs de forme ronde. Nous utiliserons ce rayon pour dtecter les collisions au lieu de nous appuyer sur la fonction hitTestObject :
public class SpaceRocks extends MovieClip { static const shipRotationSpeed:Number = .1; static const rockSpeedStart:Number = .03; static const rockSpeedIncrease:Number = .02; static const missileSpeed:Number = .2; static const thrustPower:Number = .15; static const shipRadius:Number = 20; static const startingShips:uint = 3;

Aprs les constantes, nous devons dnir une srie de variables congurer par la suite. Voici les variables qui contiennent des rfrences au vaisseau, aux astrodes et aux missiles :
// Objets du jeu private var ship:Ship; private var rocks:Array; private var missiles:Array;

Ensuite, nous avons un minuteur danimation qui sera utilis pour mettre au pas tous les mouvements :
// Minuteur danimation private var lastTime:uint;

Les touches ches de gauche, de droite et du haut seront consignes par les valeurs boolennes suivantes :
// Touches ches private var rightArrow:Boolean = false; private var leftArrow:Boolean = false; private var upArrow:Boolean = false;

La vlocit du vaisseau sera dcompose en deux valeurs de vitesse :


// Vlocit du vaisseau private var shipMoveX:Number; private var shipMoveY:Number;

Nous avons deux minuteurs. Lun correspond au dlai entre le moment o le joueur perd un vaisseau et celui o le suivant apparat. Nous lutiliserons aussi pour imposer un dlai avant lafchage du prochain ensemble dastrodes lorsque tous les astrodes ont t dtruits. Lautre correspond la dure dactivation du bouclier :
// Minuteurs private var delayTimer:Timer; private var shieldTimer:Timer;

268

ActionScript 3.0 pour les jeux

Une variable gameMode peut se voir attribuer les valeurs "play" ou "delay". Lorsquelle vaut "delay", nous ncoutons pas les appuis sur les touches du joueur. Une autre variable boolenne nous indique si le bouclier est actif, auquel cas le joueur ne peut tre touch par les astrodes :
// Mode du jeu private var gameMode:String; private var shieldOn:Boolean;

Lensemble de variables suivant concerne les boucliers et les vaisseaux. Les deux premires consignent le nombre de vaisseaux et de boucliers. Les deux suivantes sont des tableaux contenant des rfrences aux icnes afches lcran qui convoient ces informations au joueur :
// Vaisseaux et boucliers private var shipsLeft:uint; private var shieldsLeft:uint; private var shipIcons:Array; private var shieldIcons:Array;

Le score est stock dans gameScore. Il est afch dans un champ texte que nous allons crer nomm scoreDisplay. La variable gameLevel tient le registre du nombre densembles dastrodes qui ont t dtruits :
// Score et niveau private var gameScore:Number; private var scoreDisplay:TextField; private var gameLevel:uint;

Pour nir, nous avons deux sprites dans lesquels nous placerons tous les lments du jeu. Le premier est gameObjects et correspondra notre sprite principal. Nous placerons cependant les icnes de vaisseau et de bouclier ainsi que le score dans le sprite scoreObjects an de les conserver part :
// Sprites private var gameObjects:Sprite; private var scoreObjects:Sprite;

Dmarrer le jeu
La fonction constructeur commencera par congurer les sprites. Il est important que les instructions addChild apparaissent dans cet ordre an que les icnes et le score restent au-dessus des lments du jeu :
// Dmarrer le jeu public function startSpaceRocks() {

Chapitre 7

Direction et mouvement : astrodes

269

// Congurer les sprites gameObjects = new Sprite(); addChild(gameObjects); scoreObjects = new Sprite(); addChild(scoreObjects); gameLevel

est positionn 1 et shipsLeft, 3 daprs les constantes dnies prcdemment.

gameScore est x zro galement. Ensuite, un appel createShipIcons et createScoreDisplay

congure le tout. Nous les examinerons sous peu :


// Rinitialiser les objets de score gameLevel = 1; shipsLeft = startingShips; gameScore = 0; createShipIcons(); createScoreDisplay();

Il nous faut trois couteurs, comme pour les jeux Air Raid. Lun sera un appel de fonction dimage gnral, les deux autres concerneront les appuis sur les touches :
// Congurer les couteurs addEventListener(Event.ENTER_FRAME,moveGameObjects); stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);

Pour lancer le jeu, nous positionnons gameMode "delay" et shieldOn false, puis crons un tableau pour stocker les missiles et appelons deux fonctions pour lancer le jeu. La premire cre le premier ensemble dastrodes et la seconde cre le premier vaisseau. Comme ces deux fonctions seront par la suite appeles par des minuteurs vnementiels, nous devons inclure null en paramtre an de remplir lemplacement quutilisera la valeur du minuteur vnementiel par la suite :
// Dmarrer gameMode = delay; shieldOn = false; missiles = new Array(); nextRockWave(null); newShip(null); }

270

ActionScript 3.0 pour les jeux

Objets dafchage du score et de ltat


Le premier grand groupe de fonctions a affaire au nombre de vaisseaux que possde le joueur, au nombre de boucliers restants et au score du joueur. Ces nombres safchent dans les trois coins de lcran. Le score apparat sous forme de texte dans le coin suprieur droit. Le nombre de vaisseaux est indiqu en afchant de zro trois icnes dans le coin infrieur gauche. Le nombre de boucliers est indiqu en afchant de zro trois icnes de bouclier dans le coin infrieur droit. La Figure 7.11 prsente le jeu au dbut lorsque les trois lments sont prsents.
Figure 7.11
Le score est afch dans le coin suprieur droit, le nombre de vies, en bas gauche et le nombre de boucliers, en bas droite.

Les deux fonctions suivantes soccupent de crer les icnes de vaisseau et de bouclier en plaant en boucle les trois lments lcran. Ces lments sont ajouts leurs tableaux respectifs an que lon puisse y faire rfrence et les supprimer par la suite :
// Dessiner le nombre de vaisseaux restants public function createShipIcons() { shipIcons = new Array(); for(var i:uint=0;i<shipsLeft;i++) { var newShip:ShipFs:Icon = new ShipIcon(); newShip.x = 20+i*15; newShip.y = 375; scoreObjects.addChild(newShip); shipIcons. push(newShip); } }

Chapitre 7

Direction et mouvement : astrodes

271

Voici une fonction similaire pour les icnes de bouclier :


// Dessiner le nombre de boucliers restants public function createShieldIcons() { shieldIcons = new Array(); for(var i:uint=0;i<shieldsLeft;i++) { var newShield:ShieldIcon = new ShieldIcon(); newShield.x = 530-i*15; newShield.y = 375; scoreObjects.addChild(newShield); shieldIcons.push(newShield); } }

Nous aurions aussi pu viter dutiliser des icnes et nous servir simplement de champs texte pour afcher le nombre de vaisseaux et de boucliers restants. Il faudrait moins de code, mais leffet serait visuellement moins intressant.

Pour lafchage du score, nous devons crer un nouveau champ texte et dnir ses proprits. Nous utiliserons aussi une variable temporaire TextFormat pour dnir le format texte par dfaut (defaultTextFormat) du champ :
// Placer le score numrique en haut droite public function createScoreDisplay() { scoreDisplay = new TextField(); scoreDisplay.x = 500; scoreDisplay.y = 10; scoreDisplay.width = 40; scoreDisplay.selectable = false; var scoreDisplayFormat = new TextFormat(); scoreDisplayFormat.color = 0xFFFFFF; scoreDisplayFormat.font = "Arial"; scoreDisplayFormat.align = "right"; scoreDisplay.defaultTextFormat = scoreDisplayFormat; scoreObjects.addChild(scoreDisplay); updateScore(); }

272

ActionScript 3.0 pour les jeux

la n de createScoreDisplay, nous appelons immdiatement updateScore pour placer un 0 dans le champ, car il sagit de la valeur de gameScore ce point. La fonction updateScore sera cependant utilise plus tard aussi, chaque fois que nous avons un changement dans le score :
// Nouveau score afcher public function updateScore() { scoreDisplay.text = String(gameScore); }

Lorsquil est temps de supprimer un vaisseau ou un bouclier, nous devons dpiler un lment des tableaux shipIcons ou shieldIcons et utiliser removeChild sur scoreObjects pour effacer licne :
// Supprimer une icne de vaisseau public function removeShipIcon() { scoreObjects.removeChild(shipIcons.pop()); }

// Supprimer une icne de bouclier public function removeShieldIcon() { scoreObjects.removeChild(shieldIcons.pop()); }

Nous devons aussi ajouter des fonctions qui parcourent en boucle et suppriment toutes les icnes. Nous en avons besoin la n du jeu. Pour les boucliers, nous en avons besoin la n dune vie. Nous souhaitons donner au joueur trois boucliers chaque nouveau vaisseau. Nous supprimerons donc les icnes de bouclier et recommencerons lorsque cela se produira :
// Supprimer le reste des icnes de vaisseau public function removeAllShipIcons() { while (shipIcons.length > 0) { removeShipIcon(); } }

// Supprimer le reste des icnes de bouclier public function removeAllShieldIcons() { while (shieldIcons.length > 0) { removeShieldIcon(); } }

Chapitre 7

Direction et mouvement : astrodes

273

Mouvement du vaisseau et entre du joueur


Lensemble des fonctions suivantes concerne le vaisseau. La premire fonction cre un nouveau vaisseau. Le reste des fonctions concerne son dplacement.

Crer un nouveau vaisseau


La fonction newShip est appele au dbut du jeu mais galement 2 secondes aprs la disparition dun prcdent vaisseau. Lors de ces occasions subsquentes, un minuteur se chargera de cet appel. Ce minuteur se verra passer un TimerEvent. Nous nen aurons cependant pas besoin. Lors des deuxime, troisime et quatrime fois o la fonction est appele, le prcdent vaisseau existe dj. Il aura jou son animation dexplosion. la n de cette animation, une commande stop met en pause le clip la dernire image qui est vide. Le vaisseau est donc toujours l, mais il est invisible. Nous vrions que le vaisseau ne vaut pas null puis le supprimons et lenlevons avant de poursuivre.

Dans dautres jeux, il peut tre souhaitable de supprimer le vaisseau ds que lanimation dexplosion est termine. Dans ce cas, vous pouvez simplement placer un rappel la classe principale lintrieur du scnario du vaisseau. Cet appel peut se trouver dans la dernire image de lanimation, an dindiquer que lanimation est termine et que lobjet peut tre supprim.

// Crer un nouveau vaisseau public function newShip(event:TimerEvent) { // Si le vaisseau existe, le supprimer if (ship != null) { gameObjects.removeChild(ship); ship = null; }

Ensuite, nous vrions sil reste des vaisseaux. Sil nen reste pas, la partie est termine :
// Plus de vaisseau if (shipsLeft < 1) { endGame(); return; }

Un nouveau vaisseau est cr, positionn et ramen la premire image qui contient un vaisseau normal gaz teints. La rotation est xe 90, de manire pointer vers le haut. Nous devons aussi supprimer le bouclier.

274

ActionScript 3.0 pour les jeux

Ensuite, nous pouvons ajouter le clip au sprite gameObjects :


// Crer, positionner et ajouter le nouveau vaisseau ship = new Ship(); ship.gotoAndStop(1); ship.x = 275; ship.y = 200; ship.rotation = -90; ship.shield.visible = false; gameObjects.addChild(ship);

La vlocit du vaisseau est stocke dans les variables shipMoveX et shipMoveY. Maintenant que nous avons cr un vaisseau, gameMode peut passer de "delay" "play" :
// Conguration des proprits du vaisseau shipMoveX = 0.0; shipMoveY = 0.0; gameMode = "play";

Pour chaque nouveau vaisseau, nous rinitialisons le nombre de boucliers 3. Ensuite, nous devons dessiner les trois petites icnes de bouclier en bas de lcran :
// Mettre en place les boucliers shieldsLeft = 3; createShieldIcons();

Lorsque le joueur perd un vaisseau et quun nouveau vaisseau apparat, il existe une possibilit quil rapparaisse au milieu de lcran exactement au moment o un astrode passe cet endroit. Pour viter que cela ne pose un problme, nous pouvons utiliser les boucliers. En activant ces derniers, le joueur est assur de ne pas tre victime dune collision pendant 3 secondes.

Les jeux darcade de ce type vitaient ce problme lorigine en attendant simplement que le milieu de lcran devienne relativement vide avant de crer un nouveau vaisseau. Vous pourriez procder de la mme manire, en vriant la distance entre chaque astrode et le nouveau vaisseau et en imposant un dlai supplmentaire de 2 secondes quand un projectile est trop proche.

Notez que nous ne souhaitons procder ainsi que si ce nest pas la premire fois que le vaisseau apparat. Au dbut du jeu, les astrodes feront aussi leur premire apparition et se trouveront des emplacements prdnis situs lcart du centre.

Chapitre 7

Direction et mouvement : astrodes

275

Lorsque nous appelons ici startShield, nous passons la valeur true an dindiquer quil sagit dun bouclier "gratuit". Il nest pas dcompt dans la rserve des trois boucliers du joueur :
// Toutes les vies sauf la premire commencent par un bouclier gratuit if (shipsLeft != startingShips) { startShield(true); } }

Grer lentre clavier


Les deux fonctions suivantes soccupent des appuis sur les touches. Comme avec Air Raid, nous surveillons les touches ches de gauche et de droite. Nous nous occupons aussi de la touche che du haut. Nous ragissons galement la barre despace et la touche Z. Dans le cas de la touche che du haut, nous activons le propulseur et allumons les gaz en demandant au vaisseau de passer la seconde image qui fait apparatre des ammes larrire. La barre despace appelle newMissile et la touche Z, startShield :
// Enregistrer les appuis sur les touches public function keyDownFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = true; } else if (event.keyCode == 39) { rightArrow = true; } else if (event.keyCode == 38) { upArrow = true; // Allumer les gaz if (gameMode == play) ship.gotoAndStop(2); } else if (event.keyCode == 32) { // Barre despace newMissile(); } else if (event.keyCode == 90) { // z startShield(false); } }

La fonction keyUpFunction coupe les gaz lorsque le joueur relche la touche che du haut :
// Enregistrer les relchements de touches public function keyUpFunction(event:KeyboardEvent) { if (event.keyCode == 37) { leftArrow = false;

276

ActionScript 3.0 pour les jeux

} else if (event.keyCode == 39) { rightArrow = false; } else if (event.keyCode == 38) { upArrow = false; // teindre les gaz if (gameMode == play) ship.gotoAndStop(1); } }

Mouvement du vaisseau
Toutes les fonctions danimation de ce jeu prennent timeDiff en paramtre. Cette variable quivaut la variable timePassed des autres jeux avec animation mais, au lieu que chaque fonction danimation calcule son propre temps coul, nous le calculons dans une unique fonction appele moveGameObjects qui appelle ensuite les trois fonctions danimation et leur passe cette valeur. Tous les objets se dplacent alors en parfaite synchronisation les uns avec les autres. Le mouvement du vaisseau peut concerner son pivotement, son dplacement vers lavant ou les deux. Si les touches ches de gauche ou de droite sont enfonces, le vaisseau tourne en fonction de timeDiff et de la constante shipRotationSpeed. Si la touche che du haut est enfonce, le vaisseau sacclre. Nous utilisons alors Math.cos et Math.sin pour dterminer linuence que possde la pousse sur le mouvement horizontal et vertical du vaisseau :
// Animer le vaisseau public function moveShip(timeDiff:uint) { // Pivoter et acclrer if (leftArrow) { ship.rotation -= shipRotationSpeed*timeDiff; } else if (rightArrow) { ship.rotation += shipRotationSpeed*timeDiff; } else if (upArrow) { shipMoveX += Math.cos(Math.PI*ship.rotation/180)*thrustPower; shipMoveY += Math.sin(Math.PI*ship.rotation/180)*thrustPower; }

Ensuite, la position du vaisseau est mise jour en fonction de la vlocit :


// Dplacer ship.x += shipMoveX; ship.y += shipMoveY;

Chapitre 7

Direction et mouvement : astrodes

277

Lune des particularits qui font tout lattrait de ce jeu tient la manire dont le vaisseau peut quitter lcran dun ct et rapparatre de lautre. Voici le code qui se charge de grer ce mcanisme. Un grand nombre de paramtres cods en dur pourraient ici tre spars et dnis sous forme de constantes au dbut du script, mais le code est ainsi plus simple lire et comprendre. Lcran fait 550 pixels de large et 400 de haut. Nous souhaitons que le vaisseau boucle non pas ds linstant o il atteint le bord de lcran mais juste au moment o on le perd de vue. 570, le vaisseau revient ainsi 590, ce qui le place 20. Comme il se dplacerait vers la droite pour cela, il ne restera pas hors de vue.

Les 20 pixels supplmentaires que nous ajoutons aux bords de lcran sont une zone morte du jeu. Vous ne pouvez pas voir les objets qui y transitent, et les missiles ne sy trouvent pas non plus parce quils disparaissent ds quils atteignent le bord de lcran. Vous devez vous assurer que cette zone ne soit pas trop grande. Sans cela, de petits astrodes se dplaant verticalement ou horizontalement pourraient disparatre pendant un certain temps. Vous pourriez aussi aisment y perdre votre vaisseau. linverse, si vous la rendez trop troite, les objets sembleront se dsintgrer sur un bord de lcran et rapparatre miraculeusement sur lautre.
// Faire le tour de lcran if ((shipMoveX > 0) && (ship.x > 570)) { ship.x -= 590; } if ((shipMoveX < 0) && (ship.x < -20)) { ship.x += 590; } if ((shipMoveY > 0) && (ship.y > 420)) { ship.y -= 440; } if ((shipMoveY < 0) && (ship.y < -20)) { ship.y += 440; } }

Grer les collisions du vaisseau


Lorsque le vaisseau est atteint par un astrode, il doit exploser. Pour cela, il passe la troisime image intitule explode. La fonction removeAllShieldIcons supprime les icnes de bouclier de lcran. Un minuteur est ensuite congur pour appeler newShip au bout de 2 secondes.

278

ActionScript 3.0 pour les jeux

Le nombre de vaisseaux est rduit dune unit et removeShipIcon est appele an de supprimer une icne de lcran :
// Supprimer le vaisseau public function shipHit() { gameMode = "delay"; ship.gotoAndPlay("explode"); removeAllShieldIcons(); delayTimer = new Timer(2000,1); delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE,newShip); delayTimer.start(); removeShipIcon(); shipsLeft--; }

Levez vos boucliers !


Le bouclier est une partie un peu part du vaisseau. Il gure sous la forme dun clip lintrieur du clip Ship. Pour lactiver, il nous suft donc de positionner sa proprit visible true. Un minuteur est dni pour le dsactiver au bout de 3 secondes. Entre-temps, shieldOn est positionn true an que toutes les collisions avec les astrodes soient ignores.

Le bouclier est en fait un graphisme semi-transparent qui laisse transparatre le vaisseau. Un paramtre alpha est appliqu aux couleurs utilises dans le dgrad du bouclier. Aucun code ActionScript nest requis pour cela : le graphisme est simplement dessin de cette manire.

La fonction startShield opre galement une vrication au dbut et la n de la fonction. Au dbut, elle sassure quil reste des boucliers au joueur. Ensuite, elle sassure que le bouclier nest pas dj activ. la n, elle vrie le paramtre freeShield. Sil vaut false, nous rduisons le nombre de boucliers disponibles dune unit et mettons jour lcran :
// Activer le bouclier pour 3 secondes public function startShield(freeShield:Boolean) { if (shieldsLeft < 1) return; // Aucun bouclier restant if (shieldOn) return; // Bouclier dj activ // Activer le bouclier et congurer le minuteur pour sa dsactivation ship.shield.visible = true;

Chapitre 7

Direction et mouvement : astrodes

279

shieldTimer = new Timer(3000,1); shieldTimer.addEventListener(TimerEvent.TIMER_COMPLETE,endShield); shieldTimer.start(); // Mettre jour le nombre de boucliers restants if (!freeShield) { removeShieldIcon(); shieldsLeft--; } shieldOn = true; }

Lorsque le minuteur sarrte, le bouclier est de nouveau rendu invisible et la variable boolenne shieldOne est positionne false :
// Dsactiver le bouclier public function endShield(event:TimerEvent) { ship.shield.visible = false; shieldOn = false; }

Astrodes
Viennent ensuite les fonctions qui grent les astrodes. Nous avons des fonctions pour crer des astrodes, pour les supprimer et pour les dtruire.

Crer de nouveaux astrodes


Il existe trois tailles dastrodes. Quand newRock est appele, elle lest avec le paramtre rockType qui spcie la taille du nouvel astrode. Au dbut du jeu, tous les astrodes sont crs avec loption de taille "Big". Dans la suite du jeu, nous crons en revanche des paires dastrodes chaque frappe de missile qui utilisent les tailles "Medium" et "Small". Il existe pour chaque taille un rockRadius correspondant de 35, 20 et 10. Nous utiliserons ces nombres pour dtecter les collisions par la suite.
dx

Pour nir de crer lastrode, une vlocit verticale est choisie en obtenant des valeurs alatoires pour et dy. Nous rcuprons aussi une valeur alatoire pour dr, la vitesse de rotation.

Lun des autres lments alatoires est la variation des astrodes. Chaque clip contient trois images reprsentant chacune un astrode daspect diffrent.

280

ActionScript 3.0 pour les jeux

Il serait intressant de calculer dynamiquement le rayon de chaque astrode en testant les clips des astrodes eux-mmes mais, ce stade, nous nen avons encore cr aucun et ne pouvons donc pas obtenir ces valeurs. Du reste, ce ne sont pas ces valeurs que nous souhaitons. Elles inclueraient en effet les points les plus loigns dans les graphismes, or nous souhaitons un nombre plus rduit qui donne une meilleure approximation du rayon global des astrodes.

Le tableau rocks est constitu dobjets de donnes incluant une rfrence au clip rock, les valeurs dx, dy et dr, ainsi que rockType (la taille) et rockRadius :
// Crer un unique astrode dune taille spcique public function newRock(x,y:int, rockType:String) { // Crer la nouvelle classe approprie var newRock:MovieClip; var rockRadius:Number; if (rockType == "Big") { newRock = new Rock_Big(); rockRadius = 35; } else if (rockType == "Medium") { newRock = new Rock_Medium(); rockRadius = 20; } else if (rockType == "Small") { newRock = new Rock_Small(); rockRadius = 10; } // Choisir une apparence alatoire newRock.gotoAndStop(Math.ceil(Math.random()*3)); // Dnir position de dpart newRock.x = x; newRock.y = y; // Dnir mouvement et rotation alatoires var dx:Number = Math.random()*2.0-1.0; var dy:Number = Math.random()*2.0-1.0; var dr:Number = Math.random(); // Ajouter la scne et la liste rocks gameObjects.addChild(newRock); rocks.push({rock:newRock, dx:dx, dy:dy, dr:dr, rockType:rockType, rockRadius: rockRadius}); }

Chapitre 7

Direction et mouvement : astrodes

281

Crer des vagues dastrodes


Au dbut du jeu et chaque nouvelle vague dastrodes, nous appelons la fonction suivante pour crer quatre gros astrodes, tous espacs de manire gale lcran. La Figure 7.12 montre les positions des astrodes au tout dbut du jeu.
Figure 7.12
Les quatre astrodes sont placs 100 pixels de distance des cts et des bords suprieur et infrieur de lcran.

Nous souhaitons donner gameMode la valeur play. Sil sagit de la premire vague dastrodes, nous avons dj donn gameMode la valeur play. Sil ne sagit pas de la premire vague, le gameMode doit avoir t modi avec la valeur delay dans la fonction shipHit. Nous lui attribuons donc ici la valeur play par scurit :
// Crer quatre astrodes public function nextRockWave(event:TimerEvent) { rocks = new Array(); newRock(100,100,"Big"); newRock(100,300,"Big"); newRock(450,100,"Big"); newRock(450,300,"Big"); gameMode = play; }

282

ActionScript 3.0 pour les jeux

La fonction newRockWave cre chaque fois quatre astrodes au mme emplacement. Vous pourriez cependant souhaiter compliquer cette fonction en vriant la valeur de gameLevel et en utilisant des vagues de six astrodes au lieu de quatre pour les niveaux suprieurs trois ou quatre. Voil un bon moyen de pimenter le jeu. Il serait possible aussi dajouter des astrodes de petite et moyenne tailles ds le dbut de certains niveaux.

Dplacer les astrodes


Pour dplacer les astrodes, nous devons simplement examiner chacun des astrodes et obtenir les valeurs dans chaque objet du tableau rocks. La position est modie en fonction des valeurs dx et dy. La rotation est modie en fonction de la valeur dr. Comme avec le vaisseau, nous devons faire passer les astrodes dun ct de lcran au ct oppos. Le code qui gre ce mouvement est pratiquement le mme, les astrodes tant autoriss sortir de 20 pixels en dehors de lcran avant de faire leur boucle et de rapparatre ct oppos en ajoutant 40 pixels (20 de chaque ct) la largeur de lcran :
// Animer tous les astrodes public function moveRocks(timeDiff:uint) { for(var i:int=rocks.length-1;i>=0;i--) {

// Dplacer les astrodes var rockSpeed:Number = rockSpeedStart + rockSpeedIncrease*gameLevel; rocks[i].rock.x += rocks[i].dx*timeDiff*rockSpeed; rocks[i].rock.y += rocks[i].dy*timeDiff*rockSpeed;

// Faire pivoter les astrodes rocks[i].rock.rotation += rocks[i].dr*timeDiff*rockSpeed;

// Faire boucler les astrodes if ((rocks[i].dx > 0) && (rocks[i].rock.x > 570)) { rocks[i].rock.x -= 590; } if ((rocks[i].dx < 0) && (rocks[i].rock.x < -20)) { rocks[i].rock.x += 590; } if ((rocks[i].dy > 0) && (rocks[i].rock.y > 420)) { rocks[i].rock.y -= 440;

Chapitre 7

Direction et mouvement : astrodes

283

} if ((rocks[i].dy < 0) && (rocks[i].rock.y < -20)) { rocks[i].rock.y += 440; } } }

Collisions des astrodes


Lorsquun astrode est touch, la fonction rockHit dcide ce quelle doit en faire. Dans le cas dun gros astrode, deux astrodes moyens sont crs la place. Dans le cas dun astrode moyen, deux petits astrodes le remplacent. Ils commencent au mme emplacement que lancien, mais obtiennent des vitesses de rotation et des directions alatoires. Dans ces deux cas et dans le cas o cest un petit astrode qui est touch, lastrode dorigine est supprim :
public function rockHit(rockNum:uint) { // Crer deux astrodes plus petits if (rocks[rockNum].rockType == "Big") { newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Medium"); newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Medium"); } else if (rocks[rockNum].rockType == "Medium") { newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Small"); newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Small"); } // Supprimer lastrode dorigine gameObjects.removeChild(rocks[rockNum].rock); rocks.splice(rockNum,1); }

Missiles
Les missiles sont crs lorsque le joueur appuie sur la barre despace. La fonction newMissile utilise la position du vaisseau pour lancer le missile et rcupre en outre la rotation du vaisseau an de dterminer la direction du missile. Le missile nest cependant pas positionn au centre du vaisseau ; il se trouve un shipRadius de distance de ce centre, dans la mme direction que celle que suivra le missile en sloignant. Ce rglage vite que les missiles paraissent provenir du centre du vaisseau.

284

ActionScript 3.0 pour les jeux

Nous utilisons ici, pour simplier les missiles, une astuce qui consiste les reprsenter par un rond. Nous navons ainsi pas besoin de faire pivoter le missile selon un angle particulier. Les objets ronds possdent la bonne apparence quelle que soit la direction dans laquelle ils se dplacent.

Nous tenons le registre de tous les missiles avec le tableau missiles :


// Crer un nouveau missile public function newMissile() { // Crer var newMissile:Missile = new Missile();

// Dnir direction newMissile.dx = Math.cos(Math.PI*ship.rotation/180); newMissile.dy = Math.sin(Math.PI*ship.rotation/180);

// Placement newMissile.x = ship.x + newMissile.dx*shipRadius; newMissile.y = ship.y + newMissile.dy*shipRadius;

// Ajouter la scne et au tableau gameObjects.addChild(newMissile); missiles.push(newMissile); }

Lorsque les missiles se dplacent, nous utilisons la constante missileSpeed et timeDiff pour dterminer le nouvel emplacement. Les missiles ne reviennent pas de lautre ct de lcran lorsquils en sortent comme les astrodes et le vaisseau. Ils disparaissent simplement en quittant lcran :
// Animer les missiles public function moveMissiles(timeDiff:uint) { for(var i:int=missiles.length-1;i>=0;i--) { // Dplacer missiles[i].x += missiles[i].dx*missileSpeed*timeDiff; missiles[i].y += missiles[i].dy*missileSpeed*timeDiff; // Le bord de lcran est pass

Chapitre 7

Direction et mouvement : astrodes

285

if ((missiles[i].x < 0) | | (missiles[i].x > 550) | | (missiles[i].y < 0) | | (missiles[i].y > 400)) { gameObjects.removeChild(missiles[i]); missiles.splice(i,1); } } }

Lorsquun missile touche un astrode, il est galement supprim avec un appel missileHit :
// Supprimer le missile public function missileHit(missileNum:uint) { gameObjects.removeChild(missiles[missileNum]); missiles.splice(missileNum,1); }

Nous supprimons les missiles dans moveMissiles laide dun bloc de code spar au lieu dappeler missileHit, par prcaution pour lavenir. Les deux vnements se produisent dans des circonstances diffrentes. Si nous souhaitons que quelque chose de particulier se produise lorsque le missile atteint une cible, nous pourrons le placer dans missileHit. Or nous ne souhaiterions pas dans ce cas que le mme vnement se produise lorsque le missile a juste quitt lcran.

Contrle du jeu
Jusque-l, nous avons eu trois fonctions danimation : moveShip, moveRocks et moveMissiles. Toutes trois sont appeles par la fonction danimation principale, moveGameObjects. son tour, cette dernire est appele par lvnement ENTER_FRAME que nous avons congur prcdemment.

Dplacer les objets du jeu


La fonction moveGameObjects calcule le temps coul (timePassed) comme le faisait Air Raid et transmet cette valeur ces trois fonctions. Notez que moveShip nest appele que si gameMode ne possde pas la valeur "delay". Pour nir, moveGameObjects appelle checkCollisions, qui est un organe central de notre jeu :
public function moveGameObjects(event:Event) { // Calculer le temps coul et animer var timePassed:uint = getTimer() - lastTime;

286

ActionScript 3.0 pour les jeux

lastTime += timePassed; moveRocks(timePassed); if (gameMode != delay) { moveShip(timePassed); } moveMissiles(timePassed); checkCollisions(); }

Vrier les collisions


La fonction checkCollisions ralise les calculs critiques. Elle parcourt en boucle tous les astrodes et tous les missiles et vrie si certains sont entrs en collision les uns avec les autres. Le rockRadius des astrodes est utilis pour dterminer les collisions. Ce mcanisme est plus rapide que lapproche qui consiste appeler hitTestPoint. Sil y a une collision, les fonctions rockHit et missileHit sont appeles pour se charger des deux extrmits de la collision. Si un astrode et un missile doivent tre supprims ce stade, il est important quaucun dentre eux ne soit plus test pour les collisions possibles avec dautres objets. Chacune des deux boucles for imbriques se voit donc attribuer une tiquette. Ltiquette offre un moyen de spcier laquelle des boucles for une commande break ou continue est destine. Dans le cas prsent, nous souhaitons continuer dans la boucle rockloop, qui correspond la boucle externe des boucles imbriques. Une simple commande break amnerait le code continuer tester lastrode pour voir sil est entr en collision avec le vaisseau. Comme lastrode nexiste plus, cette opration produirait une erreur :
// Rechercher les missiles entrs en collision avec des astrodes public function checkCollisions() { // Parcourir les astrodes en boucle rockloop: for(var j:int=rocks.length-1;j>=0;j--) { // Parcourir les missiles en boucle missileloop: for(var i:int=missiles.length-1;i>=0;i--) { // Dtection de collision if (Point.distance(new Point(rocks[j].rock.x,rocks[j].rock.y), new Point(missiles[i].x,missiles[i].y)) < rocks[j].rockRadius) {

// Suppression de lastrode et du missile rockHit(j); missileHit(i);

Chapitre 7

Direction et mouvement : astrodes

287

// Mise jour du score gameScore += 10; updateScore();

// Nous sortons de cette boucle et reprenons la suivante continue rockloop; } }

Chaque astrode est test an de voir sil entre en collision avec le vaisseau. Pour commencer, nous devons nous assurer que nous ne nous trouvons pas dans lintervalle entre la disparition du vaisseau et sa rapparition. Nous devons aussi nous assurer que le bouclier est dsactiv. Si le vaisseau est touch, nous appelons les deux fonctions shipHit et rockHit :
// Vrier si un astrode heurte le vaisseau if (gameMode == "play") { if (shieldOn == false) { // only if shield is off if (Point.distance(new Point(rocks[j].rock.x,rocks[j].rock.y), new Point(ship.x,ship.y)) < rocks[j].rockRadius+shipRadius) {

// Supprimer le vaisseau et lastrode shipHit(); rockHit(j); } } } }

Une fois que checkCollisions a termin, elle examine rapidement le nombre dastrodes lcran. Si tous les astrodes ont t supprims, un minuteur est congur pour lancer une nouvelle vague au bout de 2 secondes. gameLevel est incrmente dune unit, an que les astrodes suivants soient plus rapides. gameMode se voit aussi attribuer la valeur "betweenlevels". Cela signie que la vrication ne sera pas ralise avant que lastrode ne rapparaisse, mais le joueur reste libre de dplacer le vaisseau :
// Plus dastrode, changer le mode du jeu et en recrer if ((rocks.length == 0) && (gameMode == "play")) { gameMode = betweenlevels; gameLevel++; // Avancer dun niveau delayTimer = new Timer(2000,1);

288

ActionScript 3.0 pour les jeux

delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE,nextRockWave); delayTimer.start(); } }

Terminer la partie
Si le vaisseau a t touch et quil nen reste plus, la partie est termine et la fonction endGame est appele. Celle-ci soccupe du nettoyage habituel et conduit lanimation la troisime image du scnario :
public function endGame() { // Supprimer tous les objets et couteurs removeChild(gameObjects); removeChild(scoreObjects); gameObjects = null; scoreObjects = null; removeEventListener(Event.ENTER_FRAME,moveGameObjects); stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpFunction);

gotoAndStop(gameover); }

Modier le jeu
La fonctionnalit du bouclier dans ce jeu ne gure pas dans le jeu Asteroids original. On la trouve cependant dans ses variantes ultrieures et dans bien dautres jeux du mme genre. Le jeu dorigine contient pour sa part une autre fonctionnalit qui permet de faire disparatre le vaisseau pour le faire rapparatre un emplacement alatoire. Si cela conduit souvent le joueur sa perte, cest aussi un bon va-tout pour celui qui ne parvient pas schapper dune situation o il se trouve pris en tau. Lajout de cette fonctionnalit est trs simple : il suft dinclure un autre appui de touche dans keyDownFunction puis dattribuer des valeurs x et y alatoires au vaisseau. Le jeu pourrait tre amlior avec des lments simples comme des sons ou dautres animations. La amme du propulseur pourrait tre anime en remplaant le graphisme actuel par un symbole graphique en boucle dans le clip. Aucun code ActionScript nest requis pour cela. Vous pourriez galement ajouter des vies supplmentaires : cest une fonctionnalit bien courante dans ce type de jeu. Dnissez simplement un palier pour le score, comme 1 000, et ajoutez une unit shipsLeft. Vous devrez retracer les icnes des vaisseaux ce moment, et pourquoi pas mettre un son pour signaler lattribution du bonus.

Chapitre 7

Direction et mouvement : astrodes

289

La plupart des jeux de ce genre sur le Web ne sont pas des jeux dans lespace. Ce concept gnral peut tre utilis des ns ducatives ou commerciales en remplaant les astrodes par des objets spciques. Par exemple, il peut sagir de noms et de verbes, le joueur ntant suppos tirer que sur les noms. Il pourrait aussi sagir de bouts de papier ramasser que vous tes cens nettoyer. Une modication simple pourrait consister oublier compltement les missiles et faire des collisions entre le vaisseau et les astrodes un objectif en soi. Vous pourriez ainsi rcolter des objets au lieu de tirer dessus. Il pourrait notamment tre intressant de devoir rcolter certains objets et en viter dautres.

8
Les casual games : Match Three
Au sommaire de ce chapitre :

Classe rutilisable : PointBursts Match Three

292

ActionScript 3.0 pour les jeux

leurs dbuts, les jeux vido taient simples et amusants. Lun des plus populaires dentre eux tait ainsi un petit jeu de puzzle appel Tetris. Les graphismes 3D ont ensuite repouss les limites de cet univers et permis de crer des mondes virtuels en camra subjective et de vritables jeux de rle en ligne. Les jeux de puzzle ont cependant connu un regain de succs au dbut de cette dcennie avec les jeux en ligne gratuits et les jeux tlchargeables. On baptise en anglais cette catgorie de jeux les casual games.

Lappellation casual game nest pas toujours trs claire. Wikipdia en propose la dnition suivante : "une catgorie de jeu lectronique ou de jeu dordinateur ciblant le grand public". Cette dnition est un peu large. On pourrait plus prcisment parler de "jeux Match Three", car la plupart des sites Web qui proposent des casual games vendent principalement des jeux comme Match Three. Bon nombre des jeux de ce livre correspondent cependant la dnition plus large. En fait, de nombreux puzzles dimages et de mots sont souvent vendus avec Match Three.

La plupart des casual games sont des jeux de puzzle daction, autrement dit des jeux qui combinent un puzzle avec une sorte de mouvement ou un dlai dans le temps pour pimenter le jeu. Le jeu Match Three est de loin le plus courant des casual games. Prs de la moiti des jeux sur les sites Web populaires de casual games sont des variantes de Match Three. Dans ce chapitre, nous allons dcouvrir comment crer lexplosion de points, un effet spcial populaire utilis dans les casual games. Ensuite, nous construirons un jeu Match Three classique.

Classe rutilisable : Point Bursts


Codes sources http://ashgameu.com A3GPU08_PointBurst.zip Aux dbuts des jeux darcades, lorsque le joueur russissait une action, il se voyait attribuer des points. Cela na pas chang. Ce qui a chang, cest le moyen de le signaler. Dans les jeux darcade anciens, on ne voyait le score se modier quau coin de lcran. Malheureusement, le plus souvent, ce nest pas cet endroit que lon regarde et lon ne peut sy reporter quune fois le feu de laction bien pass. Il est donc judicieux que les jeux aient volu et afchent le nombre de points gagns directement lemplacement de lcran o laction se produit.

Chapitre 8

Les casual games : Match Three

293

Vous dcouvrirez cela dans pratiquement tous les casual games pour le Web. La Figure 8.1 prsente mon jeu Gold Strike juste au moment o le joueur clique sur des lingots dor pour marquer des points. Vous pouvez voir le texte "30" lemplacement o se trouvaient auparavant les lingots dor. Ces nombres grossissent en un instant puis disparaissent. Ils sont juste assez longtemps lcran pour faire remarquer au joueur le nombre de points quil a marqus.
Figure 8.1
Le nombre de points marqus safche directement lendroit o se situe laction.

Jappelle cet effet une explosion de points. Il est si courant et je lutilise si frquemment quil sagit dun excellent exemple de classe spciale qui peut tre cre puis rutilise dans de nombreux jeux.

Dvelopper la classe PointBurst


La classe PointBurst.as doit tre aussi autonome que possible. En fait, notre but est de pouvoir utiliser une explosion de points avec une seule ligne de code dans le jeu. La classe elle-mme a donc besoin de soccuper de crer le texte et le sprite, de lanimer et de supprimer le tout par elle-mme une fois quelle a termin.

Notre classe PointBurst pourra tre utilise avec une seule ligne, mais ne ncessitera aucun lment dans la bibliothque de lanimation principale lexception dune police utilise pour lafchage des points.

La Figure 8.2 prsente une version tale dans le temps de ce que nous allons crer. Lexplosion de points doit commencer par un score taille rduite qui grossit progressivement. En outre, lopacit doit tre au dpart de 100 % avant de seffacer progressivement. Tout cela doit se passer en moins de 1 seconde.

294

ActionScript 3.0 pour les jeux

Figure 8.2
Cette reprsentation synchronique montre gauche le dbut de lexplosion de points puis chacun des stades de lanimation de gauche droite.

Dnition de la classe
Pour une classe si petite, il nous faut tout de mme quatre instructions import. Nous utiliserons le minuteur pour contrler lanimation de lexplosion de points, bien quune autre option et t den faire une animation temporelle en utilisant des vnements ENTER_FRAME :
package { import ash.display.*; import ash.events.*; import ash.text.*; import ash.utils.Timer;

Bien que la classe PointBurst ralise lanimation, il sagit toujours dun sprite, parce quelle ne requiert pas plusieurs images. Au lieu de cela, nous allons mettre lchelle et dnir la proprit alpha du sprite chaque tape. Nous utiliserons des constantes statistiques pour dterminer le type de police, sa taille et sa couleur :
public class PointBurst extends sprite { // Style de texte static const fontFace:String = "Arial"; static const fontSize:int = 20; static const fontBold:Boolean = true; static const fontColor:Number = 0xFFFFFF;

Nous avons aussi plusieurs constantes associes lanimation. animSteps et animStepTime dterminent la dure et la uidit de lanimation. Par exemple, avec dix tapes et 50 millisecondes entre les tapes, nous obtenons une animation de 500 millisecondes. Cest encore le cas avec vingt tapes de 25 millisecondes, mais nous avons dans ce cas deux fois plus dtapes et donc une animation plus uide :
// Animation static const animSteps:int = 10; static const animStepTime:int = 50;

Lchelle de lanimation change durant lanimation. Les deux constantes suivantes dnissent les points de dpart et de n du changement dchelle :
static const startScale:Number = 0; static const endScale:Number = 2.0;

Chapitre 8

Les casual games : Match Three

295

Aprs les constantes viennent plusieurs variables qui contiennent des rfrences aux lments dans lexplosion de points. Lune contient le champ texte et une autre, le Sprite qui encapsulera le champ texte. Une troisime contient une rfrence la scne ou au clip o nous souhaitons placer lexplosion de points. La dernire variable contient une rfrence lobjet Timer :
private var tField:TextField; private var burstSprite:Sprite; private var parentMC:MovieClip; private var animTimer:Timer;

La fonction PointBurst
La ligne de code que nous utilisons pour crer un PointBurst (explosion de points) sert crer un nouvel objet PointBurst. Cette opration appelle son tour la fonction PointBurst, qui accepte des paramtres. Ces paramtres sont notre seul moyen de communiquer lobjet PointBurst des informations cls telles que lemplacement de lexplosion de points et le texte afcher.

Le paramtre pts est un Object car nous souhaitons pouvoir accepter nimporte quel type de variable : int, Number ou String. Nous convertirons cela par la suite en String, car cest ce que requiert la proprit text du TextField.

Le premier paramtre de PointBurst est un clip, mc. Il sagira dune rfrence la scne ou un autre clip ou un sprite auquel lexplosion de points sera ajoute avec addChild :
public function PointBurst(mc:MovieClip, pts:Object, x,y:Number) {

La premire chose que la fonction doit faire est de crer un objet TextFormat attribuer au TextField que nous allons crer par la suite. Nous utiliserons pour cela des constantes de mise en forme que nous aurons dnies antrieurement. La fonction devra aussi dnir lalignement du champ en choisissant center :
// Cration du format de texte var tFormat:TextFormat = new TextFormat(); tFormat.font = fontFace; tFormat.size = fontSize; tFormat.bold = fontBold; tFormat.color = fontColor; tFormat.align = center;

296

ActionScript 3.0 pour les jeux

Ensuite, nous crons le TextField lui-mme. En plus de positionner selectable false, nous devons demander au champ dutiliser des polices incorpores au lieu de polices systme. Nous souhaitons en effet dnir la transparence du texte, ce qui ne peut tre ralis que si le texte utilise des polices incorpores. Pour centrer le texte dans le sprite que nous allons crer ensuite, nous positionnons la proprit autoSize du champ TextFieldAutoSize.CENTER. Ensuite, nous positionnons les proprits x et y linverse de la moiti de la largeur et de la hauteur. Cela place le centre du texte au point 0,0 :
// Crer le champ texte tField = new TextField(); tField.embedFonts = true; tField.selectable = false; tField.defaultTextFormat = tFormat; tField.autoSize = TextFieldAutoSize.CENTER; tField.text = String(pts); tField.x = -(tField.width/2); tField.y = -(tField.height/2);

Nous crons maintenant un sprite pour contenir le texte et agir comme objet dafchage principal pour lanimation. Nous dnissons lemplacement de ce sprite en lui attribuant les valeurs x et y passes dans la fonction. Nous dnissons lchelle du sprite en lui attribuant la constante startScale. Nous xons la proprit alpha zro. Ensuite, nous ajoutons le sprite au clip mc, cest--dire au sprite pass dans la fonction :
// Cration du sprite burstSprite = new Sprite(); burstSprite.x = x; burstSprite.y = y; burstSprite.scaleX = startScale; burstSprite.scaleY = startScale; burstSprite.alpha = 0; burstSprite.addChild(tField); parentMC = mc; parentMC.addChild(burstSprite);

Maintenant que lobjet PointBurst sest manifest comme sprite, nous devons simplement dmarrer un minuteur pour lancer lanimation au cours des 500 prochaines millisecondes. Ce minuteur appelle rescaleBurst plusieurs fois, puis appelle removeBurst une fois que cest ni :
// Dmarrer lanimation animTimer = new Timer(animStepTime,animSteps); animTimer.addEventListener(TimerEvent.TIMER, rescaleBurst); animTimer.addEventListener(TimerEvent.TIMER_COMPLETE, removeBurst); animTimer.start(); }

Chapitre 8

Les casual games : Match Three

297

Animer lexplosion de points


Lorsque le Timer appelle rescaleBurst, nous devons dnir les proprits dchelle et lalpha du sprite. Pour commencer, nous calculons percentDone en fonction du nombre dtapes de Timer qui se sont coules et du nombre total dtapes animSteps. Ensuite, nous appliquons cette valeur aux constantes startScale et endScale pour obtenir lchelle actuelle. Nous pouvons utiliser percentDone pour dnir la proprit alpha, mais nous souhaitons inverser la valeur an daller de 1.0 0.0.

La proprit alpha dnit la transparence dun sprite ou dun clip. 1.0, lobjet se comporte normalement, les couleurs unies tant 100 % dopacit. Cela signie cependant que les zones non remplies, comme celles en dehors de la forme des caractres, sont quant elles transparentes. .5 ou 50 % de transparence, les zones habituellement opaques comme les contours et les remplissages des caractres partagent les pixels avec les couleurs sous-jacentes.

// Animer public function rescaleBurst(event:TimerEvent) { // quel point en sommes-nous ? var percentDone:Number = event.target.currentCount/animSteps; // Dnir chelle et alpha burstSprite.scaleX = (1.0-percentDone)*startScale + percentDone*endScale; burstSprite.scaleY = (1.0-percentDone)*startScale + percentDone*endScale; burstSprite.alpha = 1.0-percentDone; }

Lorsque le Timer a ni, il appelle removeBurst. Cette fonction soccupe de tout pour que le PointBurst se dbarrasse lui-mme, sans aucune action de la part de lanimation principale ou de la classe de lanimation. Une fois que le champ texte tField est supprim du sprite burstSprite, burstSprite est supprim de parentMC. Ensuite, les deux sont positionns null an de les nettoyer de la mmoire. Pour nir, la commande delete est utilise pour faire compltement disparatre lobjet PointBurst.

On ne peut pas dire avec certitude que toutes les lignes de removeBurst sont ncessaires. Normalement, vous tes cens effacer toutes les rfrences un objet pour le supprimer, mais linstruction delete supprime le PointBurst, qui son tour doit supprimer les deux variables galement. La suppression de burstSprite peut aussi permettre de supprimer tField. Il nexiste pas de moyen de le tester et, lheure o ces lignes sont crites, il ne semble pas exister de document technique qui indique ce que le lecteur Flash fait spciquement dans ce cas. Il est donc prfrable dutiliser une fonction qui sassure que tout est correctement supprim.

298

ActionScript 3.0 pour les jeux

// Termin, se supprimer public function removeBurst(event:TimerEvent) { burstSprite.removeChild(tField); parentMC.removeChild(burstSprite); tField = null; burstSprite = null; delete this; }

Utiliser PointBurst dans une animation


Vous aurez besoin de deux choses avant de crer un nouvel objet PointBurst dans une animation. La premire est de crer une nouvelle police dans la bibliothque de lanimation. La seconde est dindiquer Flash o trouver votre chier PointBurst.as.

Ajouter une police une animation


Il faut une police parce que nous utilisons la proprit alpha pour la transparence du texte et cela ne peut se faire quavec une police incorpore dans la bibliothque. Pour crer une police incorpore, vous devez utiliser le menu droulant du panneau Bibliothque et choisir Nouvelle police. Ensuite, slectionnez la police souhaite et nommez-la. Le nom de llment dans la bibliothque nimporte pas vraiment. Jutilise gnralement le nom de la police, comme Arial dans cet exemple. La Figure 8.3 prsente la bote de dialogue Proprits des symboles de police.
Figure 8.3
La bote de dialogue Proprits des symboles de police vous permet de choisir une police ajouter la bibliothque.

Il ne sagit l que dune tape. Ltape numro deux, qui na rien dvident, consiste sassurer que cette police est incluse pour quActionScript puisse lutiliser. Pour cela, slectionnez la police dans la bibliothque, puis cliquez du bouton droit ou cliquez avec la touche Ctrl enfonce sur Mac et slectionnez loption Liaison pour faire apparatre la bote de dialogue Proprits de liaison prsente la Figure 8.4.

la diffrence des autres types de symboles, les options de liaisons napparaissent pas dans la bote de dialogue Proprits gnrales du symbole. Elles ne safchent que dans la bote de dialogue Proprits de liaison.

Chapitre 8

Les casual games : Match Three

299

Figure 8.4
La bote de dialogue Proprits de liaison vous permet de spcier une classe pour la police dans la bibliothque.

Le nom de classe attribu la police nimporte pas. Vous pouvez en outre ignorer la bote de dialogue qui vous indique quaucune dnition de classe nest trouve. Il nen faut aucune.

Emplacements des classes


Pour nos exemples, nous naurons rien faire pour indiquer Flash o rechercher le chier de classe PointBurst.as, car celui-ci se trouve au mme emplacement que lanimation Flash. En revanche, si vous souhaitez utiliser le mme chier de classe PointBurst.as dans plusieurs projets, vous devez le placer un endroit auquel peuvent accder toutes les animations et leur indiquer chacune o le trouver. Il existe deux moyens de procder. Le premier consiste ajouter un chemin de classe aux prfrences de Flash. Il se peut que vous souhaitiez crer un dossier pour contenir toutes les classes que vous utilisez rgulirement. Ensuite, accdez la section ActionScript des Prfrences Flash. Cliquez sur le bouton Paramtres ActionScript 3.0 et ajoutez un dossier lemplacement que consulte Flash pour les chiers de classe.

Vous pouvez aussi utiliser tout simplement lemplacement par dfaut pour les classes de bibliothque, soit le dossier Classes, qui se trouve dans le dossier Flash du dossier Program Files ou Applications. Pour ma part, jvite cette approche car je mefforce de conserver tous les documents que je cre en dehors du dossier Applications, an de ny conserver que linstallation par dfaut de mes applications.

Lautre mthode pour indiquer une animation o trouver un chier de classe qui ne se trouve pas dans le mme rpertoire que lanimation consiste choisir Fichier > Paramtres de publication, puis cliquer sur le bouton Paramtres ct de la slection de la version ActionScript. Vous pourrez alors ajouter un nouveau chemin de classe pour cette seule animation.

300

ActionScript 3.0 pour les jeux

En rsum, il existe quatre moyens pour une animation Flash daccder un chier de classe : 1. Placer le chier de classe dans le mme dossier que lanimation. 2. Ajouter lemplacement de classe dans les prfrences de Flash. 3. Placer le chier de classe dans le dossier Classes de lapplication Flash. 4. Ajouter lemplacement de la classe dans les Paramtres de publication de lanimation.

Crer une explosion de points


Une fois que la police se trouve dans la bibliothque et que lanimation a accs la classe, il suft dune ligne pour crer une explosion de points. Voici un exemple :
var pb:PointBurst = new PointBurst(this,100,50,75);

Ce code cre une explosion de points qui afche le nombre 100. Lexplosion se produit aux coordonnes 50,75. Lanimation dexemple PointBurstExample.a et sa classe PointBurstExample.as correspondante prsentent un exemple lgrement plus volu. Il cre une explosion de points partout o vous cliquez :
package { import ash.display.*; import ash.events.*; public class PointBurstExample extends MovieClip { public function PointBurstExample() { stage.addEventListener(MouseEvent.CLICK,tryPointBurst); } public function tryPointBurst(event:MouseEvent) { var pb:PointBurst = new PointBurst(this,100,mouseX,mouseY); } } }

Maintenant que nous disposons dun fragment de code indpendant qui soccupe de cet effet spcial assez complexe, nous pouvons passer notre jeu suivant en sachant quil pourra inclure lexplosion de points en ne levant presque pas le petit doigt pour programmer.

Chapitre 8

Les casual games : Match Three

301

Match Three
Codes sources http://ashgameu.com A3GPU08_MatchThree.zip Si Match Three est le casual game le plus courant et le plus populaire, il ne lest pas devenu parce quil est facile programmer. En ralit, bien des aspects de ce jeu requirent des techniques assez sophistiques. Nous allons galement examiner ce jeu lment par lment.

Jouer Match Three


Si vous tes parvenu ne pas jouer des jeux Match Three au cours des quelques dernires annes, voici le principe du jeu. Une grille de huit par huit contient une disposition alatoire de six ou sept pices de jeu. Vous pouvez cliquer sur nimporte quelle paire de pices adjacentes pour tenter de les permuter. Si la permutation produit un alignement horizontal ou vertical de trois pices identiques ou plus, elle est autorise. Les pices qui salignent sont supprimes et celles qui se trouvent au-dessus tombent dans lemplacement libr. De nouvelles pices viennent du haut an de remplir le trou laiss par la disparition des pices alignes. Voil tout. Cest cette simplicit du jeu qui le rend si populaire. Le jeu se poursuit jusqu ce que la grille parvienne un tat o aucune permutation nest plus possible. La Figure 8.5 prsente mon jeu Newtons Nightmare, un jeu Match Three plutt classique.
Figure 8.5
Le jeu Newtons Nightmare utilise des pommes pour ce jeu de Match Three.

302

ActionScript 3.0 pour les jeux

Le jeu Bejeweled, aussi appel Diamond Mine, est rput avoir lanc la fureur du Match Three.

Vue densemble des fonctionnalits du jeu


La squence dvnement dans le jeu suit douze tapes. Chaque tape prsente un d diffrent en termes de programmation.

1. Crer une grille alatoire


Une grille de huit par huit avec une disposition alatoire de sept lments diffrents est cre au dbut du jeu.

2. Vrier les correspondances


Il existe quelques restrictions concernant ce que la grille de dpart peut contenir. La premire tient ce quelle ne peut inclure de lignes avec des alignements de trois lments. Il faut que le joueur luimme trouve la premire correspondance permettant de crer un alignement.

3. Vrier les dplacements


La seconde restriction pour la grille initiale tient ce quil doit exister au moins un dplacement valide. Autrement dit, le joueur doit pouvoir permuter deux lments et obtenir une correspondance.

4. Le joueur slectionne deux pices


Les pices doivent tre adjacentes lune lautre horizontalement ou verticalement et la permutation doit produire une correspondance.

5. Les pices sont permutes


En gnral, une animation montre les deux pices qui se dplacent an doccuper leurs emplacements respectifs.

6. Rechercher des correspondances


Une fois quune permutation est effectue, il faut examiner la grille la recherche de nouvelles correspondances pour les alignements horizontaux et verticaux. Si aucune correspondance nest trouve, la permutation doit tre annule.

Chapitre 8

Les casual games : Match Three

303

7. Attribuer des points


Si une correspondance est trouve, des points doivent tre attribus.

8. Supprimer les correspondances


Les pices impliques dans une correspondance doivent tre supprimes de la grille.

9. Faire tomber les pices du dessus


Les pices situes au-dessus de celles qui ont t supprimes doivent tomber pour remplir lespace laiss vide.

10. Ajouter de nouvelles pices


De nouvelles pices doivent tomber du haut de la grille an de remplir les espaces vacants.

11. Rechercher des correspondances de nouveau


Une fois que toutes les pices sont tombes et que de nouvelles sont venues remplir les trous, il convient de rechercher de nouvelles correspondances. Retour ltape 6.

12. Vrier si dautres dplacements sont possibles


Avant de redonner le contrle au joueur, une vrication est opre an de voir si dautres dplacements sont possibles. Si ce nest pas le cas, la partie est termine.

Lanimation et la classe MatchThree


Lanimation MatchThree.a est assez simple. Hormis la police Arial dans la bibliothque, les seuls lments lis au jeu sont un clip pour les pices du jeu et un autre clip qui agit comme indicateur de slection. La Figure 8.6 prsente le clip Piece. Celui-ci contient sept images, chacune abritant une pice diffrente. Le clip de slection se trouve galement sur le calque suprieur et stend sur les sept images. Il peut tre activ ou dsactiv laide de la proprit visible. Examinons les dnitions de classe avant de passer la logique du jeu. Bizarrement, il ny a pas autant de dnitions que lon pourrait en attendre. Seules les instructions import les plus lmentaires sont requises :
package { import ash.display.*; import ash.events.*; import ash.text.*; import ash.utils.Timer;

304

ActionScript 3.0 pour les jeux

Figure 8.6
Le clip Piece contient sept variantes et un cadre de slection.

En ce qui concerne les constantes, nous nen utilisons quune pour le nombre de variantes de Piece et trois pour la disposition de lafchage lcran :
public class MatchThree extends MovieClip { // Constantes static const numPieces:uint = 7; static const spacing:Number = 45; static const offsetX:Number = 120; static const offsetY:Number = 30;

Ltat du jeu sera stock dans cinq variables diffrentes. La premire, grid, contient des rfrences tous les objets Piece. Il sagit en fait dun tableau de tableaux. Chaque lment dans la grille correspond ainsi en ralit un autre tableau contenant huit rfrences au clip Piece. Il sagit donc dun tableau imbriqu de huit par huit. Nous pouvons ds lors examiner chaque objet Piece en utilisant simplement grid[x][y].
gameSprite est un sprite destin contenir tous les sprites et les clips que nous allons crer, ce qui permet de les sparer de tous les autres graphismes dj sur la scne.

La variable rstPiece contient une rfrence au premier objet Piece sur lequel le joueur clique, comme pour le jeu de Memory du Chapitre 3.

Chapitre 8

Les casual games : Match Three

305

Les deux variables boolennes isDropping et isSwapping indiquent si des objets Piece sont en cours danimation sur le moment. La variable gameScore contient le score du joueur :
// Grille et mode du jeu private var grid:Array; private var gameSprite:Sprite; private var rstPiece:Piece; private var isDropping,isSwapping:Boolean; private var gameScore:int;

Congurer la grille
Les premires fonctions dniront les variables du jeu, notamment en congurant la grille du jeu.

Dnir les variables du jeu


Pour commencer la partie, nous devons dnir toutes les variables dtat du jeu. Nous commencerons par crer le tableau de tableaux grid. Ensuite, nous appellerons setUpGrid pour le remplir.

Il nest pas ncessaire de remplir les tableaux internes de grid par des emplacements vides. Le simple fait de dnir une position dans un tableau cre lemplacement correspondant et remplit tous les emplacements prcdents avec la valeur undened. Par exemple, si un nouveau tableau est cr puis que llment 3 se voie attribuer la valeur "My String", le tableau possde la longueur 3 et les lments 0 et 1 possdent la valeur undened.

Nous dnissons ensuite les variables isDropping, isSwapping et gameScore. Nous congurons en outre un couteur ENTER_FRAME pour diriger les mouvements dans le jeu :
// Congurer la grille et dbut de la partie public function startMatchThree() { // Crer le tableau grid grid = new Array(); for(var gridrows:int=0;gridrows<8;gridrows++) { grid.push(new Array()); } setUpGrid(); isDropping = false; isSwapping = false; gameScore = 0; addEventListener(Event.ENTER_FRAME,movePieces); }

306

ActionScript 3.0 pour les jeux

Conguration de la grille
Pour congurer la grille, nous commenons par une boucle sans n en utilisant linstruction while(true). Ensuite, nous crons les lments dans la grille. Nous prvoyons que la premire tentative crera une grille valide. Un nouveau gameSprite est cr pour contenir les clips pour les pices du jeu. Ensuite, soixante-quatre objets Piece alatoires sont crs avec la fonction addPiece. Nous examinerons cette fonction ensuite mais, pour linstant, sachez quelle ajoute un objet Piece au tableau grid ainsi quau gameSprite :
public function setUpGrid() { // Boucler jusqu ce que la grille de dpart soit valide while (true) { // Crer sprite gameSprite = new Sprite(); // Ajouter 64 pices alatoires for(var col:int=0;col<8;col++) { for(var row:int=0;row<8;row++) { addPiece(col,row); } }

Ensuite, nous devons vrier deux choses pour dterminer si la grille cre est un point de dpart valide. La fonction lookForMatches retourne un tableau des correspondances trouves. Nous lexaminerons plus loin dans ce chapitre. ce stade, elle doit retourner zro, ce qui signie quil ny a pas de correspondance lcran. Une commande continue ignore le reste de la boucle while et recommence en crant une nouvelle grille. Aprs cela, nous appelons lookForPossibles, qui vrie sil existe des correspondances possibles suite une permutation. Si la fonction retourne false, il ne sagit pas dun bon point de dpart parce que le jeu est dj termin. Si aucune de ces conditions nest remplie, la commande break permet au programme de quitter la boucle while. Ensuite, nous ajoutons le gameSprite la scne :
// Essayer nouveau si des correspondances sont prsentes if (lookForMatches().length != 0) continue; // Essayer nouveau si aucun dplacement possible if (lookForPossibles() == false) continue; // Aucune correspondance, mais des coups sont possibles : la grille est OK break; } // Ajouter le sprite addChild(gameSprite); }

Chapitre 8

Les casual games : Match Three

307

Ajouter les pices du jeu


La fonction addPiece cre un objet Piece alatoire un emplacement de colonne et de ligne dni. Elle cre le clip et dnit son emplacement :
// Crer une pice alatoire, ajouter au sprite et la grille public function addPiece(col,row:int):Piece { var newPiece:Piece = new Piece(); newPiece.x = col*spacing+offsetX; newPiece.y = row*spacing+offsetY;

Chaque Piece doit tenir le registre de son propre emplacement sur la grille. Deux proprits dynamiques appeles col et row sont dnies cet effet. En outre, type contient le nombre correspondant au type de lobjet Piece, qui correspond limage du clip qui est afche :
newPiece.col = col; newPiece.row = row; newPiece.type = Math.ceil(Math.random()*7); newPiece.gotoAndStop(newPiece.type);

Le clip select lintrieur du clip Piece correspond au contour qui apparat lorsque lutilisateur clique sur une pice. Nous le dnirons de manire quil ne soit pas visible au dpart. Ensuite, la Piece est ajoute au sprite gameSprite. Pour placer la Piece dans le tableau grid, nous utilisons ladressage des tableaux imbriqus laide des doubles crochets : grid[col][row] = newPiece. Chaque Piece se voit attribuer son propre couteur de clic. Ensuite, la rfrence lobjet Piece est retourne. Nous lutiliserons non pas dans la fonction setUpGrid prcdente mais plus tard lors de la cration de nouveaux objets Piece servant remplacer ceux qui ont t supprims suite une correspondance :
newPiece.select.visible = false; gameSprite.addChild(newPiece); grid[col][row] = newPiece; newPiece.addEventListener(MouseEvent.CLICK,clickPiece); return newPiece; }

La Figure 8.7 prsente une grille valide alatoire termine.

Interaction du joueur
Lorsque le joueur clique sur un objet Piece, laction rsultante dpend du fait quil sagit de la premire pice sur laquelle il clique ou de la seconde. Sil sagit de la premire, lobjet Piece est slectionn et rien dautre ne se passe.

308

ActionScript 3.0 pour les jeux

Figure 8.7
Voici lune des grilles de jeu alatoires possibles.

Si le joueur clique deux fois sur le mme objet Piece, celui-ci est dslectionn et le joueur revient la case dpart :
// Le joueur clique sur une pice public function clickPiece(event:MouseEvent) { var piece:Piece = Piece(event.currentTarget); // La premire est slectionne if (rstPiece == null) { piece.select.visible = true; rstPiece = piece; // Le joueur a cliqu de nouveau sur la premire } else if (rstPiece == piece) { piece.select.visible = false; rstPiece = null;

Si le joueur a cliqu sur un deuxime objet Piece, nous devons dterminer sil peut y avoir une permutation. Pour commencer, nous dsactivons la mise en surbrillance de la slection sur le premier objet Piece. Le premier test consiste dterminer si les deux objets Piece se trouvent sur la mme ligne, puis sils se trouvent cte cte. Sinon les objets Piece peuvent tre dans la mme colonne et lun au-dessus de lautre. Dans les deux cas, nous appelons makeSwap. Cette fonction soccupe de vrier si la permutation est valide autrement dit, si elle produira un alignement. Que ce soit le cas ou non, la variable rstPiece est positionne null an de se prparer la prochaine slection du joueur.

Chapitre 8

Les casual games : Match Three

309

Si le joueur a slectionn un objet Piece qui se trouve trop loign du premier, nous supposons que le joueur souhaite abandonner sa premire slection et commenons slectionner une seconde paire :
// Le joueur a cliqu sur la seconde pice } else { rstPiece.select.visible = false; // Mme ligne, une colonne aprs if (rstPiece.row == piece.row) { if (Math.abs(rstPiece.col-piece.col) == 1) { makeSwap(rstPiece,piece); rstPiece = null; } // Mme colonne, une ligne aprs } else if (rstPiece.col == piece.col) { if (Math.abs(rstPiece.row-piece.row) == 1) { makeSwap(rstPiece,piece); rstPiece = null; } // Mauvais dplacement, reslection de la premire pice } else { rstPiece = piece; rstPiece.select.visible = true; } } }

La fonction makeSwap permute les deux objets Piece puis vrie si une correspondance est disponible. Si ce nest pas le cas, elle repermute les objets Piece. Sinon la variable isSwapping est positionne true an que lanimation puisse sexcuter :
// Lancer la permutation anime des deux pices public function makeSwap(piece1,piece2:Piece) { swapPieces(piece1,piece2); // Vrier si le dplacement a produit un alignement if (lookForMatches().length == 0) { swapPieces(piece1,piece2); } else { isSwapping = true; } }

Pour effectuer la permutation effective, nous devons stocker lemplacement de la premire Piece dans une variable temporaire. Ensuite, nous dnirons lemplacement de la premire Piece en lui attribuant celui de la seconde. La Figure 8.8 prsente un diagramme du fonctionnement de la permutation.

310

ActionScript 3.0 pour les jeux

Figure 8.8
Lors de la permutation de deux valeurs, il est ncessaire de crer une variable temporaire pour stocker une valeur au cours de lchange.
Pice 1 Pice 2 Stockage temporaire

Pice 1

Pice 2

Stockage temporaire

Pice 1

Pice 2

Stockage temporaire

Une fois les emplacements des objets Piece changs, la grille doit tre mise jour. Comme chaque Piece possde maintenant les valeurs row et col appropries, nous congurons simplement la grille de manire ponter sur chaque Piece au bon emplacement dans la grille :
// Permuter les deux pices public function swapPieces(piece1,piece2:Piece) { // Permuter les valeurs row et col var tempCol:uint = piece1.col; var tempRow:uint = piece1.row; piece1.col = piece2.col; piece1.row = piece2.row; piece2.col = tempCol; piece2.row = tempRow; // Permuter les positions dans grid grid[piece1.col][piece1.row] = piece1; grid[piece2.col][piece2.row] = piece2; }

La permutation est compltement rversible, ce qui est important car elle devra souvent tre inverse. Nous ne savons si la permutation produit un alignement concordant quaprs quelle se trouve ralise. Nous aurons ainsi souvent besoin de permuter les objets Piece, de vrier sil existe un alignement, puis de reprendre la permutation si aucun alignement nest trouv.

Animer le mouvement des pices


Nous allons utiliser une mthode intressante mais pas vidente pour lanimation du mouvement des pices. Chaque objet Piece connat la ligne (row) et la colonne (col) dans laquelle il se trouve parce quil possde une proprit row et une proprit col dynamiques. Il connat galement son emplacement lcran grce ses proprits x et y.

Chapitre 8

Les casual games : Match Three

311

Ces deux positions doivent se correspondre avec laide des variables spacing, offsetX et offsetY. Une Piece dans la colonne 3 doit ainsi se trouver la position x = 3*spacing+offsetX. Que se passe-t-il cependant si une Piece se dplace vers une nouvelle colonne ? Si nous xons la valeur de col dune Piece 4, elle devrait tre 4*spacing+offsetX, qui est situe spacing (45) pixels vers la droite. Dans le cas prsent, nous demandons la Piece de se dplacer un peu vers la droite, an de se rapprocher de son nouvel emplacement. Si nous procdons ainsi chaque image, la Piece parviendra terme sa nouvelle destination et cessera de bouger (car elle possdera une valeur col et une valeur x qui se correspondent). Cette technique nous permet danimer nimporte quel objet Piece pendant quil se dplace vers son nouvel emplacement. Nous navons mme pas besoin de congurer cette animation pice par pice : il nous suft de changer la proprit col ou row dune Piece pour que la fonction suivante soccupe du reste. La fonction movePieces est appele chaque vnement ENTER_FRAME car nous lavons congure avec un couteur au dbut de la classe. Elle parcourt en boucle toutes les pices et vrie toutes les valeurs col et row an de voir si les valeurs x et y doivent tre ajustes pour y correspondre.

Nous utilisons une distance de 5 chaque image dans movePieces. Pour que col et row salignent sur les valeurs x et y, il est impratif de sen tenir des multiples de 5 pour spacing. Dans lanimation dexemple, spacing vaut 45 et cela fonctionne. Si vous deviez changer la valeur de spacing, par exemple en choisissant 48, vous devriez galement choisir une nouvelle quantit de mouvement dont 48 soit un multiple, comme 4, 6 ou 8.

public function movePieces(event:Event) { var madeMove:Boolean = false; for(var row:int=0;row<8;row++) { for(var col:int=0;col<8;col++) { if (grid[col][row] != null) { // Dplacement vers le bas if (grid[col][row].y < grid[col][row].row*spacing+offsetY) { grid[col][row].y += 5; madeMove = true; // Dplacement vers le haut } else if (grid[col][row].y > grid[col][row].row*spacing+offsetY) { grid[col][row].y -= 5; madeMove = true; // Dplacement vers la droite

312

ActionScript 3.0 pour les jeux

} else if (grid[col][row].x < grid[col][row].col*spacing+offsetX) { grid[col][row].x += 5; madeMove = true; // Dplacement vers la gauche } else if (grid[col][row].x > grid[col][row].col*spacing+offsetX) { grid[col][row].x -= 5; madeMove = true; } } } }

Au dbut de movePieces, nous positionnons la variable boolenne madeMove false. Ensuite, lorsquune animation est requise, nous la positionnons true. En dautres termes, si movePieces ne fait rien, madeMove vaut false. Ensuite, cette valeur est compare aux proprits isDropping et isSwapping de la classe. Si isDropping vaut true et madeMove vaut false, cela signie que toutes les pices qui tombaient ont atterri. Il est temps de rechercher dautres correspondances. En outre, si isSwapping vaut true et madeMove vaut false, cela signie que deux pices viennent juste de terminer leur permutation. Dans ce cas, il est galement temps de rechercher des correspondances :
// Si la chute des pices est termine if (isDropping && !madeMove) { isDropping = false; ndAndRemoveMatches(); // Si la permutation est termine } else if (isSwapping && !madeMove) { isSwapping = false; ndAndRemoveMatches(); } }

Trouver des correspondances


Deux parties du programme Match Three posent un vritable d. La premire est celle qui consiste trouver des correspondances dans la grille. Il sagit, comme nous lavons vu au Chapitre 1, dun excellent exemple de la technique de programmation qui consiste dcomposer le problme en problmes plus petits. Lopration qui consiste trouver des correspondances de trois pices conscutives ou plus dans la mme grille na rien de trivial. Elle ne peut tre rsolue en une simple tape. Il ne faut donc pas considrer quil sagisse dun unique problme rsoudre.

Chapitre 8

Les casual games : Match Three

313

Dcomposer la tche en tapes plus petites


Nous devons au lieu de cela dcomposer cette tche en problmes plus petits et poursuivre cette dcomposition jusqu ce que les problmes deviennent sufsamment simples pour tre facilement rsolus.
ndAndRemoveMatches

commence donc par dcomposer la tche en deux tapes : trouver des correspondances et les supprimer. La suppression des pices est en fait plutt simple. Elle implique simplement de supprimer les objets Piece du gameSprite, de positionner lemplacement de grid correspondant null et dattribuer des points au joueur.

Le nombre de points attribus dpend du nombre de pices conscutives alignes. Trois pices donnent (3-1)*50 ou 100 points par pice pour un total de 300 points. Quatre pices donnent (4-1)*50 soit 150 points par pice pour un total de 600 points.

Labsence de certaines Piece implique cependant que celles au-dessus devront se voir indiquer quelles sont suspendues dans les airs et doivent tomber. Cette tche nest pas triviale non plus. Nous avons donc deux tches non triviales grer : rechercher des correspondances et indiquer aux pices au-dessus de celles supprimes quelles doivent tomber. Nous dlguons ces deux tches dautres fonctions : lookForMatches et affectAbove. Nous raliserons les autres tches simples directement ici dans la fonction ndAndRemoveMatches.

La fonction ndAndRemoveMatches
Nous parcourons en boucle les correspondances trouves et les plaons dans le tableau matches. Ensuite, nous attribuons des points pour chaque correspondance puis nous parcourons tous les objets Piece supprimer et les supprimons.

La technique qui consiste dlguer des tches difciles de nouvelles fonctions que vous navez pas encore cres est appele programmation de haut en bas. Au lieu de se soucier de la manire de trouver des correspondances, nous considrons simplement une fonction lookForMatches qui soccupera de cette tche. Nous construisons le programme de haut en bas, en soccupant dabord des considrations dordre gnral et en se souciant ensuite des fonctions qui soccupent des points de dtail.

// Rcuprer les correspondances et les supprimer, attribuer les points public function ndAndRemoveMatches() { // Obtenir la liste des correspondances var matches:Array = lookForMatches(); for(var i:int=0;i<matches.length;i++) {

314

ActionScript 3.0 pour les jeux

var numPoints:Number = (matches[i].length-1)*50; for(var j:int=0;j<matches[i].length;j++) { if (gameSprite.contains(matches[i][j])) { var pb = new PointBurst(this,numPoints,matches[i][j].x,matches[i][j].y); addScore(numPoints); gameSprite.removeChild(matches[i][j]); grid[matches[i][j].col][matches[i][j].row] = null; affectAbove(matches[i][j]); } } }

La fonction ndAndRemoveMatches a deux tches de plus raliser. Tout dabord, elle appelle addNewPieces pour remplacer tous les objets Piece manquants dans une colonne. Ensuite, elle appelle lookForPossibles pour sassurer quil existe encore des dplacements possibles. Elle ne doit le faire que si aucune correspondance nest trouve. Cela ne se produit que si ndAndRemoveMatches a t appele aprs que les nouvelles pices ont ni de tomber et quaucune correspondance nest trouve :
// Ajouter les nouvelles pices en haut de la grille addNewPieces(); // Aucune correspondance trouve, peut-tre n de partie ? if (matches.length == 0) { if (!lookForPossibles()) { endGame(); } } }

La fonction lookForMatches
La fonction lookForMatches a toujours une tche assez gigantesque grer. Elle doit crer un tableau de toutes les correspondances trouves. Elle doit retrouver des correspondances horizontales et verticales de plus de deux pices. Elle le fait en parcourant en boucle les lignes pour commencer, puis les colonnes. Elle ne doit vrier que les six premiers emplacements dans chaque ligne et chaque colonne, car une correspondance qui commence au septime emplacement ne peut faire que deux de longueur et que le huitime emplacement nest suivi daucune pice. Les fonctions getMatchHoriz et getMatchVert se chargent de la tche dlgue qui consiste dterminer la longueur dune correspondance un emplacement donn de la grille. Par exemple, si lemplacement 3,6 correspond une Piece de type 4, si lemplacement 4,6 est aussi de type 4, mais que 5,6 soit de type 1, lappel getMatchHoriz(3,6) doit retourner 2, car lemplacement 3,6 dmarre une srie de deux pices correspondantes.

Chapitre 8

Les casual games : Match Three

315

Si une srie est trouve, nous souhaitons galement prolonger la boucle de quelques tapes. Sil y a un alignement de quatre pices identiques aux positions 2,1, 2,2, 2,3 et 2,4, nous vrions simplement 2,1 et obtenons le rsultat 4, puis sautons 2,2 2,3 et 2,4 an dexaminer directement 2,5. chaque fois que getMatchHoriz ou getMatchVert retrouvent une correspondance, elles retournent un tableau contenant chacun des objets Piece dans la correspondance. Ces tableaux sont ensuite ajouts au tableau matches dans lookForMatches, qui est son tour retourn au code ayant appel lookForMatches :
//Retourner un tableau de toutes les correspondances trouves public function lookForMatches():Array { var matchList:Array = new Array(); // Rechercher les correspondances horizontales for (var row:int=0;row<8;row++) { for(var col:int=0;col<6;col++) { var match:Array = getMatchHoriz(col,row); if (match.length > 2) { matchList.push(match); col += match.length-1; } } } // Rechercher les correspondances verticales for(col=0;col<8;col++) { for (row=0;row<6;row++) { match = getMatchVert(col,row); if (match.length > 2) { matchList.push(match); row += match.length-1; } } } return matchList; }

Les fonctions getMatchHoriz et getMatchVert


La fonction getMatchHoriz a maintenant une tape spcialise raliser. Avec une colonne et une ligne, elle vrie la Piece suivante an de voir si son type correspond. Si cest le cas, elle est ajoute un tableau. La fonction continue davancer horizontalement jusqu trouver une Piece qui ne correspond pas. Ensuite, elle retourne le tableau quelle a compil. Ce tableau peut en n de compte ne contenir quune seule Piece (celle de la colonne et de la ligne dorigine) si la suivante ne correspond pas.

316

ActionScript 3.0 pour les jeux

En revanche, si la suivante correspond et celle daprs aussi, elle retourne une srie de trois Piece :
// Rechercher des correspondances horizontales partir de ce point public function getMatchHoriz(col,row):Array { var match:Array = new Array(grid[col][row]); for(var i:int=1;col+i<8;i++) { if (grid[col][row].type == grid[col+i][row].type) { match.push(grid[col+i][row]); } else { return match; } } return match; }

La fonction getMatchVert est presque identique la fonction getMatchHoriz, ceci prs quelle effectue sa recherche dans les colonnes et non dans les lignes :
// Rechercher des correspondances verticales partir de ce point public function getMatchVert(col,row):Array { var match:Array = new Array(grid[col][row]); for(var i:int=1;row+i<8;i++) { if (grid[col][row].type == grid[col][row+i].type) { match.push(grid[col][row+i]); } else { return match; } } return match; }

La fonction affectAbove
Nous allons continuer de travailler an de construire pour ndAndRemoveMatches toutes les fonctions dont elle a besoin. La suivante est affectAbove. Nous lui passons un objet Piece et attendons delle quelle indique tous les objets Piece au-dessus quils doivent descendre dun cran. Il sagit en effet dune Piece qui dit : "Je men vais, aussi venez remplir lespace laiss libre." Une boucle examine dans la colonne les pices qui se trouvent au-dessus de la pice actuelle. Si la pice actuelle est 5,6, elle examine donc dans lordre 5,5, 5,4, 5,3, 5,2, 5,1 et 5,0. La ligne (row) de ces pices est alors incrmente dune unit. En outre, la Piece indique grid quelle se trouve dans un nouvel emplacement. Rappelez-vous quavec movePieces nous navons pas nous soucier de la manire dont une Piece doit sanimer pour parvenir un nouvel emplacement.

Chapitre 8

Les casual games : Match Three

317

Il nous suft de changer les proprits col ou row pour que la fonction sen charge par elle-mme :
// Inviter toutes les pices au-dessus de celle-ci descendre dun cran public function affectAbove(piece:Piece) { for(var row:int=piece.row-1;row>=0;row--) { if (grid[piece.col][row] != null) { grid[piece.col][row].row++; grid[piece.col][row+1] = grid[piece.col][row]; grid[piece.col][row] = null; } } }

La fonction addNewPieces
La prochaine fonction que nous devons crer est addNewPieces. Elle examine chaque colonne, puis chaque emplacement de la grille pour chaque colonne et compte le nombre demplacements positionns null. Pour chacun dentre eux, un nouvel objet Piece est ajout. Si la valeur col et row est dnie de manire correspondre sa destination nale, la valeur y est en revanche dnie pour correspondre la ligne au-dessus de la ligne suprieure, an quelle semble tomber de plus haut. En outre, la variable boolenne isDropping se voit attribuer la valeur true pour indiquer que lanimation est en cours :
// Sil manque des pices dans une colonne, en ajouter pour les faire tomber public function addNewPieces() { for(var col:int=0;col<8;col++) { var missingPieces:int = 0; for(var row:int=7;row>=0;row--) { if (grid[col][row] == null) { var newPiece:Piece = addPiece(col,row); newPiece.y = offsetY-spacing-spacing*missingPieces++; isDropping = true; } } } }

Trouver des dplacements possibles


Sil est compliqu de trouver des correspondances, il est en revanche plus simple de trouver des correspondances possibles. Il sagit cette fois non plus dalignements de trois pices mais de possibilits de tels alignements. La rponse la plus simple consiste balayer la grille entire en oprant toutes les permutations : 0,0 avec 1,0, puis 1,0 avec 2,0, etc. chaque permutation, on vrie les correspondances. Ds quune permutation conduit obtenir une correspondance valide, nous cessons la recherche et retournons true.

318

ActionScript 3.0 pour les jeux

Cette approche dite par "force brute" fonctionnerait, mais elle risquerait dtre assez lente, notamment sur les ordinateurs plus anciens. Il existe une technique plus efcace. Si vous considrez ce quil faut pour faire une correspondance, vous verrez que certains motifs se constituent. En gnral, vous avez deux Piece du mme type dans une ligne. Lemplacement ct de ces deux Piece est dun type diffrent mais peut tre permut dans trois sens an dy placer une autre Piece qui pourrait correspondre. Sans cela, vous avez deux Piece espaces dun cran lune de lautre et une permutation pourrait insrer une Piece correspondante entre les deux. La Figure 8.9 prsente ces deux congurations en les dcomposant en six motifs possibles au nal. Horizontalement, la Piece manquante dans la correspondance peut venir de la gauche ou de la droite alors que, verticalement, elle peut venir du haut ou du bas.

Horizontal, deux plus un

Horizontal, Milieu

ou

Vertical, deux plus un

Vertical, Milieu

ou

Figure 8.9
Les cercles remplis reprsentent les pices qui restent en place. Les cercles vides reprsentent lespace qui doit tre rempli par la pice concordante. Les cercles marqus dune croix dsignent les emplacements possibles do pourrait provenir cette pice concordante.

Sachant quil ny a que quelques motifs examiner, nous pouvons crire une fonction qui rcupre une liste des emplacements et dtermine si le motif concorde. Conformment la technique de programmation de haut en bas, nous pouvons commencer par crire lookForPossibles puis nous soucier par la suite de la fonction de correspondance des motifs.

Chapitre 8

Les casual games : Match Three

319

Si lon examine le premier motif la Figure 8.9, on remarque que, si deux emplacements contiennent une pice de mme type, nous obtenons un rsultat positif ds lors que lun parmi trois autres contient une pice correspondante. Si le cercle rempli de gauche est considr tre le point 0,0, le suivant (1,0) doit correspondre et il doit y avoir au moins une Piece correspondante aux emplacements 1,1, 2,0 ou 1,1. La correspondance peut aussi se trouver du ct droit de la paire initiale, au niveau des positions 2,1, 2,1 et 3,0. Rcapitulons : il y a une Piece de dpart. Il y a ensuite une unique position qui doit correspondre la Piece de dpart. Enn, il y a six autres positions dans lesquelles au moins une Piece doit correspondre. La Figure 8.10 prsente cette combinatoire sous forme de diagramme.
Figure 8.10
La position 1,0 doit correspondre 0,0. Au moins un des six emplacements X doit ensuite aussi correspondre 0,0.

Lappel de fonction passera un tableau des positions qui doivent correspondre et un second tableau des positions o au moins une correspondance doit tre trouve. Il ressemblera ainsi ceci :
matchPattern(col, row, [[1,0]], [[-2,0],[-1,-1],[-1,1],[2,-1],[2,1],[3,0]]))

Nous avons besoin dun appel de fonction similaire pour grer le cas "Horizontal, milieu" prsent la Figure 8.9. Idem ensuite pour les motifs verticaux. La fonction lookForPossibles les recherche tous, toutes les positions dans la grille :
// Vrier si un dplacement est possible dans la grille public function lookForPossibles() { for(var col:int=0;col<8;col++) { for(var row:int=0;row<8;row++) {

// Possibilit horizontale, deux plus un if (matchPattern(col, row, [[1,0]], [[-2,0],[-1,-1],[-1,1],[2,-1],[2,1],[3,0]])) { return true; } // Possibilit horizontale, milieu if (matchPattern(col, row, [[2,0]], [[1,-1],[1,1]])) { return true; }

320

ActionScript 3.0 pour les jeux

// Possibilit verticale, deux plus un if (matchPattern(col, row, [[0,1]], [[0,-2],[-1,-1],[1,-1],[-1,2],[1,2],[0,3]])) { return true; } // Possibilit verticale, milieu if (matchPattern(col, row, [[0,2]], [[-1,1],[1,1]])) { return true; } } } // Aucun dplacement possible na t trouv return false; }

La fonction matchPattern, quoiquelle possde une tche importante raliser, nest pas une fonction trs longue. Elle doit obtenir le type de la Piece la position de colonne et de ligne spcie. Ensuite, elle examine la liste mustHave et vrie la Piece la position relative. Si elle ne correspond pas, inutile de continuer et la fonction retourne false. Sinon chacune des Piece dans needOne est vrie. Si lune quelconque correspond, la fonction retourne true. Si aucune ne correspond, la fonction sarrte et retourne false :
public function matchPattern(col,row:uint, mustHave, needOne:Array) { var thisType:int = grid[col][row].type; // Sassurer que les pices impratives sont l for(var i:int=0;i<mustHave.length;i++) { if (!matchType(col+mustHave[i][0], row+mustHave[i][1], thisType)) { return false; } } // Sassurer quil existe au moins une des pices requises for(i=0;i<needOne.length;i++) { if (matchType(col+needOne[i][0], row+needOne[i][1], thisType)) { return true; } } return false; }

Chapitre 8

Les casual games : Match Three

321

Toutes les comparaisons dans matchPattern sont opres via des appels matchType. Cest que nous essayons souvent dexaminer des Piece qui ne se trouvent pas dans la grille. Par exemple, si la colonne et la ligne passes matchPattern sont 5,0 et que la Piece dcale de 1,1 est examine, nous examinons en fait grid[4,-1], qui nest pas dnie, car il nexiste pas dlment 1 dans un tableau. La fonction matchType recherche des valeurs demplacement de la grille qui se trouvent hors de la grille que nous avons dnie et retourne instantanment false lorsque cela se produit. Sinon la valeur de grid est examine et la valeur true est retourne si le type correspond :
public function matchType(col,row,type:int) { // Sassurer que col et row ne sont pas hors-limites if ((col < 0) | | (col > 7) | | (row < 0) | | (row > 7)) return false; return (grid[col][row].type == type); }

Mmorisation du score et n de partie


Dans ndAndRemoveMatches, nous avions appel addScore an dattribuer des points au joueur. Cette fonction simple ajoute des points au score du joueur et met jour le champ texte lcran :
public function addScore(numPoints:int) { gameScore += numPoints; MovieClip(root).scoreDisplay.text = String(gameScore); }

Lorsquil ne reste plus de correspondance possible, la fonction endGame conduit le scnario principal limage gameover. Elle utilise aussi swapChildIndex pour placer le gameSprite larrire, an que les sprites de limage gameover se trouvent au-dessus de la grille du jeu. Nous devons procder ainsi parce que nous ne supprimerons pas la grille du jeu la n de la partie. Au lieu de cela, nous la conserverons cet endroit pour que le joueur puisse lexaminer :
public function endGame() { // Ramener larrire setChildIndex(gameSprite,0); // Aller la n de partie gotoAndStop("gameover"); }

Nous nous dbarrassons de la grille (grid) et du sprite gameSprite lorsque le joueur est prt passer la suite. La fonction cleanUp sen charge :
public function cleanUp() { grid = null; removeChild(gameSprite); gameSprite = null; removeEventListener(Event.ENTER_FRAME,movePieces); }

322

ActionScript 3.0 pour les jeux

Dans le scnario principal, la fonction lie au bouton Play Again appelle cleanUp juste avant de revenir limage prcdente an de commencer une nouvelle partie.

Modier le jeu
Lune des dcisions importantes prendre est de savoir si vous souhaitez six ou sept variantes de pices dans le jeu. La plupart des jeux Match Three en comptent six. Jen ai utilis sept par le pass, et cela fonctionnait galement. Le recours sept pices acclre la n du jeu. Les points de bonus font partie des amliorations importantes qui peuvent tre effectues. Un calque de graphisme supplmentaire peut tre ajout au clip Piece, de manire analogue la bordure de slection. Il peut tre rendu visible sur des pices alatoires an dindiquer des points de bonus. Une proprit bonus peut tre ajoute la Piece galement, qui pourrait dclencher un second appel addScore lorsque cette Piece est supprime. Les indications peuvent tre un moyen de rendre le jeu plus attrayant pour le joueur. Lorsque lookForPossibles est appele, elle appelle matchType un certain nombre de fois. Si une correspondance possible est trouve dans la seconde boucle lintrieur de matchType, la valeur true est retourne. La position prcise que matchType examine ce stade est une Piece qui peut tre utilise dans une permutation pour crer un alignement gagnant. Elle peut tre place dans une nouvelle variable appele par exemple hintLocation et cet emplacement peut tre utilis pour mettre en valeur une pice lorsque le joueur clique sur le bouton Indice.

9
Jeux de mots : pendu et mots mls
Au sommaire de ce chapitre :

Chanes et champs texte Pendu Mots mls

324

ActionScript 3.0 pour les jeux

Lutilisation des lettres et des mots pour les jeux sest considrablement popularise depuis le milieu du XXe sicle avec les jeux de socit tels que le Scrabble ou les jeux sur papier comme les mots croiss et les mots mls. Ces jeux fonctionnent bien comme jeux dordinateur et sur le Web. Dans ce chapitre, nous en tudierons deux versions classiques : le jeu du pendu et le jeu des mots mls. Avant cela, nous devons cependant voir comment ActionScript gre les chanes et les champs texte.

Chanes et champs texte


Codes sources http://ashgameu.com A3GPU09_TextExamples.zip Avant dessayer de crer des jeux de mots, il est utile de compendre comment ActionScript 3.0 gre les chanes et les champs texte, car nous nous en servirons frquemment dans nos jeux.

Gestion des chanes en ActionScript 3.0


En ActionScript, une variable String (chane) est une squence de caractres. Nous avons dj utilis des chanes dans ce livre, sans vraiment nous soucier de la manire de raliser des oprations avances avec elles. Pour crer une chane, il suft dattribuer des caractres entours de guillemets une variable de type String :
var myString:String = "Why is a raven like a writing desk?";

Dconstruction des chanes


Les chanes peuvent tre dconstruites avec une varit de fonctions. Pour obtenir un unique caractre situ un emplacement particulier, vous pouvez utiliser charAt :
myString.charAt(9)

Le rsultat est ici "r".

ActionScript commence compter les positions des caractres dans les chanes partir du caractre 0. Le caractre 0 dans lexemple prcdent est ainsi "W", de sorte que le caractre 9 est "r".

Chapitre 9

Jeux de mots : pendu et mots mls

325

Il est galement possible dutiliser substr pour obtenir un ou plusieurs caractres de la chane. Le premier paramtre est la position de dpart et le second, le nombre de caractres retourner :
myString.substr(9,5)

Cette instruction retourne "raven". La fonction substring est une variante qui prend en paramtre la position de dpart et celle de n. Elle retourne la portion de chane allant du caractre de la position de dpart jusqu un caractre avant la position de n :
myString.substring(9,14)

Cette instruction retourne "raven". La fonction slice agit comme la fonction substring, sauf quant linterprtation du second paramtre. Avec substring, les paramtres sont inverss si le second est infrieur au premier. myString.substring(9,14) quivaut donc myString.substring(14,9). La fonction slice vous permet dutiliser des valeurs ngatives pour le second paramtre. Elle compte en arrire partir de la n de la chane. Ainsi, myString.slice(9,-21) retourne "raven".
substring

et slice vous permettent toutes deux domettre le second paramtre pour obtenir le reste de la chane.
myString.slice(9)

Cette instruction retourne "raven like a writing desk?".

Comparer et rechercher des chanes


Pour comparer deux chanes, il suft dutiliser loprateur == :
var testString = "raven"; trace(testString == "raven");

Ce code retourne true. Loprateur est cependant sensible la casse, de sorte que le code suivant retourne false :
trace(testString == "Raven");

Si vous souhaitez comparer deux chanes sans tenir compte de la casse des caractres, convertissez lune ou les deux en majuscules ou en minuscules. Cest ce que permettent de faire les fonctions toUpperCase et toLowerCase :
testString.toLowerCase() == "Raven".toLowerCase()

Pour trouver une chane lintrieur dune autre chane, utilisez indexOf :
myString.indexOf("raven")

326

ActionScript 3.0 pour les jeux

Cette instruction retourne 9. Vous pouvez galement utiliser lastIndexOf pour trouver la dernire occurrence dune chane lintrieur dune autre chane :
myString.indexOf("a") myString.lastIndexOf("a")

La premire ligne retourne 7 et la seconde, 20. Ces valeurs correspondent la premire et la dernire position de la lettre dans la chane "Why is a raven like a writing desk?".

Vous pouvez galement fournir un second paramtre indexOf et lastIndexOf. Ce nombre indique o commencer la recherche dans la chane au lieu de dmarrer au dbut.

La plupart du temps, lorsque vous utiliserez indexOf, vous chercherez non pas connatre la position de la chane mais savoir si elle existe. Si cest le cas, indexOf retourne un nombre suprieur ou gal 0. Si ce nest pas le cas, elle retourne 1. Vous pouvez donc dterminer si une chane se trouve lintrieur dune autre en utilisant une instruction comme la suivante :
(myString.indexOf("raven") != -1)

La fonction search offre un autre moyen de trouver une chane lintrieur dune autre chane :
myString.search("raven")

Cette instruction retourne 9. Comme indiqu prcdemment, la fonction search peut prendre une chane en paramtre, mais elle peut galement prendre ce que lon appelle une expression rgulire.

Une expression rgulire est un motif utilis pour trouver ou remplacer des chanes lintrieur dautres chanes. Les expressions rgulires sont utilises dans de nombreux langages de programmation et outils logiciels. Le sujet des expressions rgulires est trop vaste pour tre trait ici. Il existe dailleurs plusieurs livres de plus de mille pages qui lui sont entirement consacrs ! De nombreux sites Web en traitent en dtail. Consultez le site http://ashgameu.com pour trouver des liens sur ce sujet.

myString.search(/raven/);

Cet exemple correspond au type le plus simple dexpression rgulire et quivaut linstruction prcdente utilisant search. Vous remarquerez que cest le caractre / qui est utilis et non les guillemets pour entourer les caractres.

Chapitre 9

Jeux de mots : pendu et mots mls

327

Vous pouvez galement inclure des options aprs la barre oblique dans lexpression rgulire. La plus utile serait ici le i, pour ignorer la casse des caractres :
myString.search(/Raven/i);

Cet exemple retourne 9, bien quil utilise un R majuscule. Vous pouvez aussi utiliser des jokers dans les expressions rgulires. Par exemple, le point reprsente nimporte quel caractre :
myString.search(/r...n/)

Cet exemple retourne 9 parce que le mot raven correspond au motif du r suivi par trois caractres quelconques, puis un n.
myString.search(/r.*n/)

Cet exemple retourne aussi 9, le motif dsignant un r suivi par nimporte quel nombre de caractres, suivi par un n.

Construire et modier des chanes


Vous pouvez ajouter des caractres une chane en utilisant loprateur +. ActionScript dterminera quil sagit dun objet String (une chane) et non dun nombre et ajoutera les caractres au lieu de les additionner. Vous pouvez galement utiliser += pour raliser un simple ajout :
myString = "Why is a raven like"; myString += " a writing desk?";

Pour placer quelque chose avant une chane existante, utilisez du code comme le suivant :
myString = "a writing desk?"; myString = "Why is a raven like "+myString;

Alors que la fonction search recherche et retourne une valeur dindex, la fonction replace prend une expression rgulire et lutilise pour remplacer une portion de la chane :
myString.replace("raven","door mouse")

Cet exemple retourne Why is a door mouse like a writing desk? Vous pouvez galement utiliser une expression rgulire dans le premier paramtre. Cette approche permet de raliser des oprations trs complexes, par exemple pour dplacer une portion de texte lintrieur dun texte au lieu dimporter un texte de remplacement :
myString.replace(/(raven)(.*)(writing desk)/g,"$3$2$1")

Cet exemple de code recherche raven et writing desk dans la chane, spars par nimporte quel nombre de caractres. Il rordonne ensuite la chane, en plaant dabord writing desk, en dernier raven et les mmes caractres entre les deux.

328

ActionScript 3.0 pour les jeux

Conversions entre chanes et tableaux


Les chanes et les tableaux sont aussi utiles les uns que les autres pour stocker des listes dinformations. Il est donc intressant de pouvoir effectuer des conversions entre les deux. Par exemple, vous pourriez souhaiter crer un tableau partir dune chane comme "apple,orange,banana". Pour cela, vous pouvez utiliser la commande split :
var myList:String = "apple,orange,banana"; var myArray:Array = myList.split(",");

Vous pouvez inverser le processus est utilisant la commande join :


var myList:String = myArray.join(",");

Dans les deux cas, le caractre pass dans la fonction reprsente le caractre utilis pour sparer les lments dans la chane. Si vous utilisez la commande join, la chane string rsultante est recolle en insrant des virgules entre les lments.

Synthse des fonctions de chane


Le Tableau 9.1 contient toutes les fonctions de chane dont nous avons trait et quelques autres.
Tableau 9.1 : Fonctions de chane

Fonction
charAt charCodeAt

Syntaxe
myString.charAt(pos) String.charCodeAt(pos)

Description
Retourne le caractre lemplacement indiqu Retourne le code de caractre du caractre lemplacement indiqu Retourne une nouvelle chane avec la seconde chane ajoute la premire Retourne le caractre correspondant au code de caractre Retourne lemplacement de la chane interne dans la chane principale Combine les lments dans un tableau an de crer une chane Retourne le dernier emplacement de la chane intrieure dans la chane principale Retourne la sous-chane qui correspond au motif Remplace le motif

concat

myString.concat(autreChaine)

fromCharCode

String.fromCharCode(num) myString.indexOf (chaneIntrieure,posDpart) myArray.join(car) myString.lastIndexOf (chaneIntrieure,posDpart) myString.match(expression) myString.replace(expression, remplacement)

indexOf

join

lastIndexOf

match replace

Chapitre 9

Jeux de mots : pendu et mots mls

329

Tableau 9.1 : Fonctions de chane (Suite)

Fonction
search slice split string substr substring toLowerCase toUpperCase

Syntaxe
myString.search(expression) myString.slice(dbut,n) myString.split(car) String(pasUneChane) myString.substr(dbut,long) myString.substr(dbut,n) myString.toLowerCase() myString.toUpperCase()

Description
Trouve lemplacement de la sous-chane correspondant au motif Retourne la sous-chane Dcompose la chane dans un tableau Convertit un nombre ou une autre valeur en une chane Retourne la sous-chane Retourne la sous-chane Retourne la chane en lettres minuscules Retourne la chane en lettres majuscules

Appliquer une mise en forme au champ texte


Pour placer du texte lcran, vous devez crer un nouvel objet TextField, autrement dit un champ texte. Nous avons utilis ces champs dans les prcdents chapitres an de crer des messages texte et des afchages de score. Si vous souhaitez utiliser autre chose que la police et le style par dfaut, vous devez galement crer un objet TextFormat et lattribuer au champ texte. Et, pour lutilisation avance du texte dans les jeux, nous devrons encore inclure des polices dans nos animations.

Lobjet TextFormat
Lobjet TextFormat se cre gnralement juste avant de crer un objet TextField. Il peut aussi ltre au dbut dune classe si vous savez que vous allez utiliser ce format pour plusieurs des champs texte que vous allez crer.
TextFormat nest en fait rien dautre quun conteneur pour un ensemble de proprits qui contrlent lapparence du texte.

ActionScript vous permet galement de crer des feuilles de style comparables aux CSS utilises dans les documents HTML. Ces feuilles de style ne sont cependant utiles que pour les champs texte formats en HTML. Pour notre part, nous nutiliserons que des champs texte bruts dans nos jeux.

330

ActionScript 3.0 pour les jeux

Vous avez deux choix lors de la cration dun TextFormat. Le premier consiste crer simplement un objet TextFormat vide puis dnir chacune de ses proprits. Le second consiste dnir plusieurs des proprits les plus courantes dans la dclaration TextFormat. Voici un exemple de la mthode de cration rapide dun objet TextFormat :
var letterFormat:TextFormat = new TextFormat("Monaco",36,0x000000,true,false,false,null,null,"center");

Il est videmment important de se rappeler lordre exact des paramtres pour TextFormat. Il est le suivant : police, taille, couleur, gras, italique, soulign, url, cible et alignement. Vous pouvez inclure le nombre de proprits que vous souhaitez, pourvu quelles soient indiques dans cet ordre. Utilisez null pour passer les proprits que vous ne souhaitez pas dnir.

La liste des paramtres est en fait plus tendue, mais je les ai omis dans le prcdent exemple : marge gauche (leftMargin), marge droite (rightMargin), retrait (indent) et interlignage (leading).

Voici maintenant la mthode longue :


var letterFormat:TextFormat = new TextFormat(); letterFormat.font = "Monaco"; letterFormat.size = 36; letterFormat.color = 0x000000; letterFormat.bold = true; letterFormat.align = "center";

Vous remarquerez que jai laiss les proprits italic et underline, car la valeur false est utilise par dfaut pour les deux. Le Tableau 9.2 prsente une synthse de toutes les proprits TextFormat.
Tableau 9.2 : Proprits de TextFormat

Proprit
align

Valeurs dexemple
TextFormatAlign.LEFT, TextFormatAlign.RIGHT, TextFormatAlign.CENTER, TextFormatALign.JUSTIFY

Description
Alignement du texte

blockIndent bold bullet

Nombre
true/false true/false

Retrait de toutes les lignes dun paragraphe Passe le texte en gras Afche le texte sous forme de liste puces

Chapitre 9

Jeux de mots : pendu et mots mls

331

Tableau 9.2 : Proprits de TextFormat (Suite)

Proprit
color font indent

Valeurs dexemple
Couleur Nom de police Nombre
true/false true/false

Description
Couleur du texte (par exemple, 0x000000) Police utiliser Retrait de la premire ligne du paragraphe uniquement Passe le texte en italique Active lespace spcial de certains caractres (crnage) dans certaines polices Espacement vertical entre les lignes (interlignage) Espace supplmentaire gauche Espace supplmentaire entre les caractres Espace supplmentaire droite Taille de la police Emplacements de tabulation dnis Cible navigateur dun lien (par exemple, "_blank") Souligne le texte LURL du lien

italic kerning

leading leftMargin letterSpacing rightMargin size tabStops target underline url

Nombre Nombre Nombre Nombre Nombre Tableau de nombres Chane


true/false

Chane

Crer des objets TextField


Une fois que vous avez un format, il vous faut un champ texte auquel lappliquer. Lobjet TextField se cre la manire dun Sprite. Il sagit en fait dans les deux cas dun objet dafchage. Tous deux peuvent tre ajouts dautres sprites ou dautres clips avec addChild :
var myTextField:TextField = new TextField(); addChild(myTextField);

Pour attribuer un format un champ, la meilleure mthode consiste utiliser la proprit defaultTextFormat :
myTextField.defaultTextFormat = letterFormat;

Lautre possibilit consiste utiliser la fonction setTextFormat. Le problme tient alors ce que, lorsque vous dnissez la proprit text du champ, la mise en forme du texte revient la mise en forme par dfaut pour ce champ :
myTextField.setTextFormat(letterFormat);

332

ActionScript 3.0 pour les jeux

Lavantage de setTextFormat tient ce que vous pouvez ajouter un deuxime et un troisime paramtre pour spcier les caractres de dbut et de n pour la mise en forme. Vous pouvez formater un fragment de texte au lieu du texte entier. Dans les jeux, nous utilisons gnralement de petits champs texte pour diffrents usages comme lafchage du score, du niveau, du temps de jeu, du nombre de vies, et ainsi de suite. Ces champs ne requirent pas plusieurs formats de texte et sont souvent mis jour. La dnition de defaultTextFormat constitue donc la meilleure approche dans la plupart des cas. Aprs defaultTextFormat, la prochaine proprit la plus important pour nous est selectable. La plupart des champs texte que nous utiliserons pour les jeux ne sont destins qu un rle dafchage uniquement o lutilisateur nest pas cens pouvoir cliquer dessus. Nous dsactiverons ainsi la proprit selectable an que le curseur ne se modie pas lorsquil survole le champ et que lutilisateur ne puisse slectionner le texte.

La proprit border du champ texte est un moyen utile de vrier la taille et lemplacement du champ cr avec ActionScript. Par exemple, si vous ne placez quun mot ou une lettre dans un champ, vous ne pourrez pas voir vritablement la taille du champ sans positionner border true, ne serait-ce que temporairement, pour les besoins de votre test.

Le Tableau 9.3 prsente certaines proprits utiles de lobjet TextField.


Tableau 9.3 : Proprits de TextField

Proprit

Valeurs
TextFieldAutoSize.LEFT, TextFieldAutoSize.RIGHT, TextFieldAutoSize.CENTER, TextFieldAutoSize.NONE true/false

Description
Redimensionne le champ texte an de lajuster au texte plac dedans Indique sil y a un remplissage darrire-plan Couleur du remplissage darrire-plan (par exemple, 0x000000) Indique sil y a une bordure Couleur de la bordure (par exemple, 0x000000) Dnit le format de texte par dfaut utilis lorsque du nouveau texte est appliqu Doit tre positionn true pour utiliser des polices incorpores

autoSize

background backgroundColor border borderColor

Couleur
true/false

Couleur Objet TextFormat


true/false

defaultTextFormat

embedFonts

Chapitre 9

Jeux de mots : pendu et mots mls

333

Tableau 9.3 : Proprits de TextField (Suite)

Proprit
multiline

Valeurs
true/false

Description
Doit tre positionn true pour contenir plusieurs lignes de texte Si true, lutilisateur peut slectionner le texte dans le champ texte Dnit le contenu entier du texte du champ Dnit la couleur du texte (par exemple, 0x000000) Dnit si lutilisateur peut diter le texte Dnit le renvoi la ligne du texte

selectable text textColor

true/false

Chane Couleur
TextFieldType.DYNAMIC, TextFieldType.INPUT true/false

type wordWrap

Polices
Si vous crez un jeu rapide en guise dexemple, pour amuser vos amis ou simplement pour illustrer un point, vous pouvez vous en tenir aux polices de base. Cest ce que nous avons fait dans la plupart des jeux de ce livre, an quils restent aussi simples que possible. Si vous dveloppez un jeu pour un client ou pour votre site Web, vous devrez en revanche importer les polices que vous utilisez dans votre bibliothque. Vous rendrez ainsi votre jeu indpendant des polices que les utilisateurs possdent sur leur ordinateur. Cela vous permettra galement dutiliser des effets plus volus avec les polices, comme la rotation et la transparence alpha. Pour importer une police, accdez la bibliothque et choisissez Nouvelle police dans le menu droulant (comme vous lavez fait prcdemment au Chapitre 7). Aprs avoir import la police, nommez-la, cliquez du bouton droit sous Windows ou avec la touche Ctrl enfonce sur Mac pour slectionner loption Proprits de liaison et incluez la police dans lanimation.

Les programmeurs oublient couramment de dnir les Proprits de liaison pour les polices. la diffrence des clips, les proprits de liaison napparaissent pas dans la bote de dialogue Proprits standard des polices. Elles sont difciles trouver et donc faciles oublier. Aucune erreur ni aucun avertissement napparat lorsque vous essayez dutiliser des polices que vous avez oubli de lier.

Mme aprs avoir incorpor certaines polices, vos champs texte nutiliseront vos polices que si vous positionnez la proprit embedFonts true.

334

ActionScript 3.0 pour les jeux

En utilisant les polices qui se trouvent dans votre bibliothque, vous pouvez manipuler et animer du texte de diffrentes manires.

Exemple de texte anim


Les chiers TextFly.a et TextFly.as montrent comment utiliser des chanes, des formats de texte et des champs texte pour crer une animation. Le chier danimation ne contient rien lexception de la police. La scne est vide. La classe TextFly.as prend une chane et la dcompose en caractres, de manire produire un unique TextField et un Sprite pour chaque caractre. Elle anime ensuite ces sprites. La classe commence par dnir une srie de constantes qui dtermineront le comportement de lanimation :
package { import ash.display.*; import ash.text.*; import ash.geom.Point; import ash.events.*; import ash.utils.Timer; public class TextFly extends MovieClip { // Constantes pour dnir lanimation static const spacing:Number = 50; static const phrase:String = "FlashGameU"; static const numSteps:int = 50; static const stepTime:int = 20; static const totalRotation:Number = 360; static const startScale:Number = 0.0; static const endScale:Number = 2.0; static const startLoc:Point = new Point(250,0); static const endLoc:Point = new Point(50,100); private var letterFormat:TextFormat = new TextFormat(Monaco,36,0x000000,true,false, false,null,null,TextFormatAlign.CENTER);

Ensuite, elle dnit des variables pour contenir les Sprite et ltat de lanimation :
// Variables pour tenir registre de ltat de lanimation private var letters:Array = new Array(); private var ySprite:Sprite; private var animTimer:Timer;

Chapitre 9

Jeux de mots : pendu et mots mls

335

La fonction constructeur cre tous les objets TextField et Sprite. Elle lance galement lanimation en crant un Timer :
public function TextFly() { // Un sprite pour tout contenir ySprite = new Sprite(); addChild(ySprite);

// Crer toutes les lettres sous forme de champs texte dans des sprites for(var i:int=0;i<phrase.length;i++) { var letter:TextField = new TextField(); letter.defaultTextFormat = letterFormat; letter.embedFonts = true; letter.autoSize = TextFieldAutoSize.CENTER; letter.text = phrase.substr(i,1); letter.x = -letter.width/2; letter.y = -letter.height/2; var newSprite:Sprite = new Sprite(); newSprite.addChild(letter); newSprite.x = startLoc.x; newSprite.y = startLoc.y; ySprite.addChild(newSprite); letters.push(newSprite); }

// Lancer lanimation animTimer = new Timer(stepTime,numSteps); animTimer.addEventListener(TimerEvent.TIMER,animate); animTimer.start(); } Then, with each step of the animation, the rotation and scale of the Sprites will be set: public function animate(event:TimerEvent) { // O en est lanimation ? var percentDone:Number = event.target.currentCount/event.target.repeatCount;

// Changer position, chelle et rotation for(var i:int=0;i<letters.length;i++) { letters[i].x = startLoc.x*(1.0-percentDone) + (endLoc.x+spacing*i)*percentDone;

336

ActionScript 3.0 pour les jeux

letters[i].y = startLoc.y*(1.0-percentDone) + endLoc.y*percentDone; var scale:Number = startScale*(1-percentDone)+endScale*percentDone; letters[i].scaleX = scale; letters[i].scaleY = scale; letters[i].rotation = totalRotation*(percentDone-1); } }

La Figure 9.1 prsente cette animation en cours daction. Il est important de pouvoir contrler des champs texte et des formats ce niveau si vous prvoyez de crer des jeux qui utilisent des lettres ou des mots comme pices de jeu. Nous allons ainsi maintenant examiner un jeu de pendu, sans doute le jeu de lettre le plus simple quil soit possible de crer.
Figure 9.1
Le programme TextFly anime des caractres dans du texte pour les faire voltiger.

Pendu
Codes sources http://ashgameu.com A3GPU09_Hangman.zip

Le pendu est un jeu trs simple programmer. Pour ne pas droger cette simplicit, nous proposerons dans cet exemple une version dpourvue dartices du programme.

Chapitre 9

Jeux de mots : pendu et mots mls

337

Congurer le pendu
En gnral, le jeu du pendu se joue deux personnes. La premire choisit un mot ou une phrase et dessine chacune des lettres avec un trait de soulignement, puis la seconde sefforce de deviner les lettres qui le composent. Lorsque le second joueur devine une lettre du mot ou de la phrase, le premier remplit les espaces correspondants o se trouve la lettre. Si le second joueur choisit une lettre qui nest pas utilise, le premier dessine une portion supplmentaire dun pendu dans une image. En gnral, il suft de quelques rponses incorrectes pour complter le pendu, aprs quoi la partie est perdue. Dans notre jeu, nous utiliserons une squence sept tapes qui diffrent un petit peu dun pendu. La Figure 9.2 montre notre caractre de mascotte suspendu une branche. Aprs sept choix incorrects, la mascotte tombe. Lanimation Hangman.a contient donc ce seul clip, qui se trouve plac dans la scne vers la droite. Il ny a sinon rien de spcial avec cette animation, sauf que sa classe est dnie comme tant Hangman.

Le pendu est apparu au XIXe sicle, vers lpoque o lon utilisait des potences pour punir les criminels. Cette image inhabituelle est toujours utilise dans le jeu daujourdhui, mme sil est possible de lui substituer nimporte quel type de squence en sept tapes.

Figure 9.2
Cette squence de sept images peut tre remplace par nimporte quelle squence du mme type

338

ActionScript 3.0 pour les jeux

La classe Hangman
Le jeu tout entier ne fait que cinquante lignes de code. Seules quatre variables de classe sont requises. Il est plaisant de voir quun jeu plutt intressant peut tre cr si rapidement et si facilement en ActionScript 3.0. Deux chanes sont requises : lune pour contenir la phrase et lautre pour contenir le texte dafchage, qui commence par des caractres de soulignement lendroit o les lettres doivent gurer. Nous aurons ensuite une variable pour contenir une rfrence au champ texte et une autre pour tenir le registre du nombre dessais infructueux :
package { import ash.display.*; import ash.text.*; import ash.events.*;

public class Hangman extends Sprite { private var textDisplay:TextField; private var phrase:String = "Imagination is more important than knowledge."; // - Albert Einstein private var shown:String; private var numWrong:int;

Lorsque la classe dmarre, elle cre une copie de la phrase en la faisant traiter par la fonction replace avec une expression rgulire. Lexpression /[A-Za-z]/g a nimporte quel caractre de lettre (en somme, de A Z et de a z). Elle remplace ces correspondances par un caractre de soulignement :
public function Hangman() { // Crer une copie du texte avec un _ pour chaque lettre shown = phrase.replace(/[A-Za-z]/g,"_"); numWrong = 0;

Le champ texte que nous allons congurer utilisera un format de texte simple pour la police Courier, 30 points. Il dnira la largeur et la hauteur de manire que le texte ninterfre pas avec le graphisme de la mascotte ct droit.

Jai choisi la police Courier parce quil sagit dune police chasse xe, ce qui signie que toutes les lettres possdent la mme largeur. Les autres polices possdent des largeurs variables pour les diffrentes lettres (par exemple pour le l et le w). En utilisant une police chasse xe, nous avons la garantie que les caractres de texte ne changeront pas de position lorsque nous remplaons les caractres de soulignement par des lettres.

Chapitre 9

Jeux de mots : pendu et mots mls

339

// Conguration du champ texte visible textDisplay = new TextField(); textDisplay.defaultTextFormat = new TextFormat(Courier,30); textDisplay.width = 400; textDisplay.height = 200; textDisplay.wordWrap = true; textDisplay.selectable = false; textDisplay.text = shown; addChild(textDisplay);

La fonction pressKey sera attribue lvnement KEY_UP pour la scne :


// couter les appuis sur les touches stage.addEventListener(KeyboardEvent.KEY_UP,pressKey); }

Lorsque le joueur enfonce une touche, nous utilisons le code event.charCode retourn pour connatre la touche appuye :
public function pressKey(event:KeyboardEvent) { // Dterminer la touche enfonce var charPressed:String = (String.fromCharCode(event.charCode));

Une fois que cette lettre est connue, nous recherchons dventuelles correspondances dans la phrase. Nous veillons bien utiliser toLowerCase an que lappui sur la touche puisse correspondre aux versions en majuscules ou en minuscules de la phrase. Lorsquune correspondance est trouve, la variable afche est mise jour en remplaant le caractre de soulignement au niveau de cette position par la lettre correspondante de la phrase. La lettre utilise est ainsi en majuscule ou en minuscule comme elle lest originellement dans la phrase :
// Boucle pour trouver les lettres correspondantes var foundLetter:Boolean = false; for(var i:int=0;i<phrase.length;i++) { if (phrase.charAt(i).toLowerCase() == charPressed) { // Correspondance trouve, changer la phrase afche shown = shown.substr(0,i)+phrase.substr(i,1)+shown.substr(i+1); foundLetter = true; } }

La variable boolenne foundLetter est positionne false lorsque cette recherche dmarre et rinitialise true si une correspondance est trouve. Si elle reste false, nous savons donc que la lettre ne se trouvait pas dans la phrase et limage du pendu peut progresser.

340

ActionScript 3.0 pour les jeux

Avant cela, nous allons cependant mettre jour le texte lcran en attribuant la valeur shown au champ texte :
// Mettre jour le texte lcran textDisplay.text = shown; // Mettre jour le pendu if (!foundLetter) { numWrong++; character.gotoAndStop(numWrong+1); } }

Lors des tests dans Flash, assurez-vous de choisir loption de menu Contrle > Dsactiver les raccourcis clavier. Sans cela, les appuis que vous ferez sur les touches ne parviendront pas la fentre du jeu.

Ce jeu court et simple peut tre tendu an dinclure les lments de jeux auxquels nous sommes habitus, comme un cran de dpart et un cran de n de partie. Cet exemple montre quil nest pas ncessaire de passer plus de quelques heures pour crer un jeu amusant. Considrons maintenant un jeu de mots plus robuste, celui des mots mls.

Mots mls
Codes sources http://ashgameu.com A3GPU09_WordSearch.zip On pourrait penser que le jeu des mots mls est un jeu fort ancien, mais il na en ralit fait son apparition quau cours des annes 1960. Ces jeux sont populaires dans les pages des journaux et dans les revues de vacances. Les jeux de mots mls informatiques peuvent tre gnrs alatoirement partir dune liste de mots ou de dictionnaires. Ce systme les rend plus faciles crer : il vous suft de fournir une liste de mots. Bien des aspects posent cependant des ds lors de la cration dun jeu de mots mls sur ordinateur, par exemple pour lafchage des lettres, pour la mise en surbrillance horizontale, verticale et diagonale et la conservation dune liste de mots.

Chapitre 9

Jeux de mots : pendu et mots mls

341

Stratgie de dveloppement
Notre jeu prendra une liste de mots et crera une grille de 15 15 lettres reprsentant ces mots parmi dautres lettres alatoires. La Figure 9.3 prsente un exemple de grille complte. Nous allons donc commencer par une grille vide et slectionner des mots alatoires dans la liste, des positions alatoires et des directions alatoires. Ensuite, nous essaierons dinsrer le mot. Sil ne tient pas ou sil recouvre des lettres dj places dans la grille, le placement est rejet et une nouvelle tentative est effectue avec un autre mot, un autre emplacement et une autre direction.
Figure 9.3
La grille au dpart, avec la liste de mots sur la droite.

Tous les puzzles de mots mls nutilisent pas les huit directions. Certains nafchent pas les mots en sens inverse, dautres nutilisent pas les diagonales. Tout est affaire de niveau de difcult. Les puzzles les plus simples conviennent aux jeunes enfants, mais sont bien trop simples pour les adultes.

Cette boucle se rpte jusqu ce que tous les mots soient placs ou quun nombre prdni de tentatives ait t ralis. Cela nous permet dviter les cas o il ne reste plus despace pour un mot. Il nest donc pas assur que tous les mots tiennent dans le puzzle. Notre exemple nutilise que neuf mots ; il est donc peu probable que cela se produise, mais les listes plus longues peuvent rencontrer des problmes. Les listes de mots extrmement longues nutiliseront quun chantillon des mots chaque fois, ce qui rend le jeu plus intressant jouer plusieurs fois de suite par la mme personne.

342

ActionScript 3.0 pour les jeux

Une fois que les mots ont t placs, toutes les positions de lettres non utilises sont remplies avec des lettres alatoires. En outre, une liste des mots inclus est place droite de lcran. mesure que ces mots sont trouvs, ils changent de couleur dans la liste. Le joueur utilise la souris pour cliquer sur la grille et faire glisser sa slection. Nous dessinerons une ligne sous les lettres an dindiquer celles qui sont slectionnes. Nous ne le ferons cependant que pour les slections valides, autrement dit pour les slections horizontales, verticales ou en diagonale 45 degrs. La Figure 9.4 montre les diffrentes directions dans lesquelles un mot peut tre dispos.
Figure 9.4
Les slections valides peuvent sorienter dans huit directions diffrentes.

Une fois que tous les mots ont t trouvs, la partie se termine.

Dnition de la classe
Limage du jeu dans lanimation est compltement vide. Tout sera cr par le code ActionScript. Pour cela, nous aurons besoin des bibliothques de classes ash.display, ash.text, ash.geom et ash.events :
package { import ash.display.*; import ash.text.*; import ash.geom.Point; import ash.events.*;

Chapitre 9

Jeux de mots : pendu et mots mls

343

Plusieurs constantes faciliteront lajustement de la taille du puzzle, lespacement entre les lettres, la taille de la ligne de surlignement, le dcalage cran et le format du texte :
public class WordSearch extends MovieClip { // Constantes static const puzzleSize:uint = 15; static const spacing:Number = 24; static const outlineSize:Number = 20; static const offset:Point = new Point(15,15); static const letterFormat:TextFormat = new TextFormat("Arial",18,0x000000,true, false,false,null,null,TextFormatAlign.CENTER);

Pour tenir le registre des mots et de la grille des lettres, nous utiliserons les trois tableaux suivants :
// Mots et grille private var wordList:Array; private var usedWords:Array; private var grid:Array;

Le dragMode indique si le joueur slectionne actuellement une squence de lettres. startPoint et endPoint dnissent cette plage de lettres. numFound comptabilise tous les mots trouvs :
// tat du jeu private var dragMode:String; private var startPoint,endPoint:Point; private var numFound:int;

Ce jeu utilisera plusieurs Sprite. Le gameSprite contient tout. Les autres contiennent un type dlment particulier :
// Sprites private var gameSprite:Sprite; private var outlineSprite:Sprite; private var oldOutlineSprite:Sprite; private var letterSprites:Sprite; private var wordsSprite:Sprite;

Crer la grille de recherche des mots


La fonction startWordSearch a beaucoup faire pour crer une grille de puzzle utiliser dans le jeu. Elle sappuiera sur la fonction placeLetters pour raliser une partie du travail.

344

ActionScript 3.0 pour les jeux

La fonction startWordSearch
Pour lancer le jeu, nous allons crer un tableau avec les mots utiliss dans le puzzle. Dans cet exemple, nous utiliserons les neuf plantes, en ignorant les rcentes indispositions de lUnion internationale dastronomie concernant le statut de Pluton :
public function startWordSearch() { // Liste des mots wordList = ("Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus, Neptune,Pluto").split(",");

Les Sprite sont ensuite crs. Ils le sont dans lordre o ils doivent tre disposs sur la scne. Les lignes de surbrillance doivent se trouver sous les lettres. Seul le gameSprite est ajout la scne. Tous les autres sont ajouts au gameSprite :
// Conguration des sprites gameSprite = new Sprite(); addChild(gameSprite); oldOutlineSprite = new Sprite(); gameSprite.addChild(oldOutlineSprite); outlineSprite = new Sprite(); gameSprite.addChild(outlineSprite); letterSprites = new Sprite(); gameSprite.addChild(letterSprites); wordsSprite = new Sprite(); gameSprite.addChild(wordsSprite);

Les Sprite des lettres seront stocks dans le tableau grid. Nous appellerons cependant dabord placeLetters an dobtenir un tableau imbriqu avec les caractres placer dans ces Sprite. En fait, nous nous occupons de dcomposer en deux tapes la tche qui consiste crer la grille du jeu. La premire tape sert crer une grille virtuelle de lettres sous forme de tableau imbriqu. Elle servira ajouter les mots de la liste des mots et remplir le reste avec des lettres alatoires :
// Tableau de lettres var letters:Array = placeLetters();

Maintenant que nous savons o les lettres seront places, nous devons crer les Sprite, raison dun par lettre. Pour commencer, chaque lettre obtient un TextField. Ensuite, ce champ est ajout un nouveau Sprite :
// Tableau de sprites grid = new Array(); for(var x:int=0;x<puzzleSize;x++) {

Chapitre 9

Jeux de mots : pendu et mots mls

345

grid[x] = new Array(); for(var y:int=0;y<puzzleSize;y++) { // Crer un nouveau champ et un sprite pour la lettre var newLetter:TextField = new TextField(); newLetter.defaultTextFormat = letterFormat; newLetter.x = x*spacing + offset.x; newLetter.y = y*spacing + offset.y; newLetter.width = spacing; newLetter.height = spacing; newLetter.text = letters[x][y]; newLetter.selectable = false; var newLetterSprite:Sprite = new Sprite(); newLetterSprite.addChild(newLetter); letterSprites.addChild(newLetterSprite); grid[x][y] = newLetterSprite;

En plus dtre cr et ajout letterSprites, chaque Sprite doit se voir associer deux vnements : MOUSE_DOWN et MOUSE_OVER. Le premier dmarre une slection et le second permet la slection dtre mise jour mesure que le curseur survole des lettres diffrentes :
// Ajout des couteurs vnementiels newLetterSprite.addEventListener(MouseEvent.MOUSE_DOWN, clickLetter); newLetterSprite.addEventListener(MouseEvent.MOUSE_OVER, overLetter); } }

Lorsque le joueur relche le bouton de la souris, nous ne pouvons avoir la garantie quil se trouve audessus dune lettre ce moment. Au lieu dattacher lcouteur vnementiel MOUSE_UP aux lettres, nous lattachons donc la scne :
// couteur de la scne stage.addEventListener(MouseEvent.MOUSE_UP, mouseRelease);

La dernire chose crer est la liste des mots droite. Il sagit dune simple collection dobjets TextField placs dans le Sprite wordsSprite. Un objet est cr pour chaque mot dans le tableau usedWords. Ce tableau sera cr par placeLetters et ne contiendra que les mots qui ont pu trouver place dans le puzzle :
// Crer les champs et les sprites de la liste de mots for(var i:int=0;i<usedWords.length;i++) { var newWord:TextField = new TextField();

346

ActionScript 3.0 pour les jeux

newWord.defaultTextFormat = letterFormat; newWord.x = 400; newWord.y = i*spacing+offset.y; newWord.width = 140; newWord.height = spacing; newWord.text = usedWords[i]; newWord.selectable = false; wordsSprite.addChild(newWord); }

Le jeu est prt tre jou, hormis quil faut encore dnir les variables dragMode et numFound :
// Dnition de ltat du jeu dragMode = "none"; numFound = 0; }

La fonction placeLetters
La fonction placeLetters ralise plusieurs tches pineuses. Pour commencer, elle cre une grille vide de 15 15 caractres sous forme de tableau imbriqu. Chaque emplacement dans la grille est rempli avec un * qui reprsente un emplacement vide dans le puzzle :
// Placer les mots dans une grille de lettres public function placeLetters():Array { // Crer une grille vide var letters:Array = new Array(); for(var x:int=0;x<puzzleSize;x++) { letters[x] = new Array(); for(var y:int=0;y<puzzleSize;y++) { letters[x][y] = *; } }

Ltape suivante consiste crer une copie de wordList. Nous souhaitons utiliser une copie et non loriginal car nous allons supprimer des mots mesure que nous les plaons dans la grille. Nous placerons en outre les mots que nous utilisons dans un nouveau tableau appel usedWords :
// Crer une copie de la liste des mots var wordListCopy:Array = wordList.concat(); usedWords = new Array();

Chapitre 9

Jeux de mots : pendu et mots mls

347

Il est maintenant temps dajouter des mots dans la grille. Cette opration seffectue en choisissant un mot alatoire, un emplacement alatoire et une direction alatoire. Ensuite, nous essayons de placer le mot dans la grille, lettre par lettre. Si un conit se produit (par exemple, le bord de la grille est atteint ou une lettre existante dans la grille ne correspond pas la lettre que nous souhaitons placer cet endroit), la tentative est annule. Nous poursuivrons nos essais, en insrant parfois un mot, en chouant dautres fois. Nous continuerons ainsi jusqu ce que wordListCopy soit vide. Nous comptabiliserons cependant aussi le nombre de tentatives opres dans repeatTimes, qui commencera 1 000 et dcrotra chaque tentative. Si repeatTimes atteint zro, nous cessons dajouter des mots. ce point, il est fort probable que tous les mots capables de tenir dans le puzzle sy trouvent dj. Nous nutiliserons pas le reste des mots dans cette conguration alatoire.

Nous utiliserons la technique qui consiste tiqueter les boucles an de pouvoir utiliser la commande continue pour forcer le programme passer directement au dbut dune boucle en dehors de la boucle actuelle. Sans ces tiquettes, il serait bien plus difcile de crer le code qui suit.

// Oprer 1 000 tentatives pour ajouter les mots var repeatTimes:int = 1000; repeatLoop:while (wordListCopy.length > 0) { if (repeatTimes-- <= 0) break;

// Slectionner un mot, un emplacement et une direction alatoires var wordNum:int = Math.oor(Math.random()*wordListCopy.length); var word:String = wordListCopy[wordNum].toUpperCase(); x = Math.oor(Math.random()*puzzleSize); y = Math.oor(Math.random()*puzzleSize); var dx:int = Math.oor(Math.random()*3)-1; var dy:int = Math.oor(Math.random()*3)-1; if ((dx == 0) && (dy == 0)) continue repeatLoop;

// Vrier chaque emplacement dans la grille pour voir si le mot tient letterLoop:for (var j:int=0;j<word.length;j++) { if ((x+dx*j < 0) | | (y+dy*j < 0) | | (x+dx*j >= puzzleSize) | | (y+dy*j >= puzzleSize)) continue repeatLoop; var thisLetter:String = letters[x+dx*j][y+dy*j]; if ((thisLetter != *) && (thisLetter != word.charAt(j))) continue repeatLoop;

348

ActionScript 3.0 pour les jeux

} // Insrer le mot dans la grille insertLoop:for (j=0;j<word.length;j++) { letters[x+dx*j][y+dy*j] = word.charAt(j); } // Supprimer le mot de la liste wordListCopy.splice(wordNum,1); usedWords.push(word); }

Maintenant que nous avons de vrais mots dans la grille, celle-ci doit ressembler celle de la Figure 9.5, qui reprsente un jeu sans ltape suivante.
Figure 9.5
Cette grille contient des caractres * lendroit o les lettres alatoires seront places.

Les boucles suivantes examinent chacune des caractres dans la grille et remplacent le * par une lettre alatoire :
// Remplir le reste de la grille avec des lettres alatoires for(x=0;x<puzzleSize;x++) { for(y=0;y<puzzleSize;y++) { if (letters[x][y] == "*") { letters[x][y] = String.fromCharCode(65+Math.oor(Math.random()*26)); } } }

Chapitre 9

Jeux de mots : pendu et mots mls

349

Lorsque la fonction placeLetters a termin, elle retourne son tableau an que les Sprite puissent tre crs :
return letters; }

Interaction de lutilisateur
Nous utiliserons des couteurs pour surveiller trois actions de souris : le clic, le survol dun nouveau Sprite et le relchement du bouton de la souris.

Clic de souris
Lorsque le joueur clique sur une lettre, la position sur la grille est dtermine et place dans startPoint. En outre, dragMode est positionn "drag". La fonction ndGridPoint retourne un Point avec la position de la lettre dans la grille. Nous construirons cette fonction plus tard :
// Le joueur clique sur une lettre pour commencer public function clickLetter(event:MouseEvent) { var letter:String = event.currentTarget.getChildAt(0).text; startPoint = ndGridPoint(event.currentTarget); dragMode = drag; }

Glissement du curseur
chaque fois que le curseur passe sur une lettre lcran, la fonction overLetter suivante est appele. Elle vrie cependant dabord que dragMode vaut "drag". Le gros de la fonction ne sexcute donc quune fois que le joueur a cliqu sur une lettre. Le point courant est stock dans endPoint. Maintenant que nous avons un point de dpart (startPoint) et de n (endPoint), nous pouvons vrier la plage an de voir si elle est valide. Nous supposerons quelle ne lest pas, en effaant le calque graphique outlineSprite en premier. Sil sagit dune plage valide, drawOutline congure cependant le calque graphique outlineSprite avec une nouvelle ligne. En n de compte, le surlignement est supprim et redessin chaque fois que le curseur change de lettre :
// Le joueur slectionne des lettres public function overLetter(event:MouseEvent) { if (dragMode == "drag") { endPoint = ndGridPoint(event.currentTarget);

// Si la plage est valide, afcher la ligne de surbrillance

350

ActionScript 3.0 pour les jeux

outlineSprite.graphics.clear(); if (isValidRange(startPoint,endPoint)) { drawOutline(outlineSprite,startPoint,endPoint,0xFF0000); } } }

Relchement de la souris
Lorsque le joueur relche la souris sur une lettre, dragMode se voit attribuer la valeur "none" et la ligne de surbrillance est efface. Ensuite, si la plage est valide, deux fonctions sont appeles pour grer la slection. La fonction getSelectedWord rcupre la plage et retourne les lettres quelle contient. Ensuite, la fonction checkWord vrie si ce mot se trouve dans la liste et agit en fonction :
// Bouton de souris relch public function mouseRelease(event:MouseEvent) { if (dragMode == "drag") { dragMode = "none"; outlineSprite.graphics.clear(); // Rcuprer le mot et le vrier if (isValidRange(startPoint,endPoint)) { var word = getSelectedWord(); checkWord(word); } } }

Fonctions utilitaires
La fonction ndGridPoint prend un Sprite de lettre et dtermine lemplacement auquel il se trouve. Comme les Sprite sont crs de toutes pices, ils ne peuvent pas se voir attribuer des variables dynamiques. Nous ne pouvons donc pas stocker les valeurs x et y avec chacun des Sprite. Au lieu de cela, nous examinerons donc simplement la grille et trouverons dedans llment qui correspond au Sprite :
// Lorsque le joueur clique sur une lettre, trouver et retourner lemplacement x et y public function ndGridPoint(letterSprite:Object):Point { // Parcourir en boucle tous les sprites et trouver celui-ci for(var x:int=0;x<puzzleSize;x++) {

Chapitre 9

Jeux de mots : pendu et mots mls

351

for(var y:int=0;y<puzzleSize;y++) { if (grid[x][y] == letterSprite) { return new Point(x,y); } } } return null; }

Pour dterminer si deux points dans le puzzle constituent une plage valide, nous ralisons trois tests. Sils se trouvent tous deux sur la mme ligne ou la mme colonne, la plage est valide. Le troisime test examine la diffrence x et y. En cas dgalit en valeur absolue, la slection est une diagonale 45 degrs :
// Dterminer si la plage se trouve dans la mme ligne, colonne ou dans une diagonale 45 degrs public function isValidRange(p1,p2:Point):Boolean { if (p1.x == p2.x) return true; if (p1.y == p2.y) return true; if (Math.abs(p2.x-p1.x) == Math.abs(p2.y-p1.y)) return true; return false; }

Le trac de la ligne de surbrillance derrire les lettres aurait d tre lun des problmes les plus pineux rsoudre de ce jeu. Oui, mais on a parfois de la chance. Grce aux extrmits arrondies utilises par dfaut pour les traits, il suft de tracer une ligne dun emplacement lautre, de la rendre sufsamment esthtique et paisse pour obtenir un trait de surbrillance dexcellente apparence. Vous remarquerez quil est ncessaire de compenser pour placer les extrmits de la ligne au centre des lettres. Les emplacements des lettres correspondent au coin suprieur gauche du TextField et donc au coin suprieur gauche du Sprite des lettres. La moiti de la constante spacing est donc ajoute an de compenser ce dcalage :
// Tracer une ligne paisse dun emplacement un autre public function drawOutline(s:Sprite,p1,p2:Point,c:Number) { var off:Point = new Point(offset.x+spacing/2, offset.y+spacing/2); s.graphics.lineStyle(outlineSize,c); s.graphics.moveTo(p1.x*spacing+off.x ,p1.y*spacing+off.y); s.graphics.lineTo(p2.x*spacing+off.x ,p2.y*spacing+off.y); }

352

ActionScript 3.0 pour les jeux

Grer les mots trouvs


Lorsque le joueur termine une slection, la premire chose faire est de crer un mot partir des lettres de la slection. Pour cela, nous allons dterminer les valeurs dx et dy entre les deux points, ce qui nous aide slectionner les lettres dans la grille. En commenant partir de startPoint, nous avanons une lettre la fois. Si la valeur dx est positive, chaque tape implique davancer dune colonne vers la droite. Si elle est ngative, chaque tape avance dune colonne vers la gauche. Idem pour dy vers le haut et vers le bas. Ce dispositif nous guidera dans les huit directions possibles dune slection valide. Le rsultat nal correspond une chane de lettres, les mmes que celles qui apparaissent dans la slection lcran :
// Trouver les lettres slectionnes en fonction des points de dpart et de n public function getSelectedWord():String {

// Dterminer dx et dy de la slection et longueur du mot var dx = endPoint.x-startPoint.x; var dy = endPoint.y-startPoint.y; var wordLength:Number = Math.max(Math.abs(dx),Math.abs(dy))+1;

// Rcuprer chaque caractre de la slection var word:String = ""; for(var i:int=0;i<wordLength;i++) { var x = startPoint.x; if (dx < 0) x -= i; if (dx > 0) x += i; var y = startPoint.y; if (dy < 0) y -= i; if (dy > 0) y += i; word += grid[x][y].getChildAt(0).text; } return word; }

Une fois que nous connaissons le mot que le joueur pense avoir trouv, nous pouvons parcourir en boucle le tableau usedWords et comparer les lettres trouves avec les mots de la liste. Nous devons les comparer de gauche droite et de droite gauche. Nous ne souhaitons pas imposer au joueur quil slectionne la premire lettre en premier, notamment parce que nous allons afcher certains mots en les renversant dans la grille.

Chapitre 9

Jeux de mots : pendu et mots mls

353

Pour inverser un mot, lun des moyens rapides consiste utiliser split pour convertir la chane en un tableau puis reverse pour inverser le tableau et join pour revenir une chane. split et join prennent "" (une chane vide) comme sparateur, car nous souhaitons que chaque caractre soit son propre lment dans le tableau :
// Comparer le mot la liste de mots public function checkWord(word:String) {

// Parcourir en boucle les mots for(var i:int=0;i<usedWords.length;i++) {

// Comparer le mot if (word == usedWords [i].toUpperCase()) { foundWord(word); }

// Comparer le mot invers var reverseWord:String = word.split("").reverse().join(""); if (reverseWord == usedWords [i].toUpperCase()) { foundWord(reverseWord); } } }

Lorsquun mot est trouv, nous souhaitons tracer un trait permanent et supprimer le mot de la liste de droite. La fonction drawOutline peut tracer la ligne sur nimporte quel Sprite. Nous lui ferons donc cette fois tracer la ligne sur oldOutlineSprite (en utilisant une teinte de rouge plus claire). Ensuite, nous parcourons en boucle les objets TextField dans wordsSprite et examinons la proprit text de chacun dentre eux. Si elle correspond au mot, la couleur du TextField est remplace par un gris clair. Nous augmenterons galement numFound et appellerons endGame si tous les mots ont t trouvs :
// Mot trouv, supprimer de la liste, crer trait de surbrillance permanent public function foundWord(word:String) {

// Tracer le trait de surbrillance dans le sprite permanent drawOutline(oldOutlineSprite,startPoint,endPoint,0xFF9999);

354

ActionScript 3.0 pour les jeux

// Trouver le champ texte et le passer en gris for(var i:int=0;i<wordsSprite.numChildren;i++) { if (TextField(wordsSprite.getChildAt(i)).text.toUpperCase() == word) { TextField(wordsSprite.getChildAt(i)).textColor = 0xCCCCCC; } }

// Voir si tous les mots ont t trouvs numFound++; if (numFound == usedWords.length) { endGame(); } }

La fonction endGame conduit simplement le scnario principal limage gameover. Nous souhaitons non pas encore effacer les sprites du jeu mais plutt les faire apparatre sous le message "Game Over" et le bouton Play Again. Pour mieux faire ressortir ces lments, je les ai placs sur un rectangle uni. Sans cela, ils se fondraient avec la grille de lettres (voir Figure 9.6).
Figure 9.6
Le rectangle permet de mieux faire ressortir le texte Game Over et le bouton.

Chapitre 9

Jeux de mots : pendu et mots mls

355

public function endGame() { gotoAndStop(gameover); }

Le bouton Play Again appelle cleanUp et conduit limage play pour redmarrer le jeu. Comme nous avons stock tous nos Sprite dans le seul Sprite gameSprite, nous pouvons nous dbarrasser de ce dernier pour effacer la grille :
public function cleanUp() { removeChild(gameSprite); gameSprite = null; grid = null; }

Modier le jeu
Lintrt du joueur pour le jeu peut tre fortement li son intrt pour les mots. Vous pouvez crer un puzzle sur nimporte quelle thmatique. Il suft simplement dune liste de mots spars par des virgules. En fait, vous pouvez utiliser la technique du Chapitre 2 pour linclusion de variables dans le code HTML dune page Web an de passer une liste de mots courte. Un unique jeu de mots mls pourrait alors tre utilis dans plusieurs pages de votre site avec une liste de mots diffrente. Vous pouvez galement ajuster aisment les dimensions du puzzle ainsi que la taille et lespacement des lettres, par exemple an de proposer des mots mls pour les enfants. Lautre moyen dobtenir des listes de mots consiste les importer partir de chiers externes. Nous verrons comment importer des donnes externes au chapitre suivant.

10
Questions et rponses : quiz et jeux de culture gnrale
Au sommaire de ce chapitre :

Stocker et rcuprer des donnes de jeu Quiz de culture gnrale Quiz version Deluxe Quiz en images

358

ActionScript 3.0 pour les jeux

Diffrents jeux peuvent tre utiliss diffrentes ns, mais il existe peu de jeux qui puissent tre utiliss pour des besoins aussi diffrents que les jeux de quiz. Vous pouvez crer un quiz sur quasiment nimporte quel sujet et nimporte quel niveau de difcult. La partie la plus difcile pour la cration de jeux de quiz consiste les rendre intressants. Aprs tout, une srie de questions choix multiples, ce nest rien de plus quun test. Or peu de gens sont naturellement enclins passer des tests. Les jeux de quiz et de culture gnrale sappuient sur des donnes. Ils se servent de questions et de rponses comme lments de jeu principaux. Ces donnes texte sont de prfrence stockes dans des chiers externes et importes de manire dynamique dans le jeu. Nous examinerons les stratgies possibles pour cela avant dtudier les jeux eux-mmes. Aprs cela, nous crerons un jeu de quiz qui rcupre un chier texte externe et utilise les questions et rponses quil contient comme donnes du jeu. Nous ferons ensuite un pas de plus et utiliserons des images externes dans un jeu de quiz en images.

Stocker et retrouver des donnes de jeu


Codes sources http://ashgameu.com A3GPU10_XMLExamples.zip Les jeux de culture gnrale requirent une liste de questions et de rponses. Le meilleur moyen de faire venir ces donnes au dbut dun jeu consiste les lire dans un chier XML.

Flash prfre le XML aux autres types de chiers de donnes externes. Flash ne peut en ralit lire que deux types de chiers : le XML et une liste dattributions de variables. Le second format nest vritablement utile que pour les petites tches. Le XML peut tre utilis pour de trs grandes bases de donnes sil le faut.

Comprendre les donnes XML


XML est lacronyme deXtensible Markup Language (langage de balisage extensible). Son rle consiste proposer un format simple pour lchange dinformations entre systmes. Si vous navez jamais vu de chier XML auparavant mais que vous ayez travaill en HTML, vous remarquerez une similarit. Les signes infrieur et suprieur sont utiliss en XML pour entourer des mots-cls de dnition appels balises.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

359

Observez lexemple suivant :


<trivia> <item category=Entertainment> <question>Who is known as the original drummer of the Beatles?</question> <answers> <answer>Pete Best</answer> <answer>Ringo Starr</answer> <answer>Stu Sutcliffe</answer> <answer>George Harrison</answer> </answers> <hint>Was red before the Beatles hit it big.</hint> <fact>Pete stayed until shortly after their rst audition for EMI in 1962, but was red on August 16th of that year, to be replaced by Ringo Starr.</fact> </item> </trivia>

Ce chier XML reprsente un quiz une question. Les donnes suivent un format imbriqu : des balises sont places lintrieur dautres balises. Par exemple, le document entier correspond un objet <trivia>. lintrieur de cet objet gure un <item>. Dans cet objet <item> gure une <question>, un objet <answers> avec quatre objets <answer>, un objet <hint> et un objet <fact>.

Les objets individuels des documents XML sont aussi appels des nuds. Un nud peut contenir simplement des donnes ou avoir plusieurs nuds enfants. Certains nuds se voient associer des donnes supplmentaires, comme le nud item, qui dans cet exemple possde une category. On les appelle des attributs.

Vous pouvez placer un document XML directement lintrieur de votre code ActionScript 3.0. Par exemple, lanimation dexemple xmlExample.a en contient un dans le script de limage 1 :
var myXML:XML = <trivia> <item category="Entertainment"> <question>Who is known as the original drummer of the Beatles?</question> <answers> <answer>Pete Best</answer> <answer>Ringo Starr</answer> <answer>Stu Sutcliffe</answer> <answer>George Harrison</answer>

360

ActionScript 3.0 pour les jeux

</answers> <hint>Was red before the Beatles hit it big.</hint> <fact>Pete stayed until shortly after their rst audition for EMI in 1962, but was red on August 16th of that year, to be replaced by Ringo Starr.</fact> </item> </trivia>

Vous remarquerez quaucun guillemet ni parenthse nest requis autour des donnes XML. Elles peuvent tout simplement gurer lintrieur du code ActionScript 3.0 (vous imaginez cependant combien cela peut devenir incommode si les donnes deviennent plus longues). Maintenant que nous avons des donnes XML dans un objet XML, nous pouvons nous amuser en extraire des informations.

La gestion des donnes XML a t considrablement amliore avec ActionScript 3.0. Auparavant, il fallait utiliser des instructions plus complexes pour trouver un nud spcique dans les donnes. Le nouvel objet XML dans ActionScript 3.0 diffre de lobjet XML sous ActionScript 2.0, ce qui signie que vous ne pouvez pas effectuer la conversion directe de lun lautre. Faites donc attention aux anciens exemples de code qui pourraient toujours se trouver au format ActionScript 2.0.

Pour obtenir le nud question dans les donnes, vous procderiez ainsi :
trace(myXML.item.question);

Voil qui est plutt simple. Pour obtenir un attribut, il suft dutiliser la fonction attribute :
trace(myXML.item.attribute(category));

Le symbole

@ peut tre utilis comme raccourci pour obtenir lattribut. Au lieu .attribute("category"), vous pouvez donc aussi crire myXML.item.@category.

de

myXML.item

Dans le cas du nud <answers>, il y a quatre rponses (answer). Celles-ci peuvent tre traites comme un tableau en y accdant avec des crochets :
trace(myXML.item.answers.answer[1]);

Lobtention du nombre de nuds lintrieur dun autre nud, par exemple du nombre de nuds <answer>, est un peu moins vidente. Vous devez procder de la manire suivante :
trace(myXML.item.answers.child("*").length());

La fonction child retourne un enfant dun nud spci par une chane ou un nombre. En revanche, "*" retourne tous les nuds enfants. length() fournit ensuite le nombre de nuds enfants. Si vous

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

361

essayez simplement dobtenir la longueur dun nud avec length(), vous obtiendrez le rsultat 1, car un nud fait toujours un de longueur. Maintenant que vous savez comment trouver votre chemin dans les donnes XML, commenons grer des documents XML plus grands imports depuis des chiers externes.

Importer des chiers XML externes


Lorsque le XML est enregistr sous forme de chier, il est semblable un chier de texte brut. Vous pouvez dailleur ouvrir vos chiers XML avec pratiquement nimporte quel diteur de texte. Le chier trivia1.xml est un chier court contenant simplement dix lments de quiz. Pour ouvrir et lire un chier externe, nous allons utiliser les objets URLRequest et URLLoader. Nous dnirons ensuite un vnement dclencher lorsque le chier aura t charg. Lexemple de code suivant prsente un fragment de code de chargement XML provenant de xmlimport. as. La fonction constructeur cre un objet URLRequest avec le nom du chier XML. Ensuite, URLLoader lance le tlchargement.

Vous pouvez passer nimporte quelle URL valide URLRequest. Lusage dun simple nom de chier comme nous lavons fait ici implique que le chier se trouve aux cts de lanimation Flash SWF, dans le mme dossier. Vous pouvez cependant sparer un sous-dossier ou mme utiliser ../ et dautres fonctionnalits de cheminement pour indiquer une URL relative. Vous pouvez enn aussi spcier des URL absolues, qui fonctionnent aussi bien sur le serveur et lors du test local sur votre ordinateur.

Nous allons attacher un couteur au URLLoader. Cet couteur appellera xmlLoaded lorsque le chier aura t compltement tlcharg :
package { import ash.display.*; import ash.events.*; import ash.net.URLLoader; import ash.net.URLRequest; public class xmlimport extends MovieClip { private var xmldata:XML; public function xmlimport() { xmldata = new XML(); var xmlURL:URLRequest = new URLRequest("xmltestdata.xml"); var xmlLoader:URLLoader = new URLLoader(xmlURL); xmlLoader.addEventListener(Event.COMPLETE,xmlLoaded); }

362

ActionScript 3.0 pour les jeux

La fonction xmlLoaded prend les donnes charges de event.target.data et les convertit en XML pour les stocker dans xmldata. En guise de test, plaons la seconde rponse la premire question dans la fentre Sortie :
function xmlLoaded(event:Event) { xmldata = XML(event.target.data);

trace(xmldata.item.answers.answer[1]); trace(Data loaded.); } } }

Les objets XML, comme les tableaux, sont indics zro. La premire rponse du prcdent exemple se trouve donc la position 0 et la seconde, la position 1.

Capturer les erreurs de chargement


Puisquon nest jamais labri dune erreur, il est toujours utile de mettre en place un mcanisme de vrication des erreurs. Vous pouvez le faire en ajoutant un autre vnement URLLoader :
xmlLoader.addEventListener(IOErrorEvent.IO_ERROR,xmlLoadError);

Ensuite, vous pouvez obtenir le message derreur de lvnement retourn xmlLoadError :


function xmlLoadError(event:IOErrorEvent) { trace(event.text); }

Je nindiquerai cependant pas lutilisateur nal le message derreur verbatim. Par exemple, si vous supprimez simplement le chier et essayez de lancer lanimation, vous obtenez lerreur suivante suivie par le nom de chier :
Error #2032: Stream Error. URL: le:

Ce nest pas le genre de message derreur que vous souhaiterez prsenter au joueur. Il vaudrait mieux quelque chose du genre "Unable to load game le" (le chier du jeu na pas pu tre charg). Vous savez maintenant comment rcuprer des documents XML plus imposants, comme ceux dont vous aurez besoin pour crer des jeux de culture gnrale.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

363

Quiz de culture gnrale


Codes sources http://ashgameu.com A3GPU10_TriviaGame.zip Le quiz de culture gnrale aussi baptis Trivia est devenu pour la premire fois une forme de divertissement dans les annes 1950, avec lapparition de la tlvision. Les shows tlviss de quiz sont devenus de plus en plus populaires au l des ans. Dans les annes 1980, les jeux de socit comme le Trivial Pursuit ont rencontr un franc succs et permis aux gens de jouer des jeux de culture gnrale en plus de les regarder. Ces jeux sont rapidement devenus disponibles sur les ordinateurs et sur Internet. Les jeux de culture gnrale sont un bon moyen de dcliner des jeux sur tous les sujets. Votre site Web concerne les pirates ? Crez un jeu de quiz sur les pirates. Vous crez un CD-ROM pour une confrence Francfort ? Ajoutez un jeu de quiz avec des faits intressants concernant la ville. Crons dabord un jeu de quiz simple, puis ajoutons des gadgets au fur et mesure.

Concevoir un jeu de quiz simple


Le jeu de quiz lmentaire correspond simplement une srie de questions. Le joueur lit une question, puis slectionne une rponse parmi plusieurs possibles. Les joueurs ont un point ou une forme de rcompense en cas de bonne rponse. Ensuite, le jeu passe la question suivante. Nous construirons ce jeu comme tous les autres : avec trois images, laction prenant place dans limage du milieu. Dans le cas prsent, laction dsigne une srie dlments de texte et de boutons. Nous commencerons par demander au joueur sil est prt commencer. Il cliquera sur un bouton pour dmarrer (voir Figure 10.1). Le joueur se voit ensuite prsenter une question et quatre rponses. Il doit choisir une rponse. Si la rponse quil choisit est juste, le message "You Got It!" (trouv!) apparat. En cas derreur, il obtient le message "Incorrect". Dans un cas comme dans lautre, le joueur voit apparatre un autre bouton sur lequel il doit cliquer pour passer la question suivante. Ouvrez TriviaGame.a et essayez de jouer an de mieux comprendre le fonctionnement du jeu. prsent, construisons le jeu.

364

ActionScript 3.0 pour les jeux

Figure 10.1
Au dbut du jeu, le joueur voit apparatre un bouton sur lequel il doit cliquer avant dobtenir la premire question.

Congurer lanimation
Le chier danimation nutilise que deux images au lieu des trois que nous avons eu lhabitude dutiliser. Nous aurons besoin dun nouvel lment dans la bibliothque de notre animation pour crer le jeu de quiz. Il sagira dun cercle contenant une lettre et qui safchera ct dune rponse. La Figure 10.2 prsente ce clip. Le champ texte dans le clip Circle est appel letter. Nous en crerons quatre comme celui-l, un pour chaque rponse, et les placerons ct du texte de la rponse. La lettre sera chaque fois diffrente : A, B, C ou D.

Si vous observez attentivement la Figure 10.2, vous remarquerez que le point dalignement du clip est dcal vers le haut et la droite. Ce point correspond lemplacement 0,0 du champ texte qui ira ct. Nous pouvons ainsi attribuer Circle et au champ texte de rponse le mme emplacement et les faire apparatre cte cte au lieu de lun sur lautre.

La mme technique de limage darrire-plan et du champ texte sera utilise dans le clip GameButton. Cela nous permettra dutiliser le mme clip de bouton pour diffrents boutons dans le jeu. Lanimation contient galement des graphismes darrire-plan, dont un titre et des lignes horizontales (voir Figure 10.1).

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

365

Figure 10.2
Le clip Circle contient un champ texte dynamique et un cercle darrire-plan.

Congurer la classe
Comme ce jeu charge les donnes du quiz partir dun chier externe, nous avons besoin de certaines parties de la bibliothque ash.net pour utiliser les fonctions URLLoader et URLRequest :
package { import ash.display.*; import ash.text.*; import ash.events.*; import ash.net.URLLoader; import ash.net.URLRequest;

Le jeu utilisera un certain nombre de variables. Nous placerons les donnes charges depuis le chier dans dataXML. Nous avons galement diffrents formats texte et des rfrences des champs texte dynamiques que nous allons crer :
public class TriviaGame extends MovieClip { // Donnes de question private var dataXML:XML; // Formats texte private var questionFormat:TextFormat;

366

ActionScript 3.0 pour les jeux

private var answerFormat:TextFormat; private var scoreFormat:TextFormat; // Champs texte private var messageField:TextField; private var questionField:TextField; private var scoreField:TextField;

Lide pour les sprites est davoir un gameSprite qui contient tout. lintrieur, nous aurons un questionSprite contenant tous les lments dune unique question de quiz : un champ texte pour la question et dautres sprites pour les rponses. Les answerSprites contiendront les champs texte et les clips Circle pour chaque rponse, qui seront stocks dans leur propre sprite. Nous navons cependant pas besoin dune variable de classe pour les rfrencer, car ils seront proprement stocks dans le sprite answerSprites. Nous aurons aussi une rfrence pour le bouton GameButton, an que lorsque nous crons un bouton nous puissions utiliser cette rfrence pour le supprimer :
// Sprites et objets private var gameSprite:Sprite; private var questionSprite:Sprite; private var answerSprites:Sprite; private var gameButton:GameButton;

Pour tenir le registre de ltat du jeu, nous avons besoin de questionNum, qui mmorise la question laquelle nous nous trouvons, de numCorrect, qui consigne le score du joueur, et de numQuestionsAsked, qui concerne galement la dtermination du score du joueur. Pour mmoriser la question pose, nous placerons les quatre rponses dans un ordre quelconque dans le tableau answers. Avant de les mlanger, nous tiendrons cependant note de la premire rponse dorigine, que nous savons correspondre la bonne rponse, dans la variable correctAnswer :
// Variables dtat du jeu private var questionNum:int; private var correctAnswer:String; private var numQuestionsAsked:int; private var numCorrect:int; private var answers:Array;

La fonction constructeur crera le gameSprite puis congurera les trois objets TextFormat :
public function startTriviaGame() { // Crer le sprite du jeu gameSprite = new Sprite(); addChild(gameSprite);

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

367

// Dnition des formats texte questionFormat = new TextFormat("Arial",24,0x330000, true,false,false,null,null,"center"); answerFormat = new TextFormat("Arial",18,0x330000, true,false,false,null,null,"left"); scoreFormat = new TextFormat("Arial",18,0x330000, true,false,false,null,null,"center");

Il nexiste pas de moyen de dupliquer un objet TextFormat. Si vous tapez simplement answerFormat = questionFormat puis apportez une modication lun des deux formats, lautre change galement. Il est donc important de crer un nouvel objet TextFormat pour chacune des variables. Vous pouvez en revanche dnir une variable temporaire comme myFont en lui attribuant une valeur telle que "Arial" puis utiliser myFont la place de "Arial" dans chacune des dclarations TextFormat. Vous pourrez alors modier la police utilise dans le jeu en oprant un unique changement un seul emplacement du code.

Lorsque le jeu dmarre, les champs texte scoreField et messageField sont crs. Au lieu de crer un TextField, de lajouter avec addChild et de positionner chacune de ses proprits pour chacun des lments de texte requis, nous crons une fonction utilitaire appele createText qui se charge de cette tche pour nous en une ligne de code. Par exemple, le messageField contiendra le texte "Loading Questions " en utilisant le format questionFormat. Il le place dans le gameSprite 0,50 avec une largeur de 550. Nous examinerons createText plus tard :
// Crer les champs texte du score et du message de dpart scoreField = createText("",questionFormat,gameSprite,0,360,550); messageField = createText("Loading Questions...",questionFormat,gameSprite,0,50,550 );

Une fois que ltat du jeu est dni, nous appelons showScore pour placer le texte du score en bas de lcran. Nous tudierons cela plus tard galement. Nous appelons xmlImport pour rcuprer les donnes du quiz :
// Conguration de ltat et chargement des questions questionNum = 0; numQuestionsAsked = 0; numCorrect = 0; showScore(); xmlImport(); }

Le texte "Loading Questions " apparatra lcran et y restera jusqu ce que le document XML ait t lu. Lors du test de lanimation, cette tape peut prendre moins de 1 seconde. Une fois que le jeu se trouvera sur le serveur, elle devrait tre un peu plus longue, selon la ractivit de la connexion du joueur.

368

ActionScript 3.0 pour les jeux

Charger les donnes du quiz


Les questions sont charges en utilisant des fonctions analogues lexemple du dbut de ce chapitre. Pour ne pas encombrer le code de cet exemple, aucune vrication derreur nest opre. Le chier trivia1.xml contient dix lments :
// Lancer le chargement des questions public function xmlImport() { var xmlURL:URLRequest = new URLRequest("trivia1.xml"); var xmlLoader:URLLoader = new URLLoader(xmlURL); xmlLoader.addEventListener(Event.COMPLETE, xmlLoaded); }

Une fois le chargement termin, les donnes sont places dans dataXML. Ensuite, le message texte qui afchait "Loading Questions " est supprim. Il est remplac par un nouveau message indiquant "Get ready for the rst question!" (prparez-vous pour la premire question !). Une autre fonction utilitaire est appele pour crer un GameButton. Une tiquette de bouton "GO!" est place lintrieur du bouton. Nous examinerons showGameButton un peu plus loin dans ce chapitre :
// Questions charges public function xmlLoaded(event:Event) { dataXML = XML(event.target.data); gameSprite.removeChild(messageField); messageField = createText(Get ready for the rst question!,questionFormat, gameSprite,0,60,550); showGameButton(GO!); }

Le jeu attend maintenant que le joueur clique sur le bouton.

Texte du message et bouton de jeu


Plusieurs fonctions utilitaires sont requises dans ce jeu pour crer des champs texte et des boutons. Elles permettent de rduire sensiblement la longueur du code. Nous naurons pas rpter les mmes rglages TextField, addChild, x et y chaque fois que nous crons un champ texte. soccupe de rcuprer une srie de paramtres et de crer un nouvel objet TextField. Elle positionne les valeurs x, y, width et TextFormat en leur attribuant les valeurs passes en paramtre. Elle dnit galement des paramtres de constante comme multiline et wordWrap qui seront les mmes pour tout ce que nous crons dans le jeu.
createText

Lalignement du texte dans le champ variera : il sera parfois centr et dautres fois justi gauche. Ce rglage est inclus dans TextFormat. Nous souhaitons cependant attribuer la valeur qui convient la proprit autoSize du champ ; nous ralisons donc un test et attribuons autoSize la valeur TextFieldAutoSize.LEFT ou la valeur TextFieldAutoSize.RIGHT en fonction.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

369

Pour nir, nous dnissons le texte du champ et ajoutons ce dernier au sprite pass dans un autre paramtre. Le TextField est retourn par la fonction ; nous pouvons donc dnir une variable pour le rfrencer dont nous nous servirons pour le supprimer par la suite :
// Crer un champ texte public function createText(text:String, tf:TextFormat, s:Sprite, x,y: Number, width:Number): TextField { var tField:TextField = new TextField(); tField.x = x; tField.y = y; tField.width = width; tField.defaultTextFormat = tf; tField.selectable = false; tField.multiline = true; tField.wordWrap = true; if (tf.align == left) { tField.autoSize = TextFieldAutoSize.LEFT; } else { tField.autoSize = TextFieldAutoSize.CENTER; } tField.text = text; s.addChild(tField); return tField; }

Contrairement aux autres champs texte, le champ scoreField ne sera pas cr, supprim puis recr durant le jeu. Il sera simplement cr une fois et plac en bas de lcran. Ensuite, nous utiliserons showScore pour mettre jour le texte dans le champ :
// Met jour le score public function showScore() { scoreField.text = "Number of Questions: "+numQuestionsAsked+" "+numCorrect; } Number Correct:

De la mme manire que createText nous permet de crer diffrents types de champs texte avec une fonction, showGameButton nous permet de crer diffrents boutons. Elle prend buttonLabel en paramtre et sen sert pour dnir le texte de ltiquette lintrieur du bouton. La variable gameButton est dj une proprit de classe. Elle sera donc disponible par la suite pour removeChild. Nous ajouterons un couteur vnementiel ce bouton an quil appelle pressGameButton lorsque le joueur clique dessus. Cette action servira passer ltape suivante du jeu :
// Demander au joueur sil est prt pour la question suivante public function showGameButton(buttonLabel:String) { gameButton = new GameButton();

370

ActionScript 3.0 pour les jeux

gameButton.label.text = buttonLabel; gameButton.x = 220; gameButton.y = 300; gameSprite.addChild(gameButton); gameButton.addEventListener(MouseEvent.CLICK,pressedGameButton); }

Avec la programmation de haut en bas, il est ncessaire de tester chaque fragment de code mesure que vous lcrivez. Malheureusement, lexemple de code prcdent gnre une erreur parce que pressedGameButton nexiste pas encore. ce stade, il marrive gnralement de crer une fonction pressedGameButton factice qui ne contient pas de code. Cela me permet de tester dabord lemplacement du bouton, avant davoir besoin de programmer la procdure qui survient lorsque le joueur clique sur le bouton.

Passer ltape suivante


Lorsque le joueur clique sur un bouton, le jeu doit passer ltape suivante. La plupart du temps, cela implique de prsenter une nouvelle question, mais lorsquil ny a plus de question la partie se termine. Pour commencer, nous devons supprimer la question prcdente. Sil sagit de la premire question, questionSprite naura pas encore t cr. Nous devons donc vrier lexistence de questionSprite et ne le supprimer que sil se trouve bien l :
// Le joueur est prt public function pressedGameButton(event:MouseEvent) { // Supprimer la question if (questionSprite != null) { gameSprite.removeChild(questionSprite); }

Dautres choses doivent tre supprimes galement. Le message et le bouton qui restent suite la pause avant ou entre les questions sont supprims :
// Supprimer le bouton et le message gameSprite.removeChild(gameButton); gameSprite.removeChild(messageField);

prsent, nous devons dterminer si toutes les questions ont t poses. Si cest le cas, nous passons directement limage gameover. Lcran est dj vide car la question prcdente, le message et le bouton ont t supprims.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

371

Si les questions ne sont pas termines, nous appelons askQuestion pour afcher la question suivante :
// Poser la question suivante if (questionNum >= dataXML.child("*").length()) { gotoAndStop("gameover"); } else { askQuestion(); } }

Afcher les questions et les rponses


La fonction askQuestion rcupre la question suivante dans les donnes du quiz et lafche. Elle place tout ce quelle cre dans le sprite questionSprite an den faciliter la suppression par la suite. La Figure 10.3 prsente lcran aprs quune question a t afche.
Figure 10.3
La question et les quatre rponses sont afches dans le sprite questionSprite, qui couvre lessentiel du milieu de lcran.

// Congurer la question public function askQuestion() { // Prparer nouveau sprite de question questionSprite = new Sprite(); gameSprite.addChild(questionSprite);

La question elle-mme apparatra dans un champ isol vers le haut de lcran :


// Crer le champ texte pour la question var question:String = dataXML.i tem[questionNum].question; questionField = createText(question,questionFormat,questionSprite,0,60,550);

372

ActionScript 3.0 pour les jeux

Avant de placer les rponses, nous devons les mlanger. La premire parmi les donnes dorigine correspond la bonne rponse, aussi en stockons-nous une copie dans correctAnswer. Ensuite, nous appelons shufeAnswers pour obtenir un tableau de toutes les rponses dans un ordre alatoire :
// Crer le sprite pour les rponses, obtenir la bonne rponse et mlanger correctAnswer = dataXML.item[questionNum].answers.answer[0]; answers = shufeAnswers(dataXML.item[questionNum].answers);

Les rponses se trouvent dans un sous-sprite de questionSprite appel answerSprites. Un objet TextField et un objet Circle sont crs pour chaque rponse. Les objets Circle se voient tous attribuer des lettres diffrentes, de A D. Les deux sont placs au mme endroit, mais le clip Circle a t conu pour apparatre gauche de son point dalignement, tandis que le texte apparatra droite. Le texte et Circle seront tous deux livrs dans un nouveau sprite individuel, lequel sprite se verra attribuer un couteur CLICK an de pouvoir ragir comme un bouton :
// Placer chaque rponse dans un nouveau sprite avec une icne de cercle answerSprites = new Sprite(); for(var i:int=0;i<answers.length;i++) { var answer:String = answers[i]; var answerSprite:Sprite = new Sprite(); var letter:String = String.fromCharCode(65+i); // A-D var answerField:TextField = createText(answer,answerFormat,answerSprite,0,0,450);

var circle:Circle = new Circle(); // from Library circle.letter.text = letter; answerSprite.x = 100; answerSprite.y = 150+i*50; answerSprite.addChild(circle); answerSprite.addEventListener(MouseEvent.CLICK,clickAnswer); answerSprite.buttonMode = true; answerSprites.addChild(answerSprite); } questionSprite.addChild(answerSprites); }

Pour convertir un nombre en une lettre, nous utilisons Le caractre 65 produit A, le caractre 66 produit B, etc.

String.fromCharCode(65+i).

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

373

La fonction shufeAnswers rcupre en entre une XMLList correspondant au type de donnes retourn en demandant dataXML.item[questionNum].answers. Elle parcourt les donnes en boucle en supprimant chaque fois un lment au hasard de la liste et en le plaant dans un tableau. Elle retourne ensuite ce tableau de rponses tri de manire alatoire :
// Rcuprer toutes les rponses et les mlanger dans un tableau public function shufeAnswers(answers:XMLList) { var shufedAnswers:Array = new Array(); while (answers.child("*").length() > 0) { var r:int = Math.oor(Math.random()*answers.child("*").length()); shufedAnswers.push(answers.answer[r]); delete answers.answer[r]; } return shufedAnswers; }

Juger les rponses


Toutes les fonctions considres jusquici soccupaient de congurer le jeu. prsent, le joueur se voit enn prsenter la question (voir Figure 10.3). Lorsque le joueur clique sur lune des quatre rponses, nous appelons clickAnswer. Cette fonction soccupe en premier lieu de rcuprer le texte de la rponse slectionne. Lobjet TextField est le premier enfant de currentTarget. Nous rcuprons donc la valeur de sa proprit text et la plaons dans selectedAnswer. Cette valeur est ensuite compare avec celle de correctAnswer que nous avons stocke lorsque la question sest afche. Si le joueur a choisi la bonne rponse, nous crditons numCorrect dune unit. Un nouveau message texte est afch dans les deux cas :
// Le joueur slectionne une rponse public function clickAnswer(event:MouseEvent) { // Rcuprer le texte de la rponse slectionne et comparer var selectedAnswer = event.currentTarget.getChildAt(0).text; if (selectedAnswer == correctAnswer) { numCorrect++; messageField = createText("You got it!",questionFormat,gameSprite,0,140,550); } else { messageField = createText("Incorrect! The correct answer was:", questionFormat, gameSprite,0,140,550); } nishQuestion(); }

374

ActionScript 3.0 pour les jeux

Toutes les rponses sont ensuite examines. La fonction nishQuestion parcourt en boucle chaque sprite. La rponse correcte est dplace une position y qui la situe au milieu. Tous les couteurs vnementiels sont supprims galement. Les autres rponses sont rendues invisibles. La Figure 10.4 montre lcran ce stade.
Figure 10.4
La bonne rponse est dplace au milieu et accompagne dun message.

public function nishQuestion() { // Supprimer toutes les rponses sauf la bonne for(var i:int=0;i<4;i++) { answerSprites.getChildAt(i).removeEventListener(MouseEvent.CLICK,clickAnswer); if (answers[i] != correctAnswer) { answerSprites.getChildAt(i).visible = false; } else { answerSprites.getChildAt(i).y = 200; } } }

Le score doit aussi tre mis jour, ainsi que le pointeur questionNum. Pour nir, un nouveau bouton est cr avec ltiquette "Continue" (voir Figure 10.4 galement) :
// Question suivante questionNum++; numQuestionsAsked++; showScore(); showGameButton("Continue"); }

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

375

Le bouton cr par clickAnswer est un lien vers la question suivante. Lorsque le joueur clique dessus, nous appelons pressGameButton, qui lance la nouvelle question ou passe lcran gameover.

Fin de la partie
Limage gameover contient un bouton Play Again (rejouer) qui reconduit le joueur au dbut dune nouvelle partie. Avant cela, elle doit cependant appeler cleanUp pour supprimer tous les restes de la partie termine :
// Suppression des sprites public function cleanUp() { removeChild(gameSprite); gameSprite = null; questionSprite = null; answerSprites = null; dataXML = null; }

Le jeu peut maintenant tre redmarr. Ce jeu de quiz simple suft pour les sites Web ou les produits simples qui ne requirent quune solution trs rudimentaire. Pour un jeu de questions/rponses trs sophistiqu, nous devons ajouter bien dautres fonctionnalits.

Quiz version Deluxe


Codes sources http://ashgameu.com A3GPU10_TriviaGameDeluxe.zip Pour amliorer notre version du jeu actuelle, nous allons ajouter un certain nombre de fonctionnalits qui la rendront plus excitante, plus stimulante et plus amusante. Pour commencer, le joueur doit avoir un temps limit pour rpondre aux questions. La plupart des jeux de quiz sur ordinateur ou la tlvision imposent cette contrainte. Ensuite, nous ajouterons un bouton dindice an que le joueur puisse obtenir sil le souhaite une petite aide supplmentaire. Il existe deux types dindices et nous les ajouterons tous les deux. Ensuite, nous rendrons le jeu plus informatif en plaant des informations supplmentaires aprs chaque question, ce qui contribuera rendre le jeu plus ludique. Les informations viendront complter ce que le joueur vient dapprendre en rpondant la question.

376

ActionScript 3.0 pour les jeux

Pour nir, nous allons relooker le systme de score. Celui-ci doit tenir compte du temps pris pour rpondre la question et du fait que le joueur a rclam ou non un indice. Enn, en guise de bonus supplmentaire, nous amnerons le quiz lire un grand nombre de questions mais en slectionner dix au hasard utiliser. Le questionnaire sera ainsi diffrent chaque nouvelle partie.

Dnir un temps limite


Pour ajouter une contrainte de temps au jeu, nous avons besoin dune reprsentation visuelle du temps que le joueur a pour rpondre une question. Nous pouvons procder en utilisant un objet clip spar. Cet objet Clock peut correspondre nimporte quel type doutil reprsentant le temps : une horloge, du texte ou quoi que ce soit dautre. Pour cet exemple, jai congur un clip de vingt-six images. Toutes les images contiennent vingt-cinq cercles. partir de limage 2, lun des cercles est rempli avec une forme unie. Dans la premire image, les vingt-cinq cercles sont donc vides. la vingt-sixime, ils sont tous remplis. La Figure 10.5 prsente ce clip Clock.
Figure 10.5
La quinzime image du clip Clock contient quatorze cercles remplis.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

377

Nous utiliserons un Timer pour compter les secondes. Ajoutons donc une instruction import cet effet :
import ash.utils.Timer;

Ensuite, nous ajoutons un Clock aux sprites utiliss :


private var clock:Clock;

Et un Timer :
private var questionTimer:Timer;

Dans la fonction askQuestion, nous devons ajouter le Clock et lancer le Timer :


// Congurer une nouvelle horloge clock = new Clock(); clock.x = 27; clock.y = 137.5; questionSprite.addChild(clock); questionTimer = new Timer(1000,25); questionTimer.addEventListener(TimerEvent.TIMER,updateClock); questionTimer.start();

Lobjet Clock sera positionn juste en dessous de la question lcran. En fait, nous devons tendre un peu la hauteur du jeu et dplacer les lments vers le bas pour faire place notre objet Clock et certains autres lments que nous allons ajouter sous peu. La Figure 10.6 prsente cette nouvelle disposition.
Figure 10.6
Lobjet Clock a t ajout et il reste de la place pour dautres lments.

378

ActionScript 3.0 pour les jeux

Lutilisation de vingt-cinq points pour lhorloge est compltement arbitraire. Vous pourriez crer nimporte quelle squence en vingt-six images sous forme de clip et lutiliser (un chronomtre ou une barre de progression, par exemple). Il nest mme pas ncessaire dutiliser vingt-cinq lments spars. Vous pourriez aisment remplacer le tout par cinq modications et tendre les images le long du scnario.

La fonction updateClock est appele chaque seconde. Le clip Clock avance dune image de plus. Lorsque le temps est coul, un message est afch et une question nale (nishQuestion) est appele exactement comme lorsque le joueur clique sur une rponse :
// Mettre jour lhorloge public function updateClock(event:TimerEvent) { clock.gotoAndStop(event.target.currentCount+1); if (event.target.currentCount == event.target.repeatCount) { messageField = createText("Out of time! The correct answer was:", questionFormat,gameSprite,0,190,550); nishQuestion(); } }

prsent, le joueur a deux moyens dobtenir une mauvaise rponse : en choisissant une proposition incorrecte ou en dpassant le dlai autoris.

Ajouter des indices


Vous aurez peut-tre remarqu que les chiers XML dexemple incluent la fois un indice (hint) et une info supplmentaire (extra fact) pour toutes les questions. Nous allons enn nous en servir. Pour ajouter des indices simples au jeu, nous inclurons un simple bouton "Hint" (indice) ct de chaque question. Lorsque le joueur cliquera dessus, nous le remplacerons par le texte de lindice. Il nous faut quelques nouveaux lments pour implmenter ce mcanisme. Tout dabord, nous allons ajouter un hintFormat aux dnitions de la classe, avec les dnitions de variable texte :
private var hintFormat:TextFormat;

Ensuite, nous dnirons ce format dans la fonction de construction :


hintFormat = new TextFormat("Arial",14,0x330000,true,false,false,null,null,"center");

Nous ajouterons galement un hintButton la liste des variables de la classe, avec les dnitions de sprites et dobjets :
private var hintButton:GameButton;

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

379

Dans la fonction askQuestion, nous crerons le nouveau bouton Hint et le positionnerons en dessous de la dernire rponse, comme le montre la Figure 10.7 :
// Placer le bouton dindice hintButton = new GameButton(); hintButton.label.text = "Hint"; hintButton.x = 220; hintButton.y = 390; gameSprite.addChild(hintButton); hintButton.addEventListener(MouseEvent.CLICK,pressedHintButton);

Figure 10.7
Le bouton Hint apparat vers le bas.

Lorsque le joueur clique sur le bouton, celui-ci disparat. Il est remplac par un nouveau champ texte auquel est attribu le format de texte hintFormat :
// Le joueur veut un indice public function pressedHintButton(event:MouseEvent) { // Supprimer le bouton gameSprite.removeChild(hintButton); hintButton = null; // Afcher lindice var hint:String = dataXML.item[questionNum].hint; var hintField:TextField = createText(hint,hintFormat,questionSprite,0,390,550); }

380

ActionScript 3.0 pour les jeux

Nous souhaitons aussi utiliser linstruction removeChild lintrieur de la fonction nishQuestion, en vriant dabord que le hintButton existe, au cas o il aurait t supprim lorsque le joueur a cliqu dessus :
//Supprimer bouton dindice if (hintButton != null) { gameSprite.removeChild(hintButton); }

Cette vrication empche que lutilisateur clique sur le bouton aprs que la rponse la question eut dj t donne. Voil tout ce quil nous faut pour afcher lindice. Comme hintField fait partie de questionSprite, il est nettoy lorsque nous supprimons ce sprite la n de la partie. La Figure 10.8 montre lindice qui apparat aprs que le joueur a cliqu sur le bouton.
Figure 10.8
Lindice apparat la place du bouton

Quest-ce quun bon indice ? Il peut parfois tre plus difcile de rdiger un bon indice que la question et les rponses. Il ne faut pas donner la rponse directement et, pourtant, il faut aider le joueur malgr tout. Souvent, le meilleur moyen consiste donner un indice qui suggre la rponse mais dans un autre contexte. Par exemple, si la question concerne des noms de prsidents et que la rponse est Charles de Gaulle, lindice pourrait tre "Il a donn son nom un aroport".

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

381

Ajouter des informations supplmentaires


Il est assez facile dajouter des informations supplmentaires la n dune question. Cette fonctionnalit est sembable celle des indices, ceci prs que les informations safchent automatiquement lorsque le joueur a rpondu la question. Aucune nouvelle variable nest requise pour cela. Il nous suft de crer un champ texte et de le remplir lorsque la question est termine. Le code suivant est ajout nishQuestion :
// Afcher les informations supplmentaires var fact:String = dataXML.item[questionNum].fact; var factField:TextField = createText(fact,hintFormat,questionSprite,0,340,550);

Comme le nouveau TextField fait partie de questionSprite, il est supprim en mme temps. Nous utilisons galement le format hintFormat au lieu de crer un format spar pour ces informations. La Figure 10.9 prsente le rsultat.
Figure 10.9
Les informations supplmentaires safchent lorsque lutilisateur a rpondu la question.

Au moment de dcider o placer les informations supplmentaires, je me suis assur que lindice et les informations pouvaient cohabiter lcran. Si le joueur choisit dafcher lindice, il reste lcran aprs que le joueur a rpondu la question et apparat juste en dessous des informations supplmentaires.

382

ActionScript 3.0 pour les jeux

Ajouter un systme de score complexe


Le problme avec la fonctionnalit des indices ainsi quavec lhorloge tient ce que le joueur est trs peu pnalis par le fait de proter de lindice ou de laisser scouler un long dlai avant de rpondre. Ce qui rend le jeu plus excitant, cest davoir une pnalit en cas dusage de lindice. En outre, nous pouvons comptabiliser le nombre de points marqus en fonction de la rapidit avec laquelle le joueur rpond la question. Pour oprer ces modications, introduisons deux nouvelles variables. Elles peuvent tre places nimporte o dans les dnitions de variables, mme sil est prfrable de les placer avec les dnitions de variables de ltat du jeu existantes. Elles tiendront le registre du nombre de points que vaut la question actuelle et du nombre de points total que le joueur a marqus jusque-l dans la partie :
private var questionPoints:int; private var gameScore:int;

Dans la fonction startTriviaGame, nous initialiserons gameScore 0, juste avant dappeler showScore :
gameScore = 0;

La fonction showScore sera remplace par une nouvelle version. Celle-ci afchera le nombre de points que vaut la question et le score actuel du joueur :
public function showScore() { if (questionPoints != 0) { scoreField.text = Potential Points: +questionPoints+\t } else { scoreField.text = Potential Points: ---\t } } Score: +gameScore; Score: +gameScore;

Les caractres \t dans la valeur de scoreField.text reprsentent un caractre de tabulation. En plaant une tabulation entre les deux parties du champ, nous donnons la possibilit au texte de rester dans le mme espace gnral, mme lorsque la longueur des nombres change. Ce nest pas une solution parfaite, mais elle est bien plus simple que celle qui consiste crer deux champs spars dans ce cas. Vous pourriez utiliser deux champs spars si vous souhaitez mieux contrler le placement de ces nombres.

La Figure 10.10 montre comment le nouveau score est afch en bas de lcran. Maintenant que la fonction showScore doit mettre jour les points potentiels et le score total, nous devons lappeler plus souvent. chaque fois que le questionScore change, nous devons appeler showScore pour faire connatre au joueur la nouvelle valeur. Si questionScore vaut 0, nous afchons --- au lieu de 0. Nous indiquerons ainsi plus clairement que les points potentiels ne signient rien entre les questions.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

383

Figure 10.10
Le nombre de questions pos et le nombre de bonnes rponses ont t remplacs par le nombre de points potentiel pour la question et le score actuel du joueur.

Dans askQuestion, nous xerons le score potentiel de la question 1 000 :


// Commencer la question avec les points au maximum questionPoints = 1000; showScore(); )

chaque seconde qui passe, nous diminuons ensuite le score. Cette procdure intervient dans la fonction updateClock. chaque fois quun nouveau cercle est rempli, nous supprimons 25 points pour le score potentiel :
// Rduction des points questionPoints -= 25; showScore();

Les points potentiels diminuent aussi lorsque le joueur demande afcher lindice. Cette opration lui cote 300 points :
// Pnalit questionPoints -= 300; showScore();

Bien videmment, le seul moyen dobtenir des points consiste donner la bonne rponse. Linstruction suivante est donc ajoute lemplacement adquat dans clickAnswer :
gameScore += questionPoints;

384

ActionScript 3.0 pour les jeux

Inutile ici dappeler showScore car la fonction sera appele immdiatement aprs dans la fonction nishQuestion. Cest dailleurs cet endroit que nous allons positionner questionPoints 0 galement :
questionPoints = 0; showScore();

Vous pouvez aussi choisir de conserver le champ texte doirigine du score en bas et afcher les points potentiels et le score dans un champ spar. Les joueurs pourront alors voir toutes les statistiques concernant leur rsultat. Les animations TriviaGameDeluxe.a et TriviaGameDeluxe.as conservent numCorrect et numQuestionsAsked cet effet, bien quelles ne les utilisent pas.

Rendre les questions alatoires


Vous pourrez souhaiter ou non que votre jeu de quiz prsente les mmes questions chaque nouvelle partie. Tout dpend de votre manire dutiliser ce jeu. Si vous souhaitez prsenter des questions diffrentes chaque fois et que votre jeu est mis disposition sur un site Web, lidal est davoir une application serveur qui cre un document XML alatoire de questions et rponses partir dune grande base de donnes. Si vos besoins sont plus simples mais que vous souhaitiez nanmoins quun certain nombre de questions alatoires soient choisies parmi un nombre total plutt restreint de questions, il existe un moyen de procder en ActionScript. Une fois le document XML lu, ces donnes brutes peuvent tre traites pour aboutir un document XML plus petit ne contenant quun nombre dni de questions alatoires. Le nouveau dbut de la fonction xmlLoaded ressemble alors ceci :
public function xmlLoaded(event:Event) { var tempXML:XML = XML(event.target.data); dataXML = selectQuestions(tempXML,10);

La fonction selectQuestions prend en paramtres le jeu de donnes complet et un nombre de questions retourner. Elle slectionne des nuds item alatoires du document XML dorigine et cre un nouvel objet XML :
// Slectionner un nombre donn de questions alatoires public function selectQuestions(allXML:XML, numToChoose:int):XML {

// Crer un nouvel objet XML pour contenir les questions var chosenXML:XML = <trivia></trivia>;

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

385

// Boucler jusqu ce que nous ayons assez de questions while(chosenXML.child("*").length() < numToChoose) {

// Slectionner une question au hasard et la dplacer var r:int = Math.oor(Math.random()*allXML.child("*").length()); chosenXML.appendChild(allXML.item[r].copy());

// Ne pas utiliser nouveau delete allXML.item[r]; }

// Retour return chosenXML; }

Cette slection alatoire et ce mlange des questions sont trs pratiques pour crer une solution rapide. Si vous avez par exemple plus de cent questions, il est en revanche important de ne pas demander lanimation de lire un document XML aussi grand en entier chaque fois. Je recommande la solution ct serveur. Si vous navez pas lhabitude de programmer des solutions ct serveur, associez-vous avec quelquun daguerri dans cet exercice.

Quiz dimages
Codes sources http://ashgameu.com A3GPU10_PictureTriviaGame.zip Tous les jeux de questions et de rponses ne fonctionnent pas ncessairement avec du texte. Il arrive quune image soit mieux mme de reprsenter une ide. Par exemple, si vous souhaitez tester les connaissances dune personne en gomtrie, les questions et rponses sous forme de texte ne sont pas toujours les mieux adaptes pour oprer des valuations. Il nest en fait pas si difcile de convertir notre moteur de jeu de quiz en une nouvelle version qui utilise des images. Il suft de rorganiser lgrement lcran puis de permettre le chargement de chiers dimage externes. Lessentiel du jeu peut tre conserv en ltat.

386

ActionScript 3.0 pour les jeux

Amliorer la disposition des rponses


Avant de pouvoir charger des images, nous devons amliorer la disposition des rponses lcran. La Figure 10.11 prsente les rponses selon un quadrillage de 2 2 au lieu de quatre lignes. Nous disposons ainsi dun meilleur cadre pour des images denviron 250 pixels de large et 100 de haut au maximum. Il sera prfrable de sen tenir 200 80 an que les images charges ne viennent pas gner les autres boutons.
Figure 10.11
Les rponses sont maintenant empiles dans deux colonnes et deux lignes.

Cette disposition peut tre obtenue en noprant quun changement au milieu de la fonction askQuestion. Les variables xpos et ypos tiennent le registre de la position courante et commencent 0 et 0. Ensuite, 1 est ajout xpos an de passer vers la droite. Ensuite, xpos est ramene 0 et ypos, augmente. Cette procdure place les quatre rponses aux positions (0,0), (1,0), (0,1) et (1,1), ce qui correspond aux emplacements (100,150), (350,150), (100,250) et (350,250) lcran.

Nous allons apporter dautres modications cette section de code sous peu. Le code qui suit ne correspondra donc pas au chier PictureTriviaGame.as si vous avancez paralllement au livre.

// Placer chaque rponse dans un nouveau sprite avec une icne de cercle answerSprites = new Sprite(); var xpos:int = 0; var ypos:int = 0; for(var i:int=0;i<answers.length;i++) {

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

387

var answer:String = answers[i]; var answerSprite:Sprite = new Sprite(); var letter:String = String.fromCharCode(65+i); // A-D var answerField:TextField = createText(answer,answerFormat,answerSprite,0,0,200); var circle:Circle = new Circle(); // De la bibliothque circle.letter.text = letter; answerSprite.x = 100+xpos*250; answerSprite.y = 150+ypos*100; xpos++ if (xpos > 1) { xpos = 0; ypos += 1; } answerSprite.addChild(circle); answerSprite.addEventListener(MouseEvent.CLICK,clickAnswer); // En faire un bouton answerSprites.addChild(answerSprite); }

Cette modication est dj utile parce quelle prsente les rponses dune manire plus intressante quen les empilant les unes au-dessus des autres.

Reconnatre deux types de rponses


Le but ici est non pas de crer un quiz qui ne propose que des images comme rponse, mais de vous permettre de combiner du texte et des images. Nous devons donc pouvoir spcier dans le chier XML le type de la rponse. Cela peut tre fait en ajoutant un attribut la rponse dans le code XML :
<item> <question type="text">Which one is an equilateral triangle?</question> <answers> <answer type="le">equilateral.swf</answer> <answer type="le">right.swf</answer> <answer type="le">isosceles.swf</answer> <answer type="le">scalene.swf</answer> </answers> </item>

Pour dterminer si une rponse doit tre afche sous forme de texte ou de chier externe charg, nous examinons simplement la proprit type. Nous allons maintenant modier notre code pour cela.

388

ActionScript 3.0 pour les jeux

Crer des objets Loader


Dans shufeAnswers, nous crons un tableau de rponses tri alatoirement partir des rponses dans lobjet XML. Le texte de ces rponses est stock dans un tableau. Nous devons cependant maintenant stocker la fois le texte et le type de ces rponses. La ligne o nous ajoutons une nouvelle rponse au tableau prend ainsi la forme suivante :
shufedAnswers.push({type: answers.answer[r].@type, value: answers.answer[r]});

prsent, lorsque nous crons chaque rponse, nous devons dterminer si la rponse correspond du texte ou une image. Sil sagit dune image, nous crons un objet Loader. Celui-ci agit comme un clip rcupr de la bibliothque, sauf que lon utilise un URLRequest et la commande load pour rcuprer le contenu du clip partir dun chier externe :
var answerSprite:Sprite = new Sprite(); if (answers[i].type == "text") { var answerField:TextField = createText(answers[i].value,answerFormat,answerSprite, 0,0,200); } else { var answerLoader:Loader = new Loader(); var answerRequest:URLRequest = new URLRequest("triviaimages/"+answers[i].value); answerLoader.load(answerRequest); answerSprite.addChild(answerLoader); }

Le code prsuppose que toutes les images se trouvent lintrieur dun dossier nomm triviaimages. Les objets Loader peuvent agir de manire autonome. Une fois que vous les activez avec la commande load, ils obtiennent le chier depuis le serveur et apparaissent leur position dsigne lorsquils sont prts. Vous navez pas besoin de les surveiller ni de faire quoi que ce soit lorsque le chargement est termin.

Si vous combinez cet exemple avec la fonction Clock de lanimation prcdente, vous aurez un peu de travail supplmentaire. Ne serait-il pas injuste que le chronomtre se mette en marche alors que certaines des rponses ne sont pas encore apparues ? Il convient donc dcouter Event.COMPLETE pour chaque Loader et de ne lancer le chronomtre quune fois que toutes les rponses ont t afches.

La Figure 10.12 prsente le quiz avec quatre animations externes charges dans les rponses.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

389

Figure 10.12
Des animations externes ont remplac le texte dans chaque rponse.

Dterminer la bonne rponse


Nous nous sommes auparavant appuys sur la proprit text du champ de la rponse pour dterminer si le joueur avait choisi la bonne rponse. Nous ne pouvons plus le faire prsent car le clip de lobjet Loader ne possde pas de proprit text comme les objets TextField. Au lieu de cela, nous allons donc tirer parti du fait que le second objet dans answerSprite correspond lobjet Circle cr de manire dynamique. Nous pouvons lui attacher une proprit answer et y stocker la rponse :
circle.answer = answers[i].value;

Ensuite, dans la fonction clickAnswer, nous examinerons cette nouvelle proprit answer an de dterminer si le joueur a cliqu sur le bon sprite :
var selectedAnswer = event.currentTarget.getChildAt(1).answer;

Vous remarquerez que lobjet Circle est lenfant numro 1 dans answerSprite. Auparavant, nous examinions lenfant numro 0, qui tait lobjet TextField. Une autre modication est requise an de dnir correctement la position de la bonne rponse lorsque le joueur a opr son choix. Auparavant, les rponses se trouvaient toutes dans une unique colonne, avec la mme valeur x. Lorsque nous souhaitions centrer la bonne rponse, nous navions donc qu dnir la valeur y du bon answerSprite. Maintenant que la rponse peut se trouver gauche ou droite, nous devons aussi positionner la valeur x. Voici le nouveau code pour la fonction nishQuestion :
answerSprites.getChildAt(i).x = 100; answerSprites.getChildAt(i).y = 200;

390

ActionScript 3.0 pour les jeux

tendre la zone ractive


Un dernier point avant que nous nen ayons ni avec les rponses. Si la rponse est une rponse texte, les joueurs peuvent cliquer sur le cercle ou le champ texte pour enregistrer leur rponse. Avec les animations charges, il peut ne pas y avoir grand-chose cliquer. la Figure 10.11, les rponses ne sont rien dautre que des lignes nes qui composent un triangle. Pour cliquer sur la rponse, le joueur doit alors cliquer sur le cercle ou sur une partie du graphisme. Il faudrait pourtant quil puisse cliquer sur nimporte quelle partie normale de la rponse. Lun des moyens rapides de rsoudre ce problme consiste placer un rectangle plein lintrieur de chaque sprite de rponse. Il suft pour cela de tracer un rectangle plein en xant 0 le canal alpha an de le rendre invisible :
// set a larger click area answerSprite.graphics.beginFill(0xFFFFFF,0); answerSprite.graphics.drawRect(-50, 0, 200, 80);

La Figure 10.13 prsente les sprites de rponse avec un graphisme sous-jacent. Au lieu de rendre la valeur nulle, jai x la valeur alpha 0,5 an que le rectangle se remarque.
Figure 10.13
Un rectangle a t dessin derrire chaque rponse.

Le joueur peut maintenant cliquer dans la zone complte de chaque rponse.

Chapitre 10

Questions et rponses : quiz et jeux de culture gnrale

391

Images pour les questions


En plus dutiliser des images dans les rponses, vous pourriez souhaiter utiliser des images pour la question elle-mme. Nous procderons de la mme manire, en utilisant un attribut type du code XML :
<item> <question type="le">italy.swf</question> <answers> <answer type="text">Italy</answer> <answer type="text">France</answer> <answer type="text">Greece</answer> <answer type="text">Fenwick</answer> </answers> </item>

Cet ajout notre code ActionScript est plus simple car la question nest pas cette fois un lment actif. Nous avons simplement besoin dutiliser un objet Loader au lieu dun objet TextField. Voici le changement apport askQuestion :
// Crer un champ texte pour la question var question:String = dataXML.item[questionNum].question; if (dataXML.item[questionNum].question.@type == "text") { questionField = createText(question,questionFormat,questionSprite,0,60,550); } else { var questionLoader:Loader = new Loader(); var questionRequest:URLRequest = new URLRequest(triviaimages/+question); questionLoader.load(questionRequest); questionLoader.y = 50; questionSprite.addChild(questionLoader); }

La Figure 10.14 prsente une question qui utilise une image externe comme question et quatre rponses texte. Vous pourriez videmment utiliser des images externes aussi bien pour la question que pour les quatre rponses. La Figure 10.14 montre comment le fait dutiliser des chiers externes pour les questions et les rponses nimplique pas ncessairement quil sagisse de dessins ou dimages. Il peut aussi y avoir du texte. Ce mlange peut se rvler pratique pour un texte de mathmatiques qui doit utiliser des notations complexes comme des fractions, des puissances ou divers symboles.

392

ActionScript 3.0 pour les jeux

Figure 10.14
La question est une animation Flash externe, mais les quatre rponses sont du texte.

Modier le jeu
La qualit des jeux de quiz dpend de celle des questions et des rponses quils contiennent, quelle que soit par ailleurs la qualit du programme et de linterface. Si vous prvoyez de crer un jeu des ns de divertissement, il vous faut des questions et des rponses sufsamment attrayantes pour susciter lintrt des joueurs. Si vous crez un jeu des ns ducatives, vous devez vous assurer que les questions et les rponses soient claires et correctement formules. Il est assez ais de modier ce jeu de manire inclure un plus grand nombre ou un plus petit nombre de rponses. Si vous le souhaitez, vous pouvez ne proposer que deux rponses, comme Vrai et Faux. Les questionnaires choix multiples proposent cependant rarement plus de quatre rponses, bien que lon voie parfois des propositions du type "Toutes" ou "Aucune" pour valider ou invalider toutes les rponses prcdentes. Aucune programmation particulire nest requise pour crer une solution de ce type, sauf ventuellement pour sassurer que ces rponses globales soient bien proposes en cinquime ou sixime choix dans la liste. Au-del des questions et des rponses et de la manire dont elles sont afches, lune des modications possibles pourrait tre de proposer une mtaphore du jeu. Il sagirait dune reprsentation visuelle du score du joueur qui pourrait aussi modier la manire de jouer le jeu. Par exemple, le joueur pourrait avoir un personnage qui grime une corde. chaque bonne rponse, le personnage grimperait dun cran. chaque mauvaise rponse, il retomberait en bas. Le but serait de parvenir en haut en rpondant correctement un certain nombre de questions de suite. Les mtaphores de jeu peuvent tre utilises pour mieux harmoniser le jeu avec le site Web ou le produit dont il fait partie. Par exemple, un site de prservation de la nature pourrait proposer un jeu de questions/rponses qui utilise des animaux.

11
Jeux daction : jeux de plate-forme
Au sommaire de ce chapitre :

Concevoir le jeu Crer la classe Modier le jeu

394

ActionScript 3.0 pour les jeux

Codes sources http://ashgameu.com A3GPU11_PlatformGame.zip Les jeux dlement latral ou jeux de plate-forme sont apparus pour la premire fois au dbut des annes 1980 et sont rapidement devenus un standard des jeux vido jusqu ce que la 3D ne simpose dans le courant des annes 1990. Les jeux de plate-forme dlement permettent au joueur de contrler un personnage qui apparat de prol. Il peut se dplacer vers la gauche et vers la droite ainsi que sauter le plus souvent. Lorsquil avance vers un ct de lcran, larrire-plan dle an de rvler dautres portions du jeu.

Les jeux de plate-forme incluent presque toujours un personnage capable de sauter. Le plus clbre dentre eux est videmment Mario, de Nintendo. Il apparat dans des dizaines de jeux, de Donkey Kong jusqu de nombreux jeux daventure des consoles Nintendo.

Dans ce chapitre, nous allons crer un jeu de plate-forme avec un personnage principal qui se dplace vers la gauche et vers la droite et peut sauter. Nous inclurons des murs et des plates-formes. Il y aura aussi des ennemis et des objets ramasser.

Conception du jeu
Avant de commencer programmer notre code, commenons pas considrer tous les aspects du jeu. Il nous faut un hros, des ennemis, des objets et un moyen de crer des niveaux.

Conception des niveaux


Lun des aspects importants des jeux de plate-forme concerne la conception des niveaux. Tout comme le jeu de quiz du prcdent chapitre ne peut exister sans contenu, le jeu de plate-forme requiert aussi un contenu. Il sagit en loccurrence dune srie de niveaux. Quelquun (le programmeur, un graphiste ou un concepteur de niveau) doit crer les niveaux. La Figure 11.1 prsente un niveau qui sera en fait le premier de notre jeu. Les jeux de plate-forme plus sophistiqus peuvent aussi intgrer un diteur de niveau qui permet au concepteur de niveau de crer de nombreux niveaux et de les tester pendant que les programmeurs et les graphistes travaillent sur le reste du jeu. Pour notre exemple simple, nous concevrons cependant les niveaux directement dans Flash, en utilisant un clip contenant les diffrentes pices du jeu.

Chapitre 11

Jeux daction : jeux de plate-forme

395

Figure 11.1
Le niveau 1 de notre jeu de plate-forme inclut trois ennemis, plusieurs trsors, une cl et une porte.

Lanimation PlatformGame.a contient diffrentes pices de jeu dans sa bibliothque. En voici la liste :

Sol. Un bloc de 40 40 simple sur lequel le hros peut tenir debout. Il bloquera le hros ct gauche et ct droit. Mur. Identique au sol quant lusage, mais visuellement diffrent. Hros. Le personnage du joueur. Inclut des animations pour la position debout, la marche, le saut et la mort. Ennemi. Un personnage plus simple avec une animation de marche. Trsor. Un bijou simple, avec des reets anims. Cl. Un graphisme de cl simple. Porte. Une porte, avec une animation pour louverture.

Pour crer un niveau partir de ces objets, il suft de les positionner lintrieur dun clip. La Figure 11.1 en donne un exemple. Il sagit en fait du clip gamelevel1 dans la bibliothque de lanimation PlatformGame.a.

Pices des murs et du sol


Pour crer facilement ce niveau, jai mis en place une grille en choisissant Afchage > Grille > Modier la grille et en dnissant un quadrillage de 40 40. Ensuite, jai fait glisser les pices du sol et des murs de la bibliothque an de les placer le long de cette grille. La Figure 11.2 prsente le niveau en masquant larrire-plan an de rvler les repres de la grille. $ Les pices des murs et du sol diffrent visuellement dans ce jeu, mais seront considrs comme le mme type dobjet dans le code. Vous pouvez ajouter dautres "blocs constructeurs" de ce type pour mieux diversier le jeu.

Parmi les ides qui ne sont pas utilises dans ce jeu, lune consiste utiliser de nombreuses variantes pour les blocs des murs et du sol, en les stockant toutes dans diffrentes images du clip. Au dbut du jeu, une image alatoire peut ainsi tre choisie pour chaque bloc.

396

ActionScript 3.0 pour les jeux

Figure 11.2
Le niveau peut tre congur plus facilement en plaant les pices des murs et du sol le long de la grille.

Les murs et le sol nont pas besoin de se voir attribuer un nom particulier. Les lments de la bibliothque sont nanmoins congurs de manire tre exports pour ActionScript, comme le montre la Figure 11.3. Ce rglage est en revanche vital parce que notre code recherchera des objets Floor et Wall.
Figure 11.3
Le clip Floor est congur pour tre aussi lobjet de classe Floor.

Le hros et les ennemis


Le hros apparat dans le coin suprieur gauche des Figures 11.1 et 11.2. Il a t soigneusement plac de manire se tenir pile sur un bloc de sol (Floor). Le clip du hros contient plusieurs sections animes diffrentes. Examinez la Figure 11.4.

Chapitre 11

Jeux daction : jeux de plate-forme

397

Figure 11.4
Le hros possde des images pour la position debout, la marche, le saut et la mort.

Vous remarquerez que le point dalignement du clip se trouve exactement au bas des pieds du personnage. Nous le ferons correspondre au haut de llment Floor, sur lequel repose le personnage. Horizontalement, le personnage sera centr. Au moment de placer le hros, il faudra que sa position y corresponde la position y de llment
Floor situ directement sous lui. Le hros commencera donc en position debout. Si vous le placez en

hauteur au-dessus du bloc Floor, il commencera par tomber sur le sol. Cest une autre approche possible, dailleurs : le personnage pourrait ainsi paratre tomber au milieu de ce dcor. Lennemi correspond un clip similaire, avec une simple squence de marche et une position debout (voir Figure 11.5). Vous remarquerez que le point dalignement de lennemi se trouve galement au bas de son pied. Ces petits bonhommes sont conus pour que lon saute sur eux. Cest ainsi que le hros pourra sen dbarrasser. Ils sont donc courts sur pattes et comme accroupis. Nous naurons pas besoin dune squence de mort, car nous les supprimerons de lcran ds linstant o ils seront dtruits et utiliserons lexplosion de points (la classe PointBurst) du Chapitre 8 pour afcher un message cet endroit. Les ennemis doivent aussi tre placs directement sur un bloc Floor. Sinon ils tomberont sur le bloc Floor suivant : l encore, ce peut tre un effet souhait si vous le prfrez. Les ennemis requirent aussi des noms doccurrence. Les trois ennemis prsents dans les Figures 11.1 et 11.2 sont appels enemy1, enemy2 et enemy3.

398

ActionScript 3.0 pour les jeux

Figure 11.5
Lennemi na que deux squences pour la position debout et la marche.

Autre point concernant les ennemis : ils seront programms pour marcher vers lavant et larrire, en se tournant ds quils rentrent dans un mur. Vous devez donc les placer dans une zone o gurent des murs des deux cts. Sils parviennent une extrmit borde par le vide, ils tomberont la premire occasion. Ils continueront de tomber ainsi chaque fois quils en auront la possibilit jusqu se stabiliser en avant et en arrire dans une zone borde de murs des deux cts.

Joyaux et objets
Diffrents objets apparaissent aux Figures 11.1 et 11.2. Les objets en forme de diamants sont des joyaux qui peuvent tre ramasss pour gagner des points. Il ny a rien de particulirement remarquable concernant le clip Treasure, si ce nest quil contient plusieurs images pour animer un effet dclat lumineux. Cette animation naffecte en rien le jeu ; elle na quun intrt visuel.

Si vous souhaitez plusieurs types de joyaux, le moyen le plus simple consiste en placer un par image dans ce clip. Vous pouvez sinon crer une varit dobjets diffrents, comme des diamants, des pices, des bagues, etc. Vous devrez alors les rechercher chacun dans le code.

Les clips Key et Door sont similaires. Le clip Key contient des images pour lanimation uniquement. Le clip Door contient une squence douverture qui dmarre limage 2 (voir Figure 11.6).

Chapitre 11

Jeux daction : jeux de plate-forme

399

Figure 11.6
Le clip Door contient une image 1 statique et une courte squence anime de son ouverture.

Les lments nont pas besoin dtre parfaitement placs dans la grille. Ils doivent simplement tre porte du hros lorsquil marche ou dans dautres cas, lorsquil saute. Visuellement, il est cependant souvent plus naturel quils reposent sur le sol.

Faites attention la superposition par calques de vos lments de jeu. Elle sera conserve pendant le droulement du jeu. Ds lors, si le hros se trouve derrire un mur ou un autre objet, ce mur apparatra devant le graphisme du hros lorsque ce dernier sen rapproche. Vous pouvez cependant volontairement faire apparatre des objets devant le joueur, comme une vitre semi-transparente ou un petit meuble.

Les clips Treasure, Key et Door sont tous congurs de manire tre exports pour ActionScript avec des noms de classe correspondant leurs noms de bibliothque. Notre code les recherchera daprs la classe. Les occurrences des clips elles-mmes ne doivent pas ncessairement avoir de noms. Le coffre (Chest) fait partie des autres lments du jeu. Ce clip deux images prsente un coffre de trsor ferm, puis ouvert. Cest lobjet de la qute du joueur. Le jeu se termine lorsque le joueur le trouve.

400

ActionScript 3.0 pour les jeux

Graphismes darrire-plan
Les niveaux du jeu incluent galement un clip avec des graphismes darrire-plan. Dans le cas prsent, il sagit dun rectangle en dgrad. Il pourrait y avoir plus ; vrai dire, tout ce que vous ajouterez larrire-plan sera visible, sans tre actif. Vous pouvez donc colorier la scne comme vous le souhaitez. De grands tableaux peuvent tre accrochs au mur ou des torches animes, des messages et des signes. Aux Figures 11.1 et 11.2, des torches sont accroches tout en haut. Elles se trouvent simplement places sur le mme calque darrire-plan que le dgrad. Le code de notre jeu na mme pas besoin de les prendre en compte car elles ne feront que dler avec larrire-plan.

La bote de dialogue
Cette animation inclura une bote de dialogue (voir Figure 11.7) que nous pourrons afcher tout moment pour prsenter des informations et attendre la rponse de lutilisateur.
Figure 11.7
Le clip Dialog sera utilis pour attendre que le joueur clique sur un bouton avant de continuer.

La bote de dialogue sera afche lorsque le joueur meurt, lorsque la partie est termine, lorsquun niveau est termin ou lorsque le joueur gagne. Lorsque lun de ces vnements se produit, le jeu sinterrompt et une bote de dialogue safche. Nous inclurons la bote de dialogue sous forme de clip spar avec un champ texte dynamique et un bouton.

Chapitre 11

Jeux daction : jeux de plate-forme

401

Le scnario principal
Le scnario principal inclut une image start avec des instructions. Aprs cela, chaque image contient un clip de niveau de jeu. Ce systme permet facilement de passer dun niveau un autre, aussi en cours de partie que lorsque vous crez les niveaux. La seconde image contient GameLevel1, qui possde le nom dinstance gamelevel. La troisime image contient GameLevel2, qui possde galement le nom dinstance gamelevel. Lorsque le code ActionScript sexcute, il recherche le clip avec le nom dinstance gamelevel dans limage courante. Ce systme permet de placer diffrents clips de niveaux de jeu dans diffrentes images. Dans les images de niveau de jeu se trouvent trois champs texte dynamiques : un pour le niveau, un pour le nombre de vies restantes et un pour le score. La Figure 11.8 montre quoi ressemble lcran lorsque le jeu commence.
Figure 11.8
Trois champs texte apparaissent en bas de lcran.

Concevoir la classe
La classe commence par examiner le clip gamelevel. Elle parcourt en boucle chacun des enfants de ce clip et dtermine ce quil fait et comment il doit tre reprsent dans la classe du jeu. Par exemple, si un enfant est un objet Wall ou Floor, il est ajout un tableau des objets de ce type. Ensuite, lorsque les personnages se dplacent, ces objets sont tests pour dtecter les collisions.
hero

Le hros et les ennemis sont aussi examins. Le code considre que le hros possde le nom dinstance et les ennemis, les noms enemy1, enemy2, etc.

402

ActionScript 3.0 pour les jeux

Pour dterminer le type dobjet dun clip, nous utiliserons loprateur is. Cet oprateur compare le type dobjet dune variable un type dobjet donn (par exemple (CetteChose is MonObjet)).

La plus grande partie du code, et de loin, est celle qui gre le mouvement. Le hros peut se dplacer gauche et droite ou sauter. Il est cependant aussi affect par la gravit et peut tomber dun mur. Il peut entrer en collision avec des murs et tre stopp et entrer en collision avec le sol, ce qui interrompt sa chute. Les ennemis en font de mme, hormis que leurs mouvements ne sont pas affects par les touches ches. Ils suivent nanmoins les mmes rgles que le hros. Au lieu dutiliser un code de mouvement diffrent pour le hros et les ennemis, nous leur ferons donc partager la mme fonction de dplacement des personnages. Le dlement horizontal est un autre facteur de mouvement. Le hros et les ennemis se dplaceront lintrieur du clip gamelevel. Si la position relative du hros sur la scne dpasse vers la gauche ou la droite, nous dplacerons cependant le clip gamelevel tout entier pour le faire dler. Le reste du code peut ignorer cela car rien ne se dplacera vritablement lintrieur de gamelevel.

Planication des fonctions requises


Avant de commencer programmer, voyons quelles fonctions nous allons utiliser dans la classe et lesquelles feront appel dautres :

startPlatformGame. startGameLevel.

Initialise le score et les vies du joueur.

Initialise le niveau, en appelant les trois fonctions suivantes :

- createHero. Cre lobjet hero, en examinant le placement de linstance du clip hero. - addEnemies. Cre les objets enemy, en examinant les clips enemyX. - examineLevel. Recherche les murs, le sol et les autres lments dans le clip gamelevel.

keyDownFunction. keyUpFunction.

Consigne la touche enfonce par lutilisateur.

Consigne le moment o lutilisateur a ni dappuyer sur une touche.

gameLoop. Appele chaque image pour calculer le temps coul et appeler les quatre fonctions suivantes :

- moveEnemies. Parcourt en boucle tous les ennemis et les dplace. - moveCharacter. Dplace le personnage. - scrollWithHero. Fait dler le clip gamelevel en fonction de lemplacement du hros. - checkCollisions. Vrie si le hros entre en collision avec des ennemis ou des objets. Appelle les trois fonctions suivantes :

Chapitre 11

Jeux daction : jeux de plate-forme

403

- enemyDie. Le personnage de lennemi est supprim. - heroDie. Le hros perd une vie et la partie est termine le cas chant. - getObject. Le hros rcupre un objet.

addScore. Ajoute

des points au score et lafche. le nombre de vies restantes.

showLives. Afche levelComplete. gameComplete.

Le niveau est termin, pause et afchage de la bote de dialogue. Lutilisateur a cliqu sur le bouton de la bote de dialogue, passer laction

Le trsor est trouv, pause et afchage de la bote de dialogue.

clickDialogButton.

suivante.
cleanUp.

Supprimer la liste du jeu (gamelist) an de prparer le niveau suivant.

Maintenant que nous connaissons les fonctions que nous devons crire, crons la classe PlatformGame.as.

Crer la classe
Le chier de paquetage nest pas particulirement long, notamment si lon considre tout ce que ce jeu ralise. Nous conserverons donc tout le code dans une classe bien quil puisse tre plus utile pour un jeu de plus grande envergure davoir des classes spares pour les personnages, les objets et les lments du dcor.

Dnition de classe
Au dbut de la classe gure notre liste habituelle dinstructions import, avec notamment la classe ash.utils.getTimer, dont nous avons besoin pour les animations temporelles :
package { import ash.display.*; import ash.events.*; import ash.text.*; import ash.utils.getTimer;

Nous navons besoin que de quelques constantes. La premire est gravity (la gravit), puis la distance jusquaux bords de lcran an de commencer le dlement horizontal.

La constante gravity a t dtermine suite un processus de tentatives et derreurs. En sachant quelle serait multiplie par le nombre de millisecondes entre les tapes, jai commenc par une fraction rduite. Je lai ensuite ajuste une fois le jeu termin, jusqu obtenir un comportement de saut et de chute qui ma sembl naturel.

404

ActionScript 3.0 pour les jeux

public class PlatformGame extends MovieClip { // Constantes de mouvement static const gravity:Number = .004; // Bord pour le dlement static const edgeDistance:Number = 100;

Lorsque le niveau de jeu est scann, tous les objets trouvs sont placs dans deux tableaux. Le tableau xedObjects contient les rfrences tous les objets sur lesquels le joueur peut tenir debout ou par lesquels il peut tre bloqu. Le tableau otherObjects contient les lments comme la cl (Key), la porte (Door), le coffre (Chest) et les joyaux (Treasure) :
// Tableaux des objets private var xedObjects:Array; private var otherObjects:Array;

Le clip hero est dj nomm "hero" et est accessible depuis le code avec gamelevel.hero. Lobjet hero dans notre classe contient cependant cette rfrence et bien dautres lments dinformation concernant le personnage du hros. De la mme manire, le tableau enemies contient une liste dobjets avec des informations concernant chaque ennemi :
// Hros et ennemis private var hero:Object; private var enemies:Array;

Un certain nombre de variables sont requises pour tenir le registre de ltape du jeu. Nous utiliserons playerObjects comme tableau pour stocker des objets que le joueur a ramasss. Le seul objet de ce type dans ce jeu est lobjet Key, mais nous le stockerons dans un tableau quoi quil en soit an de prvoir le cas o dautres objets pourraient tre ajouts.
gameMode est une chane qui nous aidera indiquer aux diffrentes fonctions ce qui est arriv au hros. Elle possdera dabord la valeur "start" puis sera remplace par "play" lorsque le jeu sera prt commencer. gameScore et playerLives correspondent au nombre de points marqus et au nombre de vies restantes

du joueur. La variable lastTime contient la valeur en millisecondes de la dernire tape de lanimation du jeu. Nous lutiliserons pour cadencer lanimation temporelle utilise par les lments du jeu :
// tat du jeu private var playerObjects:Array; private var gameMode:String = "start"; private var gameScore:int; private var playerLives:int; private var lastTime:Number = 0;

Chapitre 11

Jeux daction : jeux de plate-forme

405

Commencer la partie et le niveau


Lorsque le jeu commence, nous avons besoin de certaines variables dtat du jeu. Pour cela, nous appelons la fonction startPlatformGame avec limage qui contient le premier niveau du jeu. Nous aurons dautres variables qui doivent tre rinitialises chaque niveau. Elles sont dnies lorsque le startGameLevel est appel limage suivante :
// Dmarrer le jeu public function startPlatformGame() { playerObjects = new Array(); gameScore = 0; gameMode = "play"; playerLives = 3; }

La Figure 11.9 prsente lcran de dmarrage du jeu, avec un bouton cliquer pour continuer.
Figure 11.9
Lcran de dmarrage du jeu de plate-forme.

La fonction startGameLevel
La fonction startGameLevel est appele chaque image qui contient un clip gamelevel. Elle dlgue ensuite les tches qui consistent trouver et congurer le hros, les ennemis et les objets du jeu :
// Niveau de dpart public function startGameLevel() {

406

ActionScript 3.0 pour les jeux

// Crer les personnages createHero(); addEnemies();

// Examiner le niveau et consigner tous les objets examineLevel();

La fonction startGameLevel congure galement trois couteurs vnementiels. Le premier est la fonction principale gameLoop, qui sexcutera chaque image an de faire avancer lanimation. Les deux autres sont les couteurs vnementiels du clavier, dont nous avons besoin pour rcuprer lentre de lutilisateur :
// Ajouter les couteurs this.addEventListener(Event.ENTER_FRAME,gameLoop); stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);

Pour nir, le gameMode est positionn "play" et deux fonctions sont appeles pour congurer lafchage du score et des vies. Lafchage du score est mis jour avec un appel addScore, qui ajoute un certain nombre de points au score et met jour le champ texte. Si nous ajoutons 0 point, elle agit donc comme une simple fonction dafchage :
// Congurer ltat du jeu gameMode = "play"; addScore(0); showLives(); }

La fonction createHero
Le clip hero se trouve dj dans le clip gamelevel, prt oprer. Nous devons cependant congurer et utiliser plusieurs proprits. Nous crerons donc un objet hero dans la classe pour y stocker ces proprits :
// Crer lobjet hero et dnir toutes les proprits public function createHero() { hero = new Object();

La premire proprit est une rfrence au clip qui est la reprsentation visuelle du hros. Nous pouvons donc maintenant faire rfrence au hros en spciant hero.mc plutt que gamelevel.hero. Cette rfrence fonctionnera mieux lorsque nous utilisons lobjet hero pour nos manipulations du personnage du joueur :
hero.mc = gamelevel.hero;

Chapitre 11

Jeux daction : jeux de plate-forme

407

Viennent ensuite deux proprits qui dcrivent la vlocit du hros :


hero.dx = 0.0; hero.dy = 0.0;

La proprit hero.inAir se verra attribuer la valeur true lorsque le hros ne repose pas sur le sol ferme :
hero.inAir = false;

La proprit hero.direction vaudra 1 ou 1 selon le sens dans lequel le hros est orient :
hero.direction = 1;

La proprit hero.animstate contiendra la valeur "stand" ou la valeur "walk". Avec la valeur "walk", nous saurons que le personnage doit excuter sa squence de marche. Les images de cette squence sont stockes dans hero.walkAnimation. Ici, la squence de marche se trouve dans les images 2 8. Pour mmoriser ltape quafche actuellement lanimation, nous utiliserons hero.animstep :
hero.animstate = "stand"; hero.walkAnimation = new Array(2,3,4,5,6,7,8); hero.animstep = 0;

La proprit hero.jump vaut true lorsque le joueur appuie sur la barre despace. De la mme manire, hero.moveLeft et hero.moveRight prennent les valeurs true et false selon la touche che qui est enfonce :
hero.jump = false; hero.moveLeft = false; hero.moveRight = false;

Les quelques proprits suivantes sont des constantes utilises pour dterminer la hauteur du saut du personnage et la vitesse laquelle il marche :
hero.jumpSpeed = .8; hero.walkSpeed = .15;

Les constantes hero.width et hero.height sont utilises pour dterminer les collisions. Au lieu dutiliser la largeur et la hauteur effectives du personnage, qui varie selon limage de lanimation afche, nous utiliserons les constantes suivantes :
hero.width = 20.0; hero.height = 40.0;

Ces constantes ont galement t dnies force de tentatives et dajustements. Jai commenc par des valeurs qui semblaient cohrentes, notamment en spciant que le personnage devait marcher environ 100 200 pixels par seconde. Jai ensuite ajust ces paramtres mesure que le jeu se construisait.

408

ActionScript 3.0 pour les jeux

Lorsque le hros entrera en collision avec un objet, nous le rinitialiserons sa position de dpart dans le niveau. Nous devons donc enregistrer cet emplacement pour lutiliser ce point :
hero.startx = hero.mc.x; hero.starty = hero.mc.y; }

La fonction addEnemies
Les ennemis sont stocks dans des objets qui ressemblent simplement lobjet hero. Comme les objets hero et enemy possdent les mmes proprits, nous pouvons les transmettre tous deux la fonction moveCharacter. La fonction addEnemies recherche un clip nomm enemy1 et lajoute au tableau enemies sous forme dobjet. Elle recherche ensuite enemy2, et ainsi de suite. Lune des quelques diffrences entre les ennemis et le hros tient ce que les premiers nont pas besoin des proprits startx et starty. En outre, la proprit enemy.moveRight commence avec la valeur true, an que les ennemis commencent marcher vers la droite :
// Trouver tous les ennemis dans le niveau et crer un objet pour chacun public function addEnemies() { enemies = new Array(); var i:int = 1; while (true) { if (gamelevel["enemy"+i] == null) break; var enemy = new Object(); enemy.mc = gamelevel["enemy"+i]; enemy.dx = 0.0; enemy.dy = 0.0; enemy.inAir = false; enemy.direction = 1; enemy.animstate = "stand" enemy.walkAnimation = new Array(2,3,4,5); enemy.animstep = 0; enemy.jump = false; enemy.moveRight = true; enemy.moveLeft = false; enemy.jumpSpeed = 1.0; enemy.walkSpeed = .08; enemy.width = 30.0; enemy.height = 30.0;

Chapitre 11

Jeux daction : jeux de plate-forme

409

enemies.push(enemy); i++; } }

La fonction examineLevel
Une fois que le hros et tous les ennemis ont t trouvs, la fonction examineLevel recherche tous les enfants du clip gamelevel :
// Rechercher tous les enfants du niveau et consigner les murs, les sols et les objets public function examineLevel() { xedObjects = new Array(); otherObjects = new Array(); for(var i:int=0;i<this.gamelevel.numChildren;i++) { var mc = this.gamelevel.getChildAt(i);

Si lobjet est un objet Floor ou un objet Wall, il est ajout au tableau xedObjects sous forme dobjet avec une rfrence au clip, mais galement dautres informations. Les emplacements des quatre cts sont stocks dans leftside, rightside, topside et bottomside. Nous avons besoin de pouvoir y accder rapidement au moment de dterminer les collisions :
// Ajouter les sols et les murs xedObjects if ((mc is Floor) | | (mc is Wall)) { var oorObject:Object = new Object(); oorObject.mc = mc; oorObject.leftside = mc.x; oorObject.rightside = mc.x+mc.width; oorObject.topside = mc.y; oorObject.bottomside = mc.y+mc.height; xedObjects.push(oorObject); All other objects are added very simply to the otherObjects array: // Ajouter les joyaux, le coffre, la cl et la porte otherOjects } else if ((mc is Treasure) | | (mc is Key) | | (mc is Door) | | (mc is Chest)) { otherObjects.push(mc); } } }

410

ActionScript 3.0 pour les jeux

Entre clavier
Lacceptation de lentre clavier fonctionnera comme dans les prcdents jeux, en utilisant les touches ches. Nous positionnerons cependant directement les proprits moveLeft, moveRight et jump du hero. Nous nautoriserons en outre jump prendre la valeur true que si le hero ne se trouve pas dj dans les airs :
// Consigner appuis sur les touches, dnir proprits de hero public function keyDownFunction(event:KeyboardEvent) { if (gameMode != "play") return; // Ne pas bouger avant le mode jeu

if (event.keyCode == 37) { hero.moveLeft = true; } else if (event.keyCode == 39) { hero.moveRight = true; } else if (event.keyCode == 32) { if (!hero.inAir) { hero.jump = true; } } }

La fonction keyUpFunction reconnat le moment o le joueur relche la touche et dsactive alors les drapeaux moveLeft et moveRight :
public function keyUpFunction(event:KeyboardEvent) { if (event.keyCode == 37) { hero.moveLeft = false; } else if (event.keyCode == 39) { hero.moveRight = false; } }

La boucle principale du jeu


Grce lcouteur EVENT_FRAME, la fonction gameLoop sera appele une fois par image. Elle dtermine le nombre de millisecondes qui se sont coules depuis la dernire fois o elle a t appele. Si gameMode vaut "play", elle appelle une varit de fonctions. Pour commencer, moveCharacter avec en paramtre le hero comme objet, mais galement timeDiff.
moveCharacter

elle appelle

Ensuite, elle appelle moveEnemies, qui soccupe de parcourir en boucle tous les ennemis et appelle pour chacun dentre eux.

Chapitre 11

Jeux daction : jeux de plate-forme

411

La fonction checkForCollisions verra si des ennemis entrent en collision avec le hros ou si le hros touche un objet. Pour nir, scrollWithHero synchronisera, si ncessaire, le clip gamelevel avec la position du hros :
public function gameLoop(event:Event) { // Calculer le temps coul if (lastTime == 0) lastTime = getTimer(); var timeDiff:int = getTimer()-lastTime; lastTime += timeDiff; // Ne raliser des tches quen mode Jeu if (gameMode == "play") { moveCharacter(hero,timeDiff); moveEnemies(timeDiff); checkCollisions(); scrollWithHero(); } }

La fonction moveEnemies vrie les proprits hitWallRight et hitWallLeft de chaque ennemi. Il sagit de proprits spciales attribues lobjet du personnage lorsque celui-ci est trait par moveCharacter. Nous les utilisons non pas pour lobjet hero, mais pour les ennemis. Lorsquun ennemi touche un mur, nous inversons son sens de marche :
public function moveEnemies(timeDiff:int) { for(var i:int=0;i<enemies.length;i++) { // Bouger moveCharacter(enemies[i],timeDiff); // Si lennemi rencontre un mur, changer de sens if (enemies[i].hitWallRight) { enemies[i].moveLeft = true; enemies[i].moveRight = false; } else if (enemies[i].hitWallLeft) { enemies[i].moveLeft = false; enemies[i].moveRight = true; } } }

412

ActionScript 3.0 pour les jeux

Il pourrait tre souhaitable que diffrents ennemis possdent diffrents comportements. Par exemple, vous pourriez vrier si le hros se trouve gauche ou droite de lennemi et ne vous dplacer que dans ce sens. Vous pourriez sinon vrier la distance entre le hros et lennemi et ne bouger que si le hros est proche.

Mouvement des personnages


Il est maintenant temps dexaminer le cur du jeu : la fonction moveCharacter. Elle prend en paramtre un objet de personnage, quil sagisse du hero ou dun enemy, et le stocke dans char. Elle prend aussi en paramtre le nombre de millisecondes qui se sont coules et le stocke dans timeDiff :
public function moveCharacter(char:Object,timeDiff:Number) {

Au dbut du jeu, la variable lastTime est initialise et le temps coul vaut 0. La valeur 0 ne produirait pas un rsultat satisfaisant avec certains des calculs de vlocit, aussi nous interrompons la fonction ce point si timeDiff vaut 0 :
if (timeDiff < 1) return;

Si timeDiff vaut 0, verticalChange vaudra 0 galement. Si verticalChange vaut 0, la nouvelle position verticale et lancienne position verticale seront les mmes, ce qui permet difcilement de savoir si le personnage repose sur le sol ou otte dans les airs.

La premire chose que nous devons faire est de calculer le changement vertical d la gravit. La gravit agit toujours sur nous, mme lorsque nous nous tenons debout sur le sol. Nous calculerons le changement de vlocit et de position verticale du personnage en fonction de la constante gravity et du temps qui sest coul. Pour dterminer le changement sur laxe vertical en raison de la gravit dans lanimation temporelle, nous prenons la vitesse verticale actuelle (char.dy) et la multiplions par timeDiff. Ce calcul concerne la vitesse vers le haut ou vers le bas du personnage. Ensuite, nous ajoutons timeDiff multipli par gravity pour dterminer la distance parcourue depuis que la dernire vitesse verticale (dy) a t mise jour. Ensuite, nous modions la vitesse verticale pour la suite en ajoutant gravity*timeDiff :
// Le personnage est tir vers le bas par la gravit var verticalChange:Number = char.dy*timeDiff + timeDiff*gravity; if (verticalChange > 15.0) verticalChange = 15.0; char.dy += timeDiff*gravity;

Chapitre 11

Jeux daction : jeux de plate-forme

413

Vous remarquerez que verticalChange est limite 15.0. Il sagit de ce que lon appelle la vlocit terminale. Dans la vie, cela se produit lorsque la rsistance au vent contrecarre lacclration due la gravit et que lobjet ne peut plus tomber plus vite. Nous ajoutons cette limite ici parce que, si le personnage tombe dune grande distance, il acclrera sa chute assez sensiblement et leffet visuel ne paratra pas naturel.

Avant dexaminer les mouvements vers la gauche et la droite, nous allons oprer quelques prsuppositions concernant ce qui va se passer. Nous supposerons que ltat de lanimation sera "stand" et que le nouveau sens de progression du personnage sera le mme que le sens actuel. Nous prsupposerons galement quil ny aura pas de changement horizontal de position :
// Ragir aux changements dappui sur les touches var horizontalChange = 0; var newAnimState:String = "stand"; var newDirection:int = char.direction;

Ensuite, nous vrierons immdiatement le bien-fond de cette prsupposition en examinant les proprits char.moveLeft et char.moveRight. Elles auront t dnies dans la fonction keyDownFunction si le joueur enfonce la touche che de gauche ou de droite. Si la touche de gauche est enfonce, horizontalChange se voit attribuer la valeur char.walkSpeed *timeDiff en ngatif. En outre, newDirection prend la valeur 1. Si la touche de droite est enfonce, horizontalChange se voit attribuer la valeur char.walkSpeed*timeDiff positive et newDirection prend la valeur 1. Dans les deux cas, newAnimState rcupre la valeur "walk" :
if (char.moveLeft) { // Marche vers la gauche horizontalChange = -char.walkSpeed*timeDiff; newAnimState = "walk"; newDirection = -1; } else if (char.moveRight) { // Marche vers la droite horizontalChange = char.walkSpeed*timeDiff; newAnimState = walk; newDirection = 1; }

La prochaine vrication que nous allons oprer concerne char.jump, qui se verra attribuer la valeur true lorsque le joueur appuie sur la barre despace. Nous rattribuerons immdiatement la valeur false an que cette action ne se produise quune seule fois par appui sur la barre despace. Ensuite, nous changerons char.dy en lui attribuant la valeur en ngatif de la constante char.jumpSpeed. Ce rglage donnera au personnage un lan vers le haut correspondant la force initiale du saut.

414

ActionScript 3.0 pour les jeux

Nous donnerons aussi newAnimState la valeur "jump". La Figure 11.10 montre ltat de saut du hros.
Figure 11.10
Le hros prend cette apparence chaque fois quil est en lair.

if (char.jump) { // Dbut du saut char.jump = false; char.dy = -char.jumpSpeed; verticalChange = -char.jumpSpeed; newAnimState = jump; }

Nous sommes maintenant sur le point dexaminer les xedObjects dans la scne an de vrier les collisions de mouvements. Avant cela, nous prsupposerons quil ny a pas de collision avec un mur de gauche ou de droite et que le personnage reste en lair :
// Prsupposition : pas de choc contre un mur et suspension en lair char.hitWallRight = false; char.hitWallLeft = false; char.inAir = true;

Nous calculerons la nouvelle position verticale du personnage en fonction de la position actuelle et de la variable verticalChange dnie prcdemment :
// Calculer la nouvelle position verticale var newY:Number = char.mc.y + verticalChange;

Chapitre 11

Jeux daction : jeux de plate-forme

415

Nous allons maintenant examiner chaque objet xe et voir si lun dentre eux se trouve sous les pieds du personnage. Pour cela, nous commenons par voir si le personnage est align horizontalement avec lobjet. Sil est trop loin gauche ou droite, nous pourrons cesser immdiatement dexaminer lobjet. La Figure 11.11 prsente une illustration du problme. Le rectangle A prsente le personnage dans la position actuelle et le rectangle B, dans sa prochaine position. Vous pouvez remarquer que le bas du personnage se trouve juste au-dessus du sol dans A et en dessous dans B.
Figure 11.11
En une tape, le personnage passerait au travers du sol si notre code ne larrtait pas.

Nous verrons ensuite si le personnage est actuellement au-dessus de lobjet et si son emplacement newY est en dessous. Cela signie que le personnage passerait normalement au travers de lobjet. Rappelez-vous que le point dalignement des personnages se trouve lextrmit infrieure de leurs pieds et que celui des murs et des sols se trouve leur extrmit suprieure. Au lieu de laisser le personnage traverser lobjet, nous allons le stopper directement la surface suprieure de lobjet. La proprit char.dy sera positionne 0 et la proprit char.inAir, false :
// Parcourir en boucle tous les objets xes et voir si le personnage a atterri for(var i:int=0;i<xedObjects.length;i++) { if ((char.mc.x+char.width/2 > xedObjects[i].leftside) && (char.mc.x-char.width/2 < xedObjects[i].rightside)) { if ((char.mc.y <= xedObjects[i].topside) && (newY > xedObjects[i].topside)) { newY = xedObjects[i].topside; char.dy = 0; char.inAir = false; break; } } }

416

ActionScript 3.0 pour les jeux

Pendant quun personnage repose sur le dessus dun objet Floor ou Wall, ce test vertical est ralis chaque tape et chaque tape il aura pour rsultat de conserver le personnage au-dessus du sol.

Nous raliserons ensuite un test similaire avec la position horizontale. Nous crerons une variable newX avec le nouvel emplacement horizontal, en supposant quil ny a pas de collision :
// Trouver nouvelle position horizontale var newX:Number = char.mc.x + horizontalChange;

Nous examinerons maintenant chacun des objets Wall et Floor et verrons si aucun ne correspond verticalement. Si cest le cas, nous verrons sils sont traverss avec la transition allant de la position courante la nouvelle. Nous devons vrier le ct gauche et le ct droit. Si lun des tests vaut true, la position x est dnie de manire correspondre exactement au mur et char.hitWallLeft ou char.hitWallRight prend la valeur true :
// Parcourir en boucle tous les objets pour voir si en ligne personnage est rentr dans un mur for(i=0;i<xedObjects.length;i++) { if ((newY > xedObjects[i].topside) && (newY-char.height < xedObjects[i].bottomside)) { if ((char.mc.x-char.width/2 >= xedObjects[i].rightside) && (newX-char.width/2 <= xedObjects[i].rightside)) { newX = xedObjects[i].rightside+char.width/2; char.hitWallLeft = true; break; } if ((char.mc.x+char.width/2 <= xedObjects[i].leftside) && (newX+char.width/2 >= xedObjects[i].leftside)) { newX = xedObjects[i].leftside-char.width/2; char.hitWallRight = true; break; } } }

Nous connaissons maintenant la nouvelle position du personnage, en tenant compte de la vitesse horizontale et verticale, de la gravit et des collisions avec le sol et les murs. Nous pouvons dnir lemplacement du personnage :
// Dnir lemplacement du personnage char.mc.x = newX; char.mc.y = newY;

Chapitre 11

Jeux daction : jeux de plate-forme

417

Le reste de la fonction soccupe de lapparence du personnage. Nous vrions la valeur char.inAir ; si elle vaut true ce stade, nous devons donner newAnimState la valeur "jump" :
// Dnir ltat de lanimation if (char.inAir) { newAnimState = "jump"; }

Nous avons donc ni de changer newAnimState. Cette variable a dmarr avec la valeur "stand". Ensuite, elle est passe "walk" si la touche che de gauche ou de droite a t enfonce. Elle a pu aussi passer "jump" si le joueur a appuy sur la barre despace ou si le personnage se trouvait dans les airs. Nous allons maintenant dnir ltat de lanimation (animstate) en lui attribuant la valeur de newAnimState :
char.animstate = newAnimState;

Ensuite, nous utiliserons animstate pour dcider de lapparence donner au personnage. Si celui-ci marche, animstep est augmente dune fraction de timeDiff et une vrication est opre pour voir si animstep doit reboucler vers 0. Ensuite, limage du personnage est dnie en fonction de celle spcie dans walkAnimation :
// Avancer dans le cycle de marche if (char.animstate == "walk") { char.animstep += timeDiff/60; if (char.animstep > char.walkAnimation.length) { char.animstep = 0; } char.mc.gotoAndStop(char.walkAnimation[Math.oor(char.animstep)]); If the character is not walking, well set the frame to either stand or jump depending on the value of animstate: // Pas de marche, afcher ltat debout ou saut } else { char.mc.gotoAndStop(char.animstate); }

La dernire tche dont moveCharacter doit se charger est de dnir lorientation du personnage. La proprit direction vaut 1 pour sorienter vers la gauche et 1 pour sorienter vers la droite. Nous la remplirons avec la valeur de newDirection qui a t dtermine prcdemment. Ensuite, nous dnirons la proprit scaleX du personnage.

Le positionnement de la proprit scaleX dun sprite ou dun clip constitue un moyen simple de renverser nimporte quel objet. Toutefois, si vous avez des ombres ou des effets 3D dans les graphismes de lobjet, vous devez dessiner une autre version de lobjet qui pointe dans la direction oppose ; sans cela, le personnage invers ne prsenterait pas lapparence souhaite.

418

ActionScript 3.0 pour les jeux

// Directions modies if (newDirection != char.direction) { char.direction = newDirection; char.mc.scaleX = char.direction; } }

Dlement du niveau du jeu


scrollWithHero est une autre fonction qui sexcute chaque image. Elle vrie la position du hros

par rapport la scne. stagePosition est calcule en ajoutant gamelevel.x hero.mc.x. Ensuite, nous obtenons galement rightEdge et leftEdge en fonction des bords de lcran, moins la constante edgeDistance. Cest ces points que lcran commence dler si besoin. Si le hros dpasse le bord droit (rightEdge), la position du niveau (gamelevel) est dplace de la mme distance vers la gauche. Si gamelevel arrive trop loin gauche, il est cependant empch davancer an que lextrmit droite de gamelevel se trouve du ct droit de la scne. De la mme manire, si le hros est assez loin gauche, le clip gamelevel avance droite, mais au maximum jusquau moment o le ct de gamelevel passerait droite du ct gauche de lcran :
// Faire dler vers la droite ou la gauche en cas de besoin public function scrollWithHero() { var stagePosition:Number = gamelevel.x+hero.mc.x; var rightEdge:Number = stage.stageWidth-edgeDistance; var leftEdge:Number = edgeDistance; if (stagePosition > rightEdge) { gamelevel.x -= (stagePosition-rightEdge); if (gamelevel.x < -(gamelevel.width-stage.stageWidth)) gamelevel.x = -(gamelevel.width-stage.stageWidth); } if (stagePosition < leftEdge) { gamelevel.x += (leftEdge-stagePosition); if (gamelevel.x > 0) gamelevel.x = 0; } }

Vrier les collisions


La fonction checkCollisions parcourt en boucle tous les ennemis et tous les autres objets (otherObjects). Elle utilise une fonction hitTestObject simple pour chaque objet an de raliser les tests de collision.

Chapitre 11

Jeux daction : jeux de plate-forme

419

Si la collision du hero et de lenemy intervient pendant que le hero se trouve en lair et progresse vers le bas, lennemi est dtruit en appelant enemyDie. Si ce nest pas le cas, nous appelons heroDie la place :
// Vrier les collisions avec les ennemis et les objets public function checkCollisions() { // Ennemis for(var i:int=enemies.length-1;i>=0;i--) { if (hero.mc.hitTestObject(enemies[i].mc)) { // Le hros saute-t-il vers le bas sur lennemi ? if (hero.inAir && (hero.dy > 0)) { enemyDie(i); } else { heroDie(); } } }

Si le hero entre en collision avec un objet dans la liste otherObjects, nous appelons getObject en lui passant le numro de llment dans la liste :
// Objets for(i=otherObjects.length-1;i>=0;i--) { if (hero.mc.hitTestObject(otherObjects[i])) { getObject(i); } } }

Mort des ennemis et du joueur


Lorsquun objet enemy est dtruit, il est supprim du clip gamelevel et de la liste enemies. Il ny a besoin de rien dautre pour le faire disparatre. Nous allons tout de mme insrer un effet spcial. En utilisant la classe PointBurst du Chapitre 8, nous ferons apparatre un petit message lendroit o lennemi a t supprim, en afchant les mots "Got Em!" (Touchs !). La Figure 11.12 prsente lcran juste aprs que lennemi a t dtruit.
// Supprimer lennemi public function enemyDie(enemyNum:int) { var pb:PointBurst = new PointBurst(gamelevel, "Got Em!",enemies[enemyNum].mc.x, enemies[enemyNum].mc.y-20); gamelevel.removeChild(enemies[enemyNum].mc); enemies.splice(enemyNum,1); }

420

ActionScript 3.0 pour les jeux

Figure 11.12
Les mots "Got Em!" apparaissent lendroit o se trouvait lennemi, changent de taille et disparaissent rapidement.

Pour utiliser la classe PointBurst, vous devez en faire glisser une copie dans le mme dossier que les chiers PlatformGame.a et PlatformGame.as. Vous aurez aussi besoin dajouter la police Arial la bibliothque de PlatformGame.a et de la congurer de manire lexporter pour ActionScript.

Lorsque le joueur meurt aprs tre entr dans un ennemi, nous avons lopportunit dafcher la bote de dialogue conue prcdemment. Pour crer la bote de dialogue, il nous suft de crer un nouvel objet Dialog et de lattribuer une variable temporaire. Ensuite, nous dnissons les positions x et y et utilisons addChild pour le placer dans la scne. Nous vrions aprs cela le nombre de vies du joueur (playerLives). Sil est nul, nous afchons le texte "Game Over!" (partie termine) dans la bote de dialogue et donnons gameMode la valeur "gameover". Sil reste des vies, nous soustrayons une unit au compte, afchons le message "He Got You!" (il vous a eu) et donnons gameMode la valeur "dead". La variable gameMode joue un rle important quant ce qui se passe lorsque le joueur clique sur le bouton dans la bote de dialogue :
// Lennemi a eu le joueur public function heroDie() { // Afcher la bote de dialogue var dialog:Dialog = new Dialog(); dialog.x = 175; dialog.y = 100; addChild(dialog);

Chapitre 11

Jeux daction : jeux de plate-forme

421

if (playerLives == 0) { gameMode = gameover; dialog.message.text = Game Over!; } else { gameMode = dead; dialog.message.text = He Got You!; playerLives--; } hero.mc.gotoAndPlay(die); }

La dernire tche dont soccupe la fonction heroDie consiste demander au clip hero de sexcuter partir de limage die. Cette fonction commence une animation qui montre le personnage qui tombe en arrire. Une commande stop gure la n du scnario de hero an que le clip ne boucle pas pour revenir au dbut. La Figure 11.13 montre le hros mort et la bote de dialogue.
Figure 11.13
Le hros est mort et le joueur doit maintenant cliquer sur le bouton pour commencer une nouvelle vie.

Collecter des points et des objets


Lorsque le joueur entre en collision avec un objet du tableau otherObjects, il obtient des points, rcupre un objet dans son inventaire ou termine le niveau.

422

ActionScript 3.0 pour les jeux

Si le type de lobjet est Treasure, le joueur rcupre 100 points. Nous utiliserons la classe PointBurst nouveau pour afcher le texte 100 lemplacement concern. Ensuite, nous supprimerons lobjet de gamelevel et de otherObjects. Nous appellerons la fonction addScore pour ajouter 100 points et mettrons jour le score :
// Le joueur entre en collision avec des objets public function getObject(objectNum:int) {

// Attribuer des points pour les joyaux if (otherObjects[objectNum] is Treasure) { var pb:PointBurst = new PointBurst(gamelevel,100, otherObjects[objectNum].x,otherObjects[objectNum].y); gamelevel.removeChild(otherObjects[objectNum]); otherObjects.splice(objectNum,1); addScore(100);

Lune des solutions simples pour avoir diffrentes valeurs de point pour les diffrents joyaux consiste utiliser le nom dinstance de lobjet Treasure. En ltat du jeu, ce nom nest utilis par rien dautre. Vous pourriez donc attribuer le nom "100" un objet Treasure et "200" un autre. Ensuite, il sufrait dexaminer otherObjects[numObjet].name pour attribuer le nombre de points correspondant.

Si lobjet est une cl (Key), nous utilisons PointBurst pour afcher le message "Got Key!" (Cl rcupre !). Nous ajoutons la chane "Key" au tableau playerObjects qui sert dinventaire. Lobjet est ensuite supprim de gamelevel et otherObjects :
// Cl rcupre, ajouter linventaire } else if (otherObjects[objectNum] is Key) { pb = new PointBurst(gamelevel,"Got Key!",otherObjects[objectNum].x,otherObjects [objectNum].y); playerObjects.push("Key"); gamelevel.removeChild(otherObjects[objectNum]); otherObjects.splice(objectNum,1);

Lobjet peut aussi tre une porte (Door). Dans ce cas, nous examinons linventaire playerObjects an de vrier si llment "Key" y gure. Si le joueur a eu la cl, la porte souvre. Nous ferons cela en demandant au clip Door de lancer sa lecture partir de limage open. Ensuite, nous appellerons levelComplete, qui afche une bote de dialogue :
// Porte atteinte, terminer le niveau si le hros a la cl } else if (otherObjects[objectNum] is Door) { if (playerObjects.indexOf("Key") == -1) return; if (otherObjects[objectNum].currentFrame == 1) {

Chapitre 11

Jeux daction : jeux de plate-forme

423

otherObjects[objectNum].gotoAndPlay("open"); levelComplete(); }

La dernire possibilit est que le joueur ait trouv le coffre (Chest). Ce cas signale la n du second niveau et la n de la qute du joueur. Ce clip possde galement une image open, mais nous utiliserons gotoAndStop car il ny a pas danimation cet endroit. Ensuite, nous appelons gameComplete :
// Coffre trouv, jeu gagn } else if (otherObjects[objectNum] is Chest) { otherObjects[objectNum].gotoAndStop(open); gameComplete(); } }

Afcher ltat du joueur


Il est maintenant temps de considrer certaines fonctions utilitaires. Ces fonctions sont appeles diffrents endroits dans le jeu en cas de besoin. La premire ajoute un certain nombre de points la variable gameScore, puis met jour le champ texte scoreDisplay dans la scne :
// Ajouter des points au score public function addScore(numPoints:int) { gameScore += numPoints; scoreDisplay.text = String(gameScore); }

La fonction qui suit place la valeur de playerLives dans le champ texte livesDisplay :
// Mettre jour les vies du joueur public function showLives() { livesDisplay.text = String(playerLives); }

Terminer les niveaux et le jeu


Le premier niveau se termine lorsque le joueur rcupre la cl et ouvre la porte. Le second se termine lorsque le joueur trouve le coffre du trsor. Dans les deux cas, un objet Dialog est cr et plac au centre de lcran. Dans le cas o la porte est ouverte et le niveau un, termin, la bote de dialogue afche le message "Level Complete!" (niveau termin) et gameMode se voit attribuer la valeur "done" :
// Niveau termin, afcher la bote de dialogue public function levelComplete() { gameMode = "done"; var dialog:Dialog = new Dialog();

424

ActionScript 3.0 pour les jeux

dialog.x = 175; dialog.y = 100; addChild(dialog); dialog.message.text = Level Complete!; }

Si le deuxime niveau se termine aprs que le joueur a trouv le coffre, le message "You Got the Treasure!" apparat et gameMode rcupre la valeur "gameover" :
// Partie termine, afcher la bote de dialogue public function gameComplete() { gameMode = gameover; var dialog:Dialog = new Dialog(); dialog.x = 175; dialog.y = 100; addChild(dialog); dialog.message.text = You Got the Treasure!; }

La bote de dialogue du jeu


La bote de dialogue apparat lorsque le joueur est mort, a termin un niveau ou a ni le jeu. Lorsque le joueur clique sur le bouton de cette bote de dialogue, nous appelons la fonction clickDialogButton dans la classe principale. Voici le code qui se trouve dans lobjet Dialog :
okButton.addEventListener(MouseEvent.CLICK,MovieClip(parent).clickDialogButton);

La premire tche dont se charge la fonction clickDialogButton consiste supprimer la bote de dialogue elle-mme :
// Le joueur a cliqu sur le bouton de la bote de dialogue public function clickDialogButton(event:MouseEvent) { removeChild(MovieClip(event.currentTarget.parent));

Sa prochaine action dpend de la valeur de gameMode. Si le joueur est mort, lafchage du nombre de vies est mis jour, le hros est replac au dbut du niveau et gameMode rcupre de nouveau la valeur "play" an que le jeu se poursuive :
// Nouvelle vie, recommencer ou passer au niveau suivant if (gameMode == "dead") { // Rinitialisation du hros showLives(); hero.mc.x = hero.startx; hero.mc.y = hero.starty; gameMode = play;

Chapitre 11

Jeux daction : jeux de plate-forme

425

Si gameMode vaut "gameover" (ce qui se produit lorsque le joueur meurt pour la dernire fois ou lorsque le joueur trouve le coffre), nous appelons la fonction cleanUp pour supprimer le clip gamelevel et nous ramenons lanimation au dbut :
} else if (gameMode == "gameover") { cleanUp(); gotoAndStop(start);

Lautre possibilit concerne le cas o gameMode vaut "done". Cela signie quil est temps de passer au niveau suivant. La fonction cleanUp est appele de nouveau et lanimation est envoye limage suivante, o une nouvelle version de gamelevel attend :
} else if (gameMode == "done") { cleanUp(); nextFrame(); }

Lune des dernires choses effectuer consiste ramener le focus du clavier sur la scne. La scne perd le focus lorsque lutilisateur clique sur le bouton. Nous souhaitons nous assurer que les touches ches et la barre despace seront de nouveau achemines vers la scne :
// Redonner la scne le focus clavier stage.focus = stage; }

La fonction cleanUp, quappelle la fonction clickDialogButton, supprime le gamelevel ainsi que les couteurs qui taient appliqus la scne et lcouteur ENTER_FRAME. Ces couteurs seront recrs dans startLevel si le joueur doit passer au niveau suivant :
// Nettoyer le jeu public function cleanUp() { removeChild(gamelevel); this.removeEventListener(Event.ENTER_FRAME,gameLoop); stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpFunction); }

Modier le jeu
Pour que ce jeu devienne vraiment palpitant, il conviendrait dy ajouter dautres niveaux contenant plus dlments. Vous pouvez ajouter autant de niveaux que vous le souhaitez. Pour linstant, le premier niveau se termine lorsque la cl est dans linventaire et que la porte est trouve. Il pourrait tre intressant de modier le code an dajouter dautres options, par exemple avec une porte qui ne requiert pas de cl ou une porte qui en ncessite plusieurs.

426

ActionScript 3.0 pour les jeux

Lautre fonctionnalit qui pourrait rendre le jeu plus attrayant consisterait avoir plus de moyens de mourir. Pour linstant, il nest possible de mourir que si un ennemi vous touche alors que vous ne sautez pas et il est assez facile de se dbarrasser des ennemis. Que se passerait-il en revanche si des pierres ou des objets pouvaient vous tuer galement ? Par exemple, la scne pourrait contenir des fosses de lave anime quil faudrait imprativement sauter sans les toucher pour parvenir au but. Il pourrait aussi y avoir dautres obstacles anims, comme des ches qui jaillissent des murs. Ces objets se comporteraient comme des ennemis, mais "mourraient" en atteignant le mur oppos. Vous pourriez aussi dnir un Timer pour crer une nouvelle che intervalles rguliers. Les possibilits sont quasiment innies. Pourtant, sil est ais de crer un jeu de plate-forme cratif et amusant, il est tout aussi facile den crer un mauvais. Concevez donc soigneusement votre jeu et testez et ajustez-le au fur et mesure.

12
Jeux de mondes : jeux de conduite et dexploration
Au sommaire de ce chapitre

Crer un jeu de conduite en vue arienne Crer un jeu de course

428

ActionScript 3.0 pour les jeux

Au chapitre prcdent, vous avez vu comment il tait possible de crer un petit monde lintrieur dun jeu ActionScript. Ce type de jeu de plate-forme cre une vue latrale qui est souvent utilise pour les jeux daventure en intrieur et les qutes. Un autre type de jeu de monde peut tre cr avec une vue arienne. Le joueur se dplace alors dans une carte. Ce type de reprsentation peut convenir nimporte quel genre de scnario et de thme. Jai cependant rcemment remarqu quil existait un grand nombre de jeux de ce genre o le joueur conduisait un vhicule dans une ville ou une autre sorte de site extrieur. Dans ce chapitre, nous allons crer un jeu de conduite en vue arienne et un jeu de course simple. Ces deux types de jeux ont un certain nombre de points communs.

Crer un jeu de conduite en vue arienne


Crons un jeu de conduite simple en vue arienne. Ce jeu contient une carte dtaille, une voiture, des objets ramasser et une logique de jeu complexe qui implique un emplacement o dposer les objets collects. Codes sources http://ashgameu.com A3GPU12_TopDownGame.zip

Crer un jeu en vue arienne


Notre jeu dexemple pour ce chapitre met en scne un campus de lyce. Une zone de trois blocs sur trois inclut diffrents immeubles qui remplissent lespace entre les rues (voir Figure 12.1). Si vous examinez attentivement la grille en bas de la carte, vous verrez une petite voiture. Il sagit de la voiture du joueur, quil peut "conduire" dans la carte. Vu les dimensions de la carte, le joueur ne pourra pas en voir plus dune petite section la fois. La carte fait 2 400 pixels carrs et lcran nen fait que 550 400. mesure que le joueur conduit, la carte se repositionne en conservant la voiture exactement au centre de la scne. La Figure 12.2 prsente lcran lorsque le joueur commence. Vous pouvez voir la grille en bas et une portion du parking au-dessus. Une bande semi-transparente avec les lments du score apparat en bas. La carte est loge dans sa totalit dans un unique clip nomm GameMap. lintrieur, les neuf groupes dimmeubles possdent chacun leur propre clip pour des raisons pratiques dorganisation. Les rues sont composes de morceaux droits et de trois diffrents types de coins. La clture externe est constitue de diffrentes pices galement.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

429

Figure 12.1
Lunivers entier du jeu fait environ 2 400 pixels de large et 2 400 de haut.

Figure 12.2
Seule une petite zone de 550 400 de la carte peut tre vue la fois.

430

ActionScript 3.0 pour les jeux

Tous ces lments graphiques ne sont l que pour la dcoration. Ils nimportent pas pour le code du jeu. Voil une excellente nouvelle pour les graphistes, car cela signie quils ont toute libert pour crer larrire-plan artistique pour le jeu. La voiture pourra se dplacer nimporte o dans lcran avec quelques restrictions simples. Pour commencer, la voiture sera contrainte de rester dans les limites internes de la clture. Cette contrainte sera dnie par des valeurs x et y minimales et maximales.
Blocks.

Ensuite, la voiture sera empche dentrer dans la zone de certains autres clips. Nous les appellerons Si la voiture entre en collision avec lun de ces Blocks, elle sera stoppe son bord. Les neuf Blocks seront placs sur les neuf blocs de ville dans la carte. La Figure 12.3 signale leurs emplacements avec des bordures paisses.

Le terme bloc possde trois signications. La plus importante est quil bloque la voiture en lempchant dentrer dans la zone. Il reprsente cependant aussi des blocs dimmeubles dans cette carte. Enn, il est de forme rectangulaire.

Figure 12.3
Les neuf clips Block sont ici reprs par des bordures paisses.

Le but du jeu est de rcolter les ordures dans le campus et de les dposer dans les bennes de recyclage. Il y aura trois bennes ordures dans trois des coins du campus.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

431

Il y aura trois types dordures, un pour chaque benne : les canettes, les papiers et les bouteilles. Au lieu de placer manuellement les ordures dans la carte, nous chargerons notre code de le faire. Celuici placera cent ordures diffrentes de manire alatoire dans le campus. Nous devons nous assurer que ces ordures napparaissent pas sur les Blocks, sans quoi la voiture ne pourrait les atteindre. Le d consiste ramasser toutes les ordures et dposer chaque type dans sa propre benne. La voiture ne peut cependant contenir que dix ordures diffrentes la fois. Avant de pouvoir en ramasser dautres, le joueur devra donc commencer par en dposer dans les bennes. Le jeu se complique ainsi parce que le joueur devra dcider le type dordure ramasser en fonction de la benne quil souhaite atteindre pour les y dverser.

Conception du jeu
Il vaut la peine dexaminer tous les intrants, les objets et les mcanismes du jeu avant de commencer programmer notre code. Cela nous permettra de clarier ce que nous faisons.

Contrle de la voiture
La voiture sera contrle par les touches ches. En fait, seules trois des quatre touches ches seront requises. La Figure 12.4 prsente le clip car.
Figure 12.4
Le clip car pointe vers la droite ; valeur rotation 0 correspond donc la direction que Math.cos et Math.sin reprsentent.

432

ActionScript 3.0 pour les jeux

Nous ne sommes pas en train de crer un jeu de simulation ; nous pouvons donc ignorer lacclration, le freinage et la marche arrire pour autant que le joueur nen a pas besoin. Dans le cas prsent, il suft de pouvoir tourner gauche et droite et davancer pour sorienter. Nous utiliserons les touches ches de gauche et de droite pour modier directement la proprit rotation de la voiture. Ensuite, nous utiliserons les valeurs Math.cos et Math.sin de la rotation pour dnir lorientation du mouvement en avant. Cette approche sapparente celle que nous avons adopte avec les touches ches et la trigonomtrie dans le jeu de mtorites du Chapitre 7.

Limites de la voiture
La voiture est limite rouler sur les rues. Plus exactement, la voiture ne peut pas quitter la carte et ne peut pas rouler dans la zone de lun des clips Block. Le clip Block est prsent la Figure 12.5.
Figure 12.5
Le Block ne se voit jamais dans le jeu ; seuls nous le voyons pendant la conception du niveau. Une ne bordure rouge et un remplissage semi-transparent nous aident le positionner.

Pour cela, nous comparerons le rectangle de la voiture aux rectangles des objets Block. Nous obtiendrons une liste de ces objets lorsque le jeu dmarre. Si le rectangle de la voiture et lun de ceux des Blocks se recoupent, nous repousserons la voiture au point o elle se trouve, juste lextrieur du Block. Ce mcanisme est semblable celui que nous avons utilis pour le jeu de casse-brique du Chapitre 5. Au lieu de faire rebondir la voiture sur le Block, nous la positionnerons parfaitement de manire quelle se trouve exactement lextrieur du Block.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

433

Ordures
Les ordures correspondent en fait un unique clip TrashObject de trois images. Nous les placerons de manire alatoire dans la carte, en nous assurant quaucun ne se trouve plac sur les Blocks. Lorsquun lment est plac, il est alatoirement conduit limage 1, 2 ou 3, qui reprsentent chacune un des trois types dordures : canettes, papiers ou bouteilles. La Figure 12.6 prsente le clip TrashObject. mesure que la voiture se dplace, nous vrions si la distance entre chaque TrashObject et la voiture est assez rduite pour que la voiture le ramasse. Nous supprimerons ces objets de lcran et tiendrons le registre du nombre dordures de chaque type ramass par le joueur. Nous limiterons ce nombre dix objets la fois et indiquerons au joueur quand la voiture est pleine. Lorsque le joueur se rapprochera ensuite sufsamment dune benne, nous ramnerons zro le type dordure correspondant dans la collection du joueur. Les joueurs astucieux rempliront leur voiture avec un mme type dordure et iront dposer les dix lments dans la benne approprie.
Figure 12.6
Le clip TrashObject contient trois images diffrentes, chacune avec un type dordure diffrent.

Score et chronomtre du jeu


Les indicateurs de score (voir en bas de la Figure 12.7) sont plus importants dans ce jeu que dans ceux que nous avons crs jusque-l. Le joueur doit y prter attention.

434

ActionScript 3.0 pour les jeux

Figure 12.7
Les indicateurs de score se trouvent en bas de lcran, avec un cadre semi-transparent en dessous.

Les trois premiers indicateurs indiquent le nombre dordures que possde le joueur. Comme les joueurs ne peuvent avoir plus de dix ordures avant de se rendre une benne, ils chercheront de prfrence remplir la voiture avec un type dordure particulier. Ils souhaiteront en outre surveiller le moment o leur voiture est presque pleine. Nous passerons les trois chiffres en rouge lorsque la voiture sera pleine dordures. En outre, nous utiliserons un son pour lindiquer. Un son de collecte sentendra lorsque le joueur sapprochera sufsamment dune ordure. Si la voiture est pleine, le joueur entend un autre son et lordre reste sur le sol. Les deux indicateurs suivants prsentent le nombre dordures qui restent trouver, le nombre dordures ramasses et le temps coul. La valeur cl ici est le temps. Les joueurs trouveront tous les cent ordures moins quils ne se dcouragent trop tt. Cest donc le temps qui dnira vritablement leur score. Le but du jeu sera de nir le plus vite possible.

La dnition de classe
Le code de ce jeu est plutt simple considrant tout ce que le jeu permet de faire. Le jeu commence en examinant le monde cr dans lanimation Flash et en vriant chaque image les changements et les mouvements du joueur. Le paquetage commence par importer un grand nombre de bibliothques de classe. Nous aurons besoin de nos classes habituelles, ainsi que de ash.geom.* pour lutilisation des objets Point et Rectangle et de ash.media.Sound et ash.media.SoundChannel pour les effets sonores :
package { import ash.display.*; import ash.events.*;

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

435

import ash.text.*; import ash.geom.*; import ash.utils.getTimer; import ash.media.Sound; import ash.media.SoundChannel;

Le jeu requiert un certain nombre de constantes. speed et turnSpeed contrlent la raction de la voiture aux touches ches. carSize dtermine le rectangle de contour de la voiture par rapport son point central :
public class TopDownDrive extends MovieClip { // Constantes static const speed:Number = .3; static const turnSpeed:Number = .2; static const carSize:Number = 50;

La constante mapRect dnit les limites de la carte. Il sagit approximativement de lemplacement de la clture qui entoure le campus :
static const mapRect:Rectangle = new Rectangle(-1150,-1150,2300,2300);

La constante numTrashObjects dsigne le nombre dordures cres au dbut du jeu. maxCarry dnit galement le nombre dordures que le joueur peut avoir dans la voiture avant de devoir dcharger sa cargaison dans une benne :
static const numTrashObjects:uint = 100; static const maxCarry:uint = 10;

Les deux constantes suivantes dnissent la distance pour les collisions avec les ordures et les bennes. Il se peut que vous deviez ajuster ces valeurs si vous dplacez les bennes un peu lcart des routes ou si vous modiez la constante carSize :
static const pickupDistance:Number = 30; static const dropDistance:Number = 40;

Il faut viter de choisir une valeur trop grande pour pickUpDistance car il est important que le joueur puisse faire glisser la voiture prs des ordures sans les rcolter sil sefforce de ne ramasser que les ordures dun certain type.

Les variables peuvent tre rparties en trois groupes. Le premier est une srie de tableaux qui consignent les objets du jeu.

436

ActionScript 3.0 pour les jeux

Le tableau blocks contiendra tous les objets Block qui empchent la voiture de quitter la route. trashObjects est une liste de toutes les ordures rparties alatoirement dans la carte. Le tableau trashcans contient les trois bennes qui sont les points de dpose pour les ordures :
// Objets du jeu private var blocks:Array; private var trashObjects:Array; private var trashcans:Array;

Lensemble de variables suivant concerne ltat du jeu. Nous commencerons par lhabituelle srie de variables boolennes des touches ches :
// Variables de jeu private var arrowLeft, arrowRight, arrowUp, arrowDown:Boolean;

Viennent ensuite deux valeurs de temps. La premire, lastTime, sera utilise pour dterminer la dure coule depuis la dernire tape danimation. La seconde, gameStartTime, sera utilise pour dterminer depuis combien de temps la partie a commenc :
private var lastTime:int; private var gameStartTime:int;

Le tableau onboard est une liste avec un lment pour chaque benne, soit trois lments. Ils commenceront 0 et contiendront le nombre de chaque type dordure que le joueur transporte dans la voiture :
private var onboard:Array;

La variable totalTrashObjects contiendra la somme des trois nombres dans onboard. Nous lutiliserons en rfrence rapide lorsquil sagira de dcider sil y a assez de place pour dautres ordures dans la voiture :
private var totalTrashObjects:int; score

correspond simplement au nombre dordures collect et dpos dans les bennes :


private var score:int;

La variable lastObject est utilise pour dterminer le moment o le son de charge pleine de la voiture doit tre mis. Lorsque le joueur a dj collect dix ordures dans sa voiture, nous mettons un son dalerte, linverse du son positif que le joueur obtient lorsquil reste de la place pour les ordures. Comme lordure nest pas supprime de la carte, il est fort probable que le joueur entre immdiatement en collision avec elle une nouvelle fois et continue de le faire jusqu ce que la voiture scarte sufsamment. Nous enregistrerons donc une rfrence lobjet Trash dans lastObject et la sauvegarderons pour nous y rfrer par la suite. Nous saurons ainsi que le son ngatif a dj t mis pour cet objet et quil nest pas ncessaire de le produire de nouveau tant que la voiture reste proximit :
private var lastObject:Object;

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

437

Les dernires variables sont des rfrences aux quatre sons stocks dans la bibliothque de lanimation. Tous ces sons ont t dnis avec des proprits de liaison qui les mettent disposition de notre code ActionScript sous forme de classes :
// Sons var theHornSound:HornSound = new HornSound(); var theGotOneSound:GotOneSound = new GotOneSound(); var theFullSound:FullSound = new FullSound(); var theDumpSound:DumpSou nd = new DumpSound();

La fonction constructeur
Lorsque lanimation atteint limage 2, elle appelle startTopDownDrive pour commencer le jeu. Cette fonction appelle immdiatement ndBlocks et placeTrash pour congurer la carte. Nous examinerons ces fonctions sous peu.
public function startTopDownDrive() { // Rcuprer les blocs ndBlocks(); // Placer les ordures placeTrash();

Comme il ny a que trois bennes et quelles ont t spciquement nommes dans le gamesprite, nous les placerons dans le tableau trashcans laide dune simple ligne de code.

Le gamesprite est linstance sur la scne de llment de bibliothque GameMap. Dans la bibliothque, il sagit en fait dun MovieClip. Comme il ne fait quune image, nous lappellerons cependant gamesprite.
// Conguration des bennes trashcans = new Array(gamesprite.Trashcan1, gamesprite.Trashcan2, gamesprite.Trashcan3);

Comme les objets Trash sont crs par notre code et que la voiture se trouve dans le gamesprite avant que notre code sexcute, les ordures seront au-dessus de la voiture. Cela sera apparent une fois la voiture pleine et que le joueur passe sur dautres ordures. Si nous ny faisions rien, vous verriez les ordures otter au-dessus de la voiture. En appelant setchildIndex avec gamesprite.numChildren1, nous replaons en fait la voiture au-dessus de tous les autres lments du jeu :
// Sassurer que la voiture est au-dessus gamesprite.setChildIndex(gamesprite.car,gamesprite.numChildren-1);

438

ActionScript 3.0 pour les jeux

Nous aurions pu aussi crer un clip vide dans le clip GameMap an de contenir toutes les ordures. Nous aurions pu alors le placer dans un calque de scnario juste sous la voiture, au-dessus de la route. Ce serait important si nous souhaitions que des lments, comme un pont, restent afchs aussi bien au-dessus de la voiture que des ordures.

Il nous faut trois couteurs, un pour lvnement ENTER_FRAME, qui guidera le jeu entier, et deux autres pour les appuis sur les touches :
// Ajouter les couteurs this.addEventListener(Event.ENTER_FRAME,gameLoop); stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);

Nous congurons ensuite ltat du jeu. gameStartTime prend la valeur de temps actuelle. Le tableau onboard est rempli avec des zros, tout comme totalTrashObjects et score :
// Conguration des variables du jeu gameStartTime = getTimer(); onboard = new Array(0,0,0); totalTrashObjects = 0; score = 0;

Pour faire avancer le jeu, nous allons immdiatement appeler deux fonctions utilitaires. La fonction centerMap permet de positionner le gamesprite de manire que la voiture se trouve au centre de lcran. Si nous ne lappelions pas maintenant, nous verrions lespace dun instant le gamesprite tel quil apparat dans le scnario brut avant le premier vnement ENTER_FRAME. Un problme du mme genre conduit appeler ici showScore, an que tous les indicateurs de score possdent leurs valeurs dorigine avant que le joueur ne puisse les voir :
centerMap(); showScore();

Pour nir, nous mettons un son avec la fonction utilitaire playSound. Jai inclus un son de klaxon simple pour signaler au joueur que le jeu a commenc :
playSound(theHornSound); }

Trouver les blocs


Pour trouver tous les objets Block dans le gamesprite, nous devons parcourir en boucle tous les enfants de gamesprite et voir lesquels sont de type Block laide de loprateur is. Nous ajouterons ceux qui le sont au tableau blocks. Nous positionnerons galement la proprit visible de chacun des Blocks false an quils ne safchent pas pour le joueur. Nous pourrons ainsi les voir

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

439

clairement lors du dveloppement de lanimation mais naurons pas nous rappeler de les masquer ou de les rendre transparents avant de nir le jeu :
// Trouver tous les objets Block public function ndBlocks() { blocks = new Array(); for(var i=0;i<gamesprite.numChildren;i++) { var mc = gamesprite.getChildAt(i); if (mc is Block) { // Ajouter au tableau et rendre invisible blocks.push(mc); mc.visible = false; } } }

Placer les ordures


Pour placer alatoirement cent ordures, nous devons boucler cent fois en plaant un objet dordure chaque fois :
// Crer des objets Trash alatoires public function placeTrash() { trashObjects = new Array(); for(var i:int=0;i<numTrashObjects;i++) {

Pour chaque placement, nous commenons une seconde boucle. Ensuite, nous testons diffrentes valeurs pour les positions x et y de lordure :
// Boucle innie while (true) { // Emplacement alatoire var x:Number = Math.oor(Math.random()*mapRect.width)+mapRect.x; var y:Number = Math.oor(Math.random()*mapRect.height)+mapRect.y;

Une fois que nous avons un emplacement, nous le vrions par rapport aux Blocks. Si lemplacement se trouve sur un Block, nous le notons en donnant la variable locale isOnBlock la valeur true :
// Vrier tous les blocs pour voir si chevauchement var isOnBlock:Boolean = false; for(var j:int=0;j<blocks.length;j++) { if (blocks[j].hitTestPoint(x+gamesprite.x,y+gamesprite.y)) { isOnBlock = true; break; } }

440

ActionScript 3.0 pour les jeux

Si lemplacement nentre en intersection avec aucun Block, nous poursuivons et crons le nouvel objet TrashObject. Ensuite, nous dnissons son emplacement. Nous avons galement besoin de choisir un type alatoire pour cet lment, en conduisant le clip limage 1, 2 ou 3. La Figure 12.8 prsente le dbut dun jeu o trois clips TrashObject ont t placs proximit du point de dpart de la voiture.

Le clip TrashObject contient trois images avec un graphisme diffrent dans chacune. Ces graphismes sont en fait eux-mmes des clips. Il nest pas ncessaire quil sagisse de clips spars pour les utiliser dans TrashObject, mais nous souhaitons pouvoir utiliser les mmes graphismes pour les bennes an dindiquer quel type dordure chacune correspond. En procdant ainsi, nous navons quune version de chaque image dans la bibliothque.

Nous ajoutons cet objet dordure trashObjects et quittons la boucle.


Figure 12.8
Trois clips TrashObject ont t placs alatoirement prs de la voiture au dbut du jeu.

Cette instruction break nale nous fait sortir de la boucle while et passer au placement de lordure suivante. Si isOnBlock vaut true, nous poursuivons cependant avec la boucle while en choisissant un autre emplacement tester :
// Pas dintersection, utiliser cet emplacement if (!isOnBlock) { var newObject:TrashObject = new TrashObject(); newObject.x = x; newObject.y = y;

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

441

newObject.gotoAndStop(Math.oor(Math.random()*3)+1); gamesprite.addChild(newObject); trashObjects.push(newObject); break; } } } }

Lorsque vous testez une fonction de placement comme placeTrash, il est utile de la tester avec un nombre dobjets trs lev. Par exemple, jai test placeTrash en ayant attribu la valeur 10 000 numTrashObjects. Des tonnes dordures se trouvaient ainsi dverses sur la route, mais jai pu clairement voir quelles ne ltaient que sur la route et non dans les emplacements o je ne les voulais pas.

Entre clavier
Le jeu inclut un ensemble de fonctions dentre clavier analogues celles que nous avons utilises dans plusieurs jeux prcdents. Quatre valeurs boolennes sont dnies en fonction de lappui sur les quatre touches ches du clavier. Les fonctions reconnaissent mme la touche che du bas bien que cette version du jeu ne lutilise pas :
// Consigner les appuis sur les touches, dnir les proprits public function keyDownFunction(event:KeyboardEvent) { if (event.keyCode == 37) { arrowLeft = true; } else if (event.keyCode == 39) { arrowRight = true; } else if (event.keyCode == 38) { arrowUp = true; } else if (event.keyCode == 40) { arrowDown = true; } } public function keyUpFunction(event:KeyboardEvent) { if (event.keyCode == 37) { arrowLeft = false; } else if (event.keyCode == 39) {

442

ActionScript 3.0 pour les jeux

arrowRight = false; } else if (event.keyCode == 38) { arrowUp = false; } else if (event.keyCode == 40) { arrowDown = false; } }

La boucle du jeu
La fonction gameLoop grera le mouvement de la voiture. Il ny a en fait pas dautre objet qui se dplace dans le jeu. Le joueur dplace la voiture et tout le reste est statique dans le gamesprite. Il sagit dune animation temporelle ; nous allons donc calculer le temps coul depuis la dernire image et dplacer les lments en fonction de cette valeur :
public function gameLoop(event:Event) { // Calculer le temps coul if (lastTime == 0) lastTime = getTimer(); var timeDiff:int = getTimer()-lastTime; lastTime += timeDiff;

Nous vrierons les touches ches de gauche et de droite et appellerons rotateCar pour grer lorientation de la voiture. Nous passerons timeDiff et le sens du tournant :
// Rotation gauche ou droite if (arrowLeft) { rotateCar(timeDiff,"left"); } if (arrowRight) { rotateCar(timeDiff,"right"); }

Si la touche che du haut est enfonce, nous appelons moveCar en passant timeDiff. Ensuite, nous appelons centerMap pour nous assurer que le gamesprite est correctement positionn daprs le nouvel emplacement de la voiture. La fonction checkCollisions vrie si le joueur a collect des ordures ou sest approch dune benne :
// Dplacer la voiture if (arrowUp) { moveCar(timeDiff); centerMap(); checkCollisions(); }

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

443

Rappelez-vous que le temps est en fait le vritable score de ce jeu. Le joueur joue contre la montre. Nous devons donc mettre jour le temps coul an que le joueur puisse valuer sa russite :
// Mettre jour le temps et vrier si le jeu est termin showTime(); }

Examinons tout de suite la fonction centerMap, parce quelle est particulirement simple. Elle doit juste dnir lemplacement du gamesprite en lui attribuant les versions ngatives de lemplacement de la voiture lintrieur du gamesprite. Par exemple, si la voiture se trouve lemplacement 1000,600 dans gamesprite, le fait de positionner le gamesprite 1000,600 implique que la voiture se trouvera lemplacement 0,0 dans la scne. Nous ne souhaitons pas que la voiture soit prcisment 0,0, car cela correspond au coin suprieur gauche de la scne. Nous souhaitons la centrer dans la scne. Pour cela, nous ajoutons donc 275,200.

Si vous souhaitez modier la taille de la zone visible de la scne, par exemple pour passer 640 480, il est ncessaire de changer galement les valeurs cet endroit pour les faire correspondre au milieu de la scne. Une scne de 640 480 ncessiterait les valeurs 320 et 240 pour les ajustements x et y an de positionner la voiture au milieu de lcran.
public function centerMap() { gamesprite.x = -gamesprite.car.x + 275; gamesprite.y = -gamesprite.car.y + 200; }

Mouvement de la voiture
Le guidage de la voiture est assez peu raliste dans ce jeu : la voiture pivote autour de son centre de quelques degrs chaque image. En fait, la voiture peut mme tourner sans avancer. Essayez donc avec votre propre voiture Si vous jouez ce jeu, vous remarquerez cependant peine cette incongruit. La rotation est temporelle ; elle est donc le produit de timeDiff et de la constante turnSpeed. La voiture doit tourner la mme cadence quelle que soit la cadence dimages de lanimation :
public function rotateCar(timeDiff:Number, direction:String) { if (direction == "left") { gamesprite.car.rotation -= turnSpeed*timeDiff; } else if (direction == "right") { gamesprite.car.rotation += turnSpeed*timeDiff; } }

444

ActionScript 3.0 pour les jeux

Il est aussi assez simple de faire avancer la voiture ou, du moins, cela le serait sil ne fallait dtecter et grer les collisions avec les Blocks et les limites de la carte. Nous simplierons la dtection des collisions en utilisant des objets Rectangle simples et la fonction intersects. La premire chose dont nous ayons besoin est donc le Rectangle de la voiture. La voiture est dj de forme rectangulaire mais, comme elle pivote, il est problmatique dutiliser le
Rectangle exact du clip. Au lieu de cela, nous allons utiliser un Rectangle recr qui utilise le centre de la voiture et carSize. Cette zone carre offrira une approximation sufsante de la zone de la

voiture pour que le joueur ne sen rende pas compte.

Pour prserver lillusion que les collisions sont prcises, il est important de veiller ce que le graphisme de la voiture soit relativement carr, autrement dit aussi long que large. Une voiture bien plus longue que large ncessiterait que lon fasse dpendre la distance de collision de la rotation de la voiture par rapport aux bords avec lesquels elle pourrait entrer en collision. Ce cas de gure serait dj bien plus complexe.

// Faire avancer la voiture public function moveCar(timeDiff:Number) { // Calculer la zone actuelle de la voiture var carRect = new Rectangle(gamesprite.car.x-carSize/2, gamesprite.car.y-carSize/2, carSize, carSize);

Nous avons maintenant lemplacement actuel de la voiture dans carRect. Pour calculer le nouvel emplacement de la voiture, nous convertissons la rotation de la voiture en radians, fournissons ces nombres Math.cos et Math.sin, puis multiplions ces valeurs par la vitesse et timeDiff. Nous obtenons ainsi un mouvement temporel en utilisant la constante speed. newCarRect contient ensuite le nouvel emplacement de la voiture :
// Calculer la nouvelle zone de la voiture var newCarRect = carRect.clone(); var carAngle:Number = (gamesprite.car.rotation/360)*(2.0*Math.PI); var dx:Number = Math.cos(carAngle); var dy:Number = Math.sin(carAngle); newCarRect.x += dx*speed*timeDiff; newCarRect.y += dy*speed*timeDiff;

Nous avons galement besoin des emplacements x et y correspondant au nouveau Rectangle. Nous ajouterons les mmes valeurs x et y pour obtenir ce nouvel emplacement :
// Calculer le nouvel emplacement var newX:Number = gamesprite.car.x + dx*speed*timeDiff; var newY:Number = gamesprite.car.y + dy*speed*timeDiff;

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

445

Il est maintenant temps de parcourir en boucle les blocs et de voir si le nouvel emplacement entre en intersection avec lun dentre eux :
// Parcourir en boucle les blocs et vrier les collisions for(var i:int=0;i<blocks.length;i++) { // Rcuprer le rectangle du bloc, voir sil y a collision var blockRect:Rectangle = blocks[i].getRect(gamesprite); if (blockRect.intersects(newCarRect)) {

En cas de collision, nous examinons sparment les donnes horizontales et verticales de la collision. Si la voiture a pass le ct gauche dun Block, nous la ramenons au bord de ce Block. Le mme principe est utilis pour le ct droit du Block. Nous navons pas nous soucier dajuster le Rectangle, mais uniquement les valeurs de position newX et newY. Ce sont elles qui seront utilises pour dnir le nouvel emplacement de la voiture :
// Repousser horizontalement la voiture if (carRect.right <= blockRect.left) { newX += blockRect.left - newCarRect.right; } else if (carRect.left >= blockRect.right) { newX += blockRect.right - newCarRect.left; }

Voici maintenant le code qui gre les cts suprieur et infrieur du Block heurt :
// Repousser verticalement la voiture if (carRect.top >= blockRect.bottom) { newY += blockRect.bottom-newCarRect.top; } else if (carRect.bottom <= blockRect.top) { newY += blockRect.top - newCarRect.bottom; } } }

Une fois que tous les blocs ont t examins an de dterminer les ventuelles collisions, nous devons examiner les limites de la carte. Cest loppos des blocs, car nous souhaitons conserver la voiture lintrieur du Rectangle des limites et non en dehors. Nous examinerons donc chacun des quatre cts et repousserons les valeurs newX ou newY an dempcher la voiture de quitter les limites de la carte :
// Vrier les collisions avec les bords if ((newCarRect.right > mapRect.right) && (carRect.right <= mapRect.right)) { newX += mapRect.right - newCarRect.right;

446

ActionScript 3.0 pour les jeux

} if ((newCarRect.left < mapRect.left) && (carRect.left >= mapRect.left)) { newX += mapRect.left - newCarRect.left; }

if ((newCarRect.top < mapRect.top) && (carRect.top >= mapRect.top)) { newY += mapRect.top-newCarRect.top; } if ((newCarRect.bottom > mapRect.bottom) && (carRect.bottom <= mapRect.bottom)) { newY += mapRect.bottom - newCarRect.bottom; }

Maintenant que la voiture est scurise dans les limites de la carte et rejete hors de tout Block, nous pouvons dnir le nouvel emplacement de la voiture :
// Dnir le nouvel emplacement de la voiture gamesprite.car.x = newX; gamesprite.car.y = newY; }

Vrier les collisions avec les ordures et les bennes


La fonction checkCollisions doit rechercher deux types de collisions diffrents. Elle commence par examiner tous les trashObjects. Elle utilise la fonction Point.distance pour voir si lemplacement de la voiture et celui du TrashObject sont plus rapprochs que la constante pickupDistance :
public function checkCollisions() {

// Parcourir les bennes en boucle for(var i:int=trashObjects.length-1;i>=0;i--) {

// Voir si proximit sufsante pour rcuprer les ordures if (Point.distance(new Point(gamesprite.car.x,gamesprite.car.y), new Point(trashObjects[i].x, trashObjects[i].y)) < pickupDistance) {

Si un lment est sufsamment proche, nous comparons totalTrashObjects la constante maxCarry. Sil reste de la place, lordure est ramasse en positionnant lemplacement appropri dans onboard daprs currentFrame-1 du clip TrashObject. Ensuite, lordure est supprime de gamesprite et du tableau trashObjects. Nous devons mettre jour le score et lire GotOneSound :
// Voir sil y a de la place if (totalTrashObjects < maxCarry) { // Rcuprer lordure

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

447

onboard[trashObjects[i].currentFrame-1]++; gamesprite.removeChild(trashObjects[i]); trashObjects.splice(i,1); showScore(); playSound(theGotOneSound);

Lun des aspects de notre code susceptible de porter confusion tient la manire dont les types dordures sont rfrencs. Comme images dans le clip TrashObject, ils correspondent aux images 1, 2 et 3. En revanche, les tableaux sont indics 0, aussi, dans le tableau onboard, nous stockons les types dordures 1, 2 et 3 dans les emplacements de Tableau 0, 1 et 2. Les bennes seront nommes Trashcan1, Trashcan2 et Trashcan3 et correspondront aux numros des images, mais pas aux emplacements de tableau. Pour autant que vous gardiez ce point lesprit, vous ne devriez pas avoir de problme pour modier le code. Le fait que les tableaux soient indics 0 et que les images commencent 1 soulve des problmes constants pour les dveloppeurs ActionScript.

linverse, si le joueur entre en collision avec une ordure mais quil ny ait plus de place, nous mettons un autre son. Nous ne le faisons jouer que si llment ne correspond pas lastObject (le dernier objet). Cette vrication vite que le son ne se joue de manire rptitive le temps que le joueur scarte de lobjet. Le son nest ainsi jou quune seule fois par objet :
} else if (trashObjects[i] != lastObject) { playSound(theFullSound); lastObject = trashObjects[i]; } } }

Lensemble suivant de collisions examine les trois bennes. Nous utiliserons ici aussi Point.distance. Aprs quune collision aura t dtecte, nous supprimerons toutes les ordures de ce type du tableau onboard. Nous mettrons jour le score et mettrons un son signalant que les ordures sont dposes :
// Dposer les ordures si proches dune benne for(i=0;i<trashcans.length;i++) {

// Voir si la voiture est sufsamment proche if (Point.distance(new Point(gamesprite.car.x,gamesprite.car.y), new Point(trashcans[i].x, trashcans[i].y)) < dropDistance) { // Voir si le joueur a des ordures de ce type if (onboard[i] > 0) {

448

ActionScript 3.0 pour les jeux

// Dposer score += onboard[i]; onboard[i] = 0; showScore(); playSound(theDumpSound);

Si le score sest lev au point datteindre la valeur de la constante numTrashObjects, nous en concluons que la dernire ordure a t dpose et la partie est termine :
// Voir si toutes les ordures ont t dposes if (score >= numTrashObjects) { endGame(); break; } } } } }

Le chronomtre
La mise jour du chronomtre est assez simple et analogue ce que nous avons fait dans le jeu de Memory du Chapitre 3. Nous soustrayons le temps courant du temps de dpart pour obtenir le nombre de millisecondes coules depuis le dbut du jeu. Ensuite, nous utilisons la fonction utilitaire clockTime pour convertir cette valeur en un format dhorloge :
// Mettre jour le temps afch public function showTime() { var gameTime:int = getTimer()-gameStartTime; timeDisplay.text = clockTime(gameTime); }

La fonction clockTime calcule le nombre de secondes et de minutes, puis formate ces valeurs avec des zros den-tte si besoin :
// Conversion au format dhorloge public function clockTime(ms:int):String { var seconds:int = Math.oor(ms/1000); var minutes:int = Math.oor(seconds/60); seconds -= minutes*60; var timeString:String = minutes+":"+String(seconds+100).substr(1,2); return timeString; }

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

449

Les indicateurs de score


Dans ce jeu, lafchage du score est complexe et ne se limite pas afcher un simple nombre. Nous allons afcher les trois nombres stocks dans onboard. Dans le mme temps, nous additionnerons ces nombres pour obtenir la valeur totalTrashObjects, qui sera utilise autre part dans le jeu an de dterminer sil reste de la place dans la voiture :
// Mettre jour les lments texte du score public function showScore() {

// Dnir chaque nombre dordure, additionner le tout totalTrashObjects = 0; for(var i:int=0;i<3;i++) { this["onboard"+(i+1)].text = String(onboard[i]); totalTrashObjects += onboard[i]; }

Nous utiliserons galement totalTrashObjects ds maintenant pour colorer les trois nombres en rouge ou en blanc selon que la voiture est pleine ou non. Ce formatage offrira un indicateur naturel au joueur an de lui indiquer quil a atteint la capacit maximale de la voiture et doit se rendre une benne :
// Dnir la couleur des trois en fonction de la limite atteinte for(i=0;i<3;i++) { if (totalTrashObjects >= 10) { this[onboard+(i+1)].textColor = 0xFF0000; } else { this[onboard+(i+1)].textColor = 0xFFFFFF; } }

Ensuite, nous afchons la fois le score et le nombre dordures restant ramasser :


// Dnir le nombre restant et le score numLeft.text = String(trashObjects.length); scoreDisplay.text = String(score); }

Fin du jeu
Lorsque la partie est termine, nous supprimons les couteurs mais pas le gamesprite, car nous ne lavons pas cr. Celui-ci disparat simplement lorsque nous utilisons gotoAndStop pour nous rendre limage suivante.

450

ActionScript 3.0 pour les jeux

Comme le gamesprite ne se trouve que dans limage play, il nest pas afch dans limage gameover :
// Fin de la partie, supprimer les couteurs public function endGame() { blocks = null; trashObjects = null; trashcans = null; this.removeEventListener(Event.ENTER_FRAME,gameLoop); stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpFunction); gotoAndStop(gameover); }

Lorsque limage gameover a t atteinte, nous appelons showFinalMessage. Nous ne pouvons lappeler avant car le champ texte nalMessage ne se trouve que dans limage gameover et nest accessible quune fois que cette image est visible. Nous placerons le temps nal dans ce champ texte :
// Afcher le temps dans lcran nal public function showFinalMessage() { showTime(); var nalDisplay:String = ""; nalDisplay += "Time: "+timeDisplay.text+"\n"; nalMessage.text = nalDisplay; }

Il nous manque une dernire fonction : la fonction utilitaire playSound. Celle-ci sert simplement demplacement central pour tous les effets sons dclencher :
public function playSound(soundObject:Object) { var channel:SoundChannel = soundObject.play(); }

Lun des avantages lis au fait dutiliser une mme fonction partout o les effets son sont initis tient ce que vous pouvez rapidement et aisment crer des fonctions de sourdine et de volume. Si vous parpillez votre code de son dans tout le jeu, vous serez contraint de modier chacun de ces emplacements pour ajouter un systme de sourdine ou de rglage du volume.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

451

Modier le jeu
Ce jeu peut tre modi pour correspondre presque nimporte quel type de jeu dexploration ou de collecte dobjets. Vous pouvez modier les lments darrire-plan sans aucune programmation particulire. Les zones de collision (les Blocks) peuvent tre modis en dplaant et en ajoutant simplement de nouveaux clips Block. Vous pouvez mme faire durer le jeu plus longtemps en faisant apparatre de nouvelles ordures mesure que le temps passe. Vous pouvez par exemple congurer un Timer de faon quune nouvelle ordure soit ajoute toutes les cinq secondes. Le Timer pourrait procder de cette manire pendant quelques minutes avant de sinterrompre nalement. Vous pourriez galement ajouter des obstacles viter, comme des tches dhuile ou des mines. Une version militaire de ce jeu pourrait ainsi mettre en scne un vhicule militaire charg de rcuprer des soldats sur un champ de bataille tout en vitant les mines qui jonchent le sol.

Crer un jeu de course


En jouant notre jeu en vue arienne, vous serez peut-tre tent de vous amuser faire la course de voiture. Vous pourriez ainsi essayer de voir le temps quil vous faut pour faire le tour du campus. Si la prcdente version du jeu constitue un bon dpart, il convient tout de mme dajouter quelques lments supplmentaires pour crer un jeu de course. Codes sources http://ashgameu.com A3GPU12_RacingGame.zip

lments du jeu de course


Bien que nous crions un jeu de course "darcade" et non un vritable jeu de simulation, il convient de rendre la conduite sufsamment raliste pour donner limpression que lon pilote une vraie voiture. Il ne faut donc pas que la voiture se retrouve lance pleine vitesse ds la premire seconde o lon appuie sur la touche ni quelle sarrte ds linstant o on la relche. Nous allons donc ajouter des effets dacclration et de dclration ce jeu. La touche che du haut contribuera acclrer la vitesse de la voiture et la vitesse de la voiture sera utilise pour dterminer le mouvement chaque image.

452

ActionScript 3.0 pour les jeux

La distinction entre un jeu darcade et un jeu de simulation est plus importante ici que dans aucun des jeux que nous avons considrs prcdemment. Une vritable simulation doit tenir compte de la ralit physique des lments, comme la masse de la voiture, le couple moteur du vhicule et la friction entre les pneus et la route, sans mentionner encore les drapages. Ces points de dtail dpassent non seulement le cadre dun jeu simple cr sous Flash mais sont gnralement simplis ou ignors dans bien des jeux de console coteux. Il est important de ne pas laisser le ralisme empiter sur le plaisir du jeu ni de venir entraver le bon droulement du dveloppement du jeu en abandonnant sa ralisation faute de budget et de temps.

De la mme manire, si la touche che du bas est enfonce, une acclration inverse sopre. En position darrt, la touche che du bas produira donc une valeur de vitesse ngative et fera reculer la voiture. Lun des autres aspects du jeu de course tient ce que la voiture doit suivre un trac spcique. Le joueur ne doit pas pouvoir couper la piste en oprant un raccourci ni faire machine arrire pour retraverser la ligne darrive en quelques secondes. Pour surveiller le cheminement du joueur, nous utiliserons une technique simple dite des points de parcours. Le joueur doit alors se rapprocher dune srie demplacements autour de la piste et rcolter les points associs. Seul le joueur qui a atteint tous ces points est autoris passer la ligne darrive. Le plus intressant concernant les points de parcours tient ce que le joueur ne sait mme pas o ils se trouvent. Nous masquerons ces points et comptabiliserons le score du parcours sans en informer le joueur. Ce dernier ne saura en dnitive quune chose : quil doit courir vite et honntement. Une autre fonctionnalit de ce jeu contribuera le rendre plus palpitant : le compte rebours de dpart. Au lieu de faire commencer le jeu directement, nous bloquerons le joueur pendant 3 secondes en afchant 3, puis 2 puis 1 avant le top dpart.

Crer la piste
La dtection de collision dans le jeu en vue arienne utilisait des blocs rectangulaires. Il est assez facile de dtecter des collisions par rapport des bords horizontaux ou verticaux droits. Les pistes de courses prsentent en revanche des courbes, et la dtection des collisions avec des courbes, voire simplement avec de courts segments de murs en diagonale, se rvle bien plus difcile. Nous luderons donc ce problme dans ce jeu. La piste sera constitue de trois zones : la route, les bordures et tout le reste. Si la voiture se trouve sur la route, elle se dplace sans contrainte. Si elle se trouve sur la bordure de la route, elle continue de se dplacer, mais avec une enquiquinante dclration constante qui fera perdre du temps au joueur. Si la voiture se trouve en dehors de la route et de sa bordure, la dclration deviendra drastique et la voiture devra tourner et boitiller jusqu la route. La Figure 12.9 prsente ces trois zones. La route se trouve au milieu et apparat en gris dans Flash. Juste lextrieur se trouve sa bordure reprsente en marron dans Flash et dun ton de gris diffrent dans la gure.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

453

Figure 12.9
La piste est entoure dune bordure paisse.

La piste inclut galement des lments inactifs comme les arbres parpills autour.

Si les arbres ne sont pas rfrencs dans notre code et ne sont mme pas des clips mais simplement des symboles graphiques, ils jouent nanmoins un rle important. Sans ces lments incidents, il serait difcile pour le joueur de remarquer le mouvement de la voiture et dvaluer sa vitesse.

Le clip car est plac sur la piste la position o la voiture doit dmarrer, soit exactement sur la ligne darrive, qui correspond un clip spar. Les points qui apparaissent autour de la piste sont les points de parcours. Vous pouvez nen placer que quelques-uns autour de la piste, comme nous lavons fait, ou bien plus si cette piste inclut plus de tournants et de chicanes et que vous deviez viter que le joueur triche en coupant les virages. Tous ces lments se trouvent dans le clip Track, qui est le gamesprite auquel notre code fait rfrence.

454

ActionScript 3.0 pour les jeux

Effets sonores
Ce jeu utilisera plusieurs effets sonores. Trois diffrents sons de conduite seront lus en boucle pendant que le joueur fait avancer la voiture. Voici une liste des sons utiliss dans le jeu :

DriveSound. Un son en boucle mis pendant que la voiture acclre et se trouve sur la route. Analogue au son dun moteur de voiture de sport. SideSound.

Un son en boucle mis pendant que la voiture acclre et se trouve sur la bordure de la route. Analogue au son de pneus qui patinent dans la boue.

OffroadSound. Un son en boucle mis pendant que la voiture acclre et se trouve hors de la route

et de sa bordure. Analogue au son dune voiture qui roule sur des gravillons.
BrakestopSound. ReadysetSound. GoSound.

Un son de freins crissant utiliser lorsque la voiture passe la ligne darrive.

Un bip aigu mis durant le compte rebours au dbut du jeu.

Un bip grave mis lorsque le compte rebours atteint zro.

Le jeu pourrait facilement inclure dautres sons, comme un son dormant lorsque la voiture nacclre pas. BrakestopSound pourrait en outre tre remplac par une foule qui acclame le joueur la n de la course.

Constantes et variables
Certaines parties du code de ce jeu sont identiques celles du jeu de conduite en vue arienne. Nous nous occuperons ici avant tout du code qui change. Les constantes incluent maintenant des constantes dacclration et de dclration. Elles correspondent des nombres particulirement petits parce quelles seront multiplies par les millisecondes qui scoulent entre les images :
public class Racing extends MovieClip { // Constantes static const maxSpeed:Number = .3; static const accel:Number = .0002; static const decel:Number = .0003; static const turnSpeed:Number = .18;

Parmi les variables du jeu gure gameMode, qui indiquera si la course a dmarr. Nous aurons galement un tableau waypoints pour contenir les emplacements Point des clips Waypoint. La variable speed contiendra la cadence actuelle laquelle la piste se dplace, qui changera mesure que la voiture acclre et dclre :
// Variables de jeu private var arrowLeft, arrowRight, arrowUp, arrowDown:Boolean; private var lastTime:int;

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

455

private var gameStartTime:int; private var speed:Number; private var gameMode:String; private var waypoints:Array; private var currentSound:Object;

Voici les dnitions initiales pour tous les nouveaux sons. Chacun se trouve dans la bibliothque et a t congur de manire tre export pour ActionScript :
// Sons static const theBrakestopSound:BrakestopSound = new BrakestopSound(); static const theDriveSound:DriveSound = new DriveSound(); static const theGoSound:GoSound = new GoSound(); static const theOffroadSound:OffroadSound = new OffroadSound(); static const theReadysetSound:ReadysetSound = new ReadysetSound(); static const theSideSound:SideSound = new SideSound(); private var driveSoundChannel:SoundChannel;

Dmarrer le jeu
Lorsque ce jeu dmarre, il na pas besoin de rechercher des Blocks. Il doit au lieu de cela trouver les points de parcours (Waypoints). La fonction ndWaypoints sen charge. Nous y viendrons juste aprs :
public function startRacing() { // Obtenir la liste des points de parcours ndWaypoints();

Les couteurs requis sont les mmes que pour le jeu de conduite en vue arienne, mais parmi les variables qui doivent tre dnies au dbut du jeu gurent maintenant gameMode et speed. Nous dnirons galement le champ texte timeDisplay en lui attribuant une chane vide parce quil sera vide pendant les 3 premires secondes du jeu, jusqu ce que la course dmarre :
// Ajouter les couteurs this.addEventListener(Event.ENTER_FRAME,gameLoop); stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction); // Congurer les variables du jeu speed = 0; gameMode = "wait"; timeDisplay.text = ""; gameStartTime = getTimer()+3000; centerMap(); }

456

ActionScript 3.0 pour les jeux

Vous remarquerez que gameStartTime se voit ajouter trois secondes. En effet, le jeu dmarre avec un compte rebours de 3 secondes. La voiture ne sera pas autorise se dplacer avant que ces 3 secondes se soient coules et que gameTimer() ait rattrap gameStartTime. La fonction ndWaypoints est trs proche de la fonction ndBlocks du prcdent jeu. Cette fois, nous ne souhaitons cependant connatre que lemplacement du Point de chaque point de parcours. Une fois que nous avons enregistr cette information, le clip nimporte plus :
// Examiner tous les enfants de gamesprite et mmoriser les points de parcours public function ndWaypoints() { waypoints = new Array(); for(var i=0;i<gamesprite.numChildren;i++) { var mc = gamesprite.getChildAt(i); if (mc is Waypoint) { // Ajouter au tableau et rendre invisible waypoints.push(new Point(mc.x, mc.y)); mc.visible = false; } } }

La boucle principale du jeu


Nous passerons les fonctions dcouteur clavier parce quelles sont identiques celles du jeu prcdent. La fonction gameLoop est en revanche un peu diffrente. Nous y inclurons directement un grand nombre des mcanismes du jeu au lieu de les dlguer dautres fonctions. Aprs avoir dtermin le temps qui sest coul depuis la dernire excution de gameLoop, nous examinerons les touches ches de gauche et de droite et tournerons la voiture :
public function gameLoop(event:Event) { // Calculer le temps coul if (lastTime == 0) lastTime = getTimer(); var timeDiff:int = getTimer()-lastTime; lastTime += timeDiff; // Ne dplacer la voiture quen mode Course if (gameMode == "race") { // Pivoter gauche ou droite if (arrowLeft) { gamesprite.car.rotation -= (speed+.1)*turnSpeed*timeDiff; } if (arrowRight) { gamesprite.car.rotation += (speed+.1)*turnSpeed*timeDiff; }

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

457

Trois facteurs affectent la valeur de rotation : la vitesse (speed), la constante turnSpeed (braquage) et timeDiff. speed est en outre augmente de .1. Ce rglage permet au joueur de tourner la voiture lgrement lorsquil se trouve larrt et lgrement plus lorsquil se dplace lentement. Si cela ne correspond pas prcisment une simulation de conduite, cela rend nanmoins le jeu moins frustrant.

En liant la vitesse au braquage, nous permettons la voiture de tourner plus vite lorsquelle se dplace plus vite. Cela rend la conduite plus raliste et permet de mieux grer les courbes du circuit.

En outre, vous noterez que la rotation et le mouvement qui suit ne se produisent que si gameMode vaut "race". Cela ne se produit quune fois le compte rebours de 3 secondes coul. Le mouvement de la voiture dpend de sa vitesse. La vitesse dpend de lacclration, qui se produit lorsque le joueur appuie sur les touches ches du haut et du bas. Le code qui suit se charge de ces changements et sassure que la vitesse ne semballe pas en la restreignant maxSpeed :
// Faire acclrer la voiture if (arrowUp) { speed += accel*timeDiff; if (speed > maxSpeed) speed = maxSpeed; } else if (arrowDown) { speed -= accel*timeDiff; if (speed < -maxSpeed) speed = -maxSpeed;

Si ni la touche che du haut ni celle du bas ne sont enfonces, la voiture doit sarrter progressivement. Nous utiliserons la constante decel pour rduire la vitesse de la voiture :
// Aucune touche enfonce, ralentir } else if (speed > 0) { speed -= decel*timeDiff; if (speed < 0) speed = 0; } else if (speed < 0) { speed += decel*timeDiff; if (speed > 0) speed = 0; }

Vous pourriez aisment ajouter des freins la voiture. Pour cela, incluez la barre despace en plus des quatre touches ches lorsque vous surveillez le clavier. Lors de lappui sur la barre despace, vous pouvez provoquer un ralentissement plus important que la constante decel.

458

ActionScript 3.0 pour les jeux

Nous navons vrier le mouvement de la voiture que sil y a une valeur speed. Si la voiture est compltement larrt, nous pouvons ignorer ce qui suit. Si la voiture se dplace, nous devons en revanche la repositionner, vrier si elle se trouve ou non sur la route, recentrer la carte par rapport la voiture, vrier si de nouveaux points de parcours ont t rencontrs et vrier si la voiture a franchi la ligne darrive :
// En cas de dplacement, bouger la voiture et vrier ltat if (speed != 0) { moveCar(timeDiff); centerMap(); checkWaypoints(); checkFinishLine(); } }

Que la voiture bouge ou non, le chronomtre doit pour sa part tre mis jour :
// Mettre jour le temps et vrier si la course est termine showTime(); }

Mouvement de la voiture
La voiture se dplace en fonction de rotation, speed et timeDiff. La rotation est convertie en radians et la valeur, fournie Math.cos et Math.sin. La position originale de la voiture est stocke dans carPos et le changement de position, dans dx et dy :
public function moveCar(timeDiff:Number) { // Obtenir la position actuelle var carPos:Point = new Point(gamesprite.car.x, gamesprite.car.y); // Calculer le changement var carAngle:Number = gamesprite.car.rotation; var carAngleRadians:Number = (carAngle/360)*(2.0*Math.PI); var carMove:Number = speed*timeDiff; var dx:Number = sMath.cos(carAngleRadians)*carMove; var dy:Number = Math.sin(carAngleRadians)*carMove;

Pendant que nous dterminons o doit se trouver le nouvel emplacement de la voiture, nous devons aussi dterminer le son qui doit tre jou. Si la voiture se dplace et se trouve sur la route, il faut lire le son theDriveSound.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

459

Nous supposerons que cest le cas ce stade et ajusterons la valeur de newSound mesure que nous examinerons dautres aspects de ltat du jeu :
// Nous supposons que nous allons utiliser le son de conduite var newSound:Object = theDriveSound;

Le premier test raliser ici consiste voir si la voiture se trouve actuellement sur la route. Nous utiliserons hitTestPoint pour cela. Le troisime paramtre dans hitTestPoint nous permet de tester un point par rapport la forme spcique de la route. Nous devons ajouter gamesprite.x et gamesprite.y la position de la voiture, car hitTestPoint fonctionne au niveau de la scne, avec les positions de la scne et non au niveau du gamesprite avec les positions du gamesprite :
// Voir si la voiture nest PAS sur la route if (!gamesprite.road.hitTestPoint(carPos.x+dx+gamesprite.x, carPos.y+dy+gamesprite.y, true)) {

Notez la prsence du point dexclamation crucial dans la ligne de code prcdente. Ce ! signie "non" et inverse la valeur boolenne qui le suit. Au lieu de vrier si lemplacement de la voiture se trouve lintrieur de la route, nous vrions ainsi sil ne se trouve pas lintrieur de la route (en dautres termes, sil se trouve en dehors). Maintenant que nous savons que la voiture ne se trouve pas sur la route, le test suivant doit nous indiquer si la voiture se trouve tout le moins sur la bordure de la route :
// Voir si la voiture est sur la bordure if (gamesprite.side.hitTestPoint(carPos.x+dx+gamesprite.x, carPos.y+dy+gamesprite.y, true)) {

Si la voiture se trouve sur la bordure de la route, nous utilisons le test unitaire theSideSound au lieu de theDriveSound. Nous rduisons en outre la vitesse de la voiture dun faible pourcentage :
// Utiliser un son spcique, rduire la vitesse newSound = theSideSound; speed *= 1.0-.001*timeDiff;

Si la voiture ne se trouve ni sur la route ni sur sa bordure, nous utilisons theOffroadSound en rduisant la vitesse dune quantit plus importante :
} else { // Utiliser son spcique, rduire la vitesse newSound = theOffroadSound; speed *= 1.0-.005*timeDiff; } }

460

ActionScript 3.0 pour les jeux

Nous pouvons maintenant dnir lemplacement de la voiture :


// Dnir la nouvelle position de la voiture gamesprite.car.x = carPos.x+dx; gamesprite.car.y = carPos.y+dy;

Il ne nous reste plus qu dterminer le son lire. newSound vaut theDriveSound, theSideSound ou theOffroadSound. Si le joueur nest pas en train dacclrer cet instant, nous ne souhaitons toutefois pas mettre de son :
// Si le joueur nacclre pas, ignorer le son if (!arrowUp && !arrowDown) { newSound = null; }

La variable newSound contient le son appropri. Si ce son est dj lu et boucle, nous ne souhaitons rien faire hormis le laisser continuer. Nous ne souhaitons ragir que si un nouveau son doit venir remplacer le son actuel. Si cest le cas, nous mettons une commande driveSoundChannel.stop() an dannuler lancien son, puis une nouvelle commande play avec un grand nombre de boucles, pour commencer :
// Si nouveau son, permuter if (newSound != currentSound) { if (driveSoundChannel != null) { driveSoundChannel.stop(); } currentSound = newSound; if (currentSound != null) { driveSoundChannel = currentSound.play(0,9999); } } }

En plus de la fonction moveCar, nous avons besoin de la fonction centerMap, qui est identique celle du jeu de conduite en vue arienne de la premire partie du chapitre et conserve la voiture au centre de lcran.

Vrier ltat davancement


Pour vrier o en est le joueur sur le circuit, nous allons examiner chacun des Waypoints et voir si la voiture en est proche. Pour cela, nous utiliserons la fonction Point.distance. Le tableau waypoints contient dj des objets Point, mais nous devons en construire un la vole avec lemplacement de la voiture pour effectuer la comparaison.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

461

Jai choisi une distance de 150 pour considrer quun point de parcours est atteint. Cest sufsant pour que la voiture ne puisse manquer un point de parcours au milieu de la route mme si elle le franchit en passant ct. Il est essentiel que cette distance soit sufsamment grande pour que le joueur ne puisse passer ct dun point de parcours sans quil soit comptabilis. Sans cela, il ne pourrait nir la course et ne comprendrait pas pourquoi :
// Vrier si la voiture est assez proche dun point de parcours public function checkWaypoints() { for(var i:int=waypoints.length-1;i>=0;i--) { if (Point.distance(waypoints[i], new Point(gamesprite.car.x, gamesprite.car.y)) < 150) { waypoints.splice(i,1); } } }

Lorsquun Waypoint est rencontr, il est supprim du tableau. Lorsque le tableau est vide, nous savons que tous les points de parcours ont t franchis. Cest exactement ce que vrie en premier checkFinishLine. Si le tableau waypoints contient encore des lments, le joueur nest pas prt franchir la ligne darrive :
// Voir si la ligne darrive est franchie public function checkFinishLine() { // Uniquement si tous les points de parcours ont t atteints if (waypoints.length > 0) return;

linverse, si le joueur a atteint tous les points de parcours, nous pouvons supposer quil approche de la ligne darrive. Nous vrions la valeur y de la voiture pour voir sil a pass la valeur y du clip nish. Si cest le cas, le joueur a termin la course :
if (gamesprite.car.y < gamesprite.nish.y) { endGame(); } }

Si vous changez la carte et repositionnez la ligne darrive, soyez attentif lorsque vous vriez si la voiture a pass nish. Par exemple, si la voiture approche de nish en venant de la gauche, vous devrez vrier cette fois la valeur x de la voiture pour voir si elle est suprieure celle de nish.

462

ActionScript 3.0 pour les jeux

Compte rebours et chronomtre


Si le chronomtre de ce jeu est trs proche de celui du jeu de conduite en vue arienne, il est accompagn dun autre chronomtre qui, pour sa part, effectue un compte rebours avant le dpart de la course. Si gameMode vaut "wait", la course na pas encore dmarr. Nous testons gameTime pour voir si sa valeur est ngative. Si cest le cas, gameTimer() na pas encore rattrap le dlai de 3 secondes que nous avons cr lorsque nous avons dni gameStartTime en lui attribuant la valeur getTimer()+3000. Au lieu dafcher le temps dans le champ timeDisplay, nous lafcherons dans le champ countdown. Nous lafcherons cependant sous forme dun nombre de secondes arrondi : 3, puis 2, puis 1. Nous lirons aussi le son theReadysetSound chaque fois que ce nombre change. La Figure 12.10 prsente ce chronomtre de compte rebours au dbut du jeu.
// Mettre jour le temps afch public function showTime() { var gameTime:int = getTimer()-gameStartTime; // En mode Attente, afcher le chronomtre du compte rebours if (gameMode == "wait") { if (gameTime < 0) { // Afcher 3, 2, 1 var newNum:String = String(Math.abs(Math.oor(gameTime/1000))); if (countdown.text != newNum) { countdown.text = newNum; playSound(theReadysetSound); }

Figure 12.10
Un nombre au centre de lcran indique le temps restant avant le dbut de la course.

Chapitre 12

Chapitre 12 Jeux de mondes : jeux de conduite et dexploration

463

Lorsque gameTime atteint 0, nous changeons gameMode et supprimons le nombre de countdown. Nous lisons galement theGoSound :
} else { // Compte rebours termin, passer en mode Course gameMode = "race"; countdown.text = ""; playSound(theGoSound); }

Pour le reste de la course, nous afcherons le temps dans le champ timeDisplay. La fonction clockTime est exactement la mme que celle utilise prcdemment dans ce chapitre :
// Afcher le temps } else { timeDisplay.text = clockTime(gameTime); } }

Fin de partie
Lorsque la partie se termine, le nettoyage faire est plus important que dhabitude. Le driveSoundChannel doit arrter de lire les sons. Nous dclencherons cependant aussi le son theBrakeSound ce point. Ensuite, nous supprimons tous les couteurs et passons limage gameover :
// Partie termine, supprimer les couteurs public function endGame() { driveSoundChannel.stop(); playSound(theBrakestopSound); this.removeEventListener(Event.ENTER_FRAME,gameLoop); stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction); stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpFunction); gotoAndStop(gameover); }

Une fois que nous nous trouvons limage gameover, nous afchons le score nal exactement comme avec le jeu de conduite en vue arienne. Dans le cas prsent, nous souhaitons cependant conserver le gamesprite visible. Dans le scnario principal, il gure la fois dans les images play et gameover de sorte quil reste prsent lorsque nous passons limage gameover. La fonction showFinalMessage est identique celle du jeu prcdent. Inutile de revenir ici dessus. Le scnario principal inclut galement le mme code dans limage gameover.

464

ActionScript 3.0 pour les jeux

Modier le jeu
Le circuit de ce jeu est assez simple : il sagit dune piste de vitesse tout ce quil y a de plus classique. Vous pouvez cependant en crer de bien plus complexes avec des tournants et des chicanes.

Lastuce pour crer le clip de la route et celui de la bordure consiste ne se soucier dabord que du clip road (celui de la route). Une fois ce clip termin, crez-en une copie et appelez cette copie side. Ensuite, slectionnez la forme lintrieur du clip et choisissez Modication > Forme > tendre le remplissage. tendez la piste denviron 50 pixels. Vous crerez ainsi une copie de la route plus paisse qui correspond exactement la route dorigine.

Vous pouvez galement joncher la route dobstacles. Des tches dhuile pourraient ainsi ralentir la voiture. Elles pourraient tre gres de la mme manire que les points de parcours, mais en dnissant une distance trs rduite pour considrer quelles aient t touches. La vitesse de la voiture pourrait alors tre affecte. Il est aussi courant dans ce type de jeu de disposer une portion de terrain rugueux au milieu de la route. Vous pourriez le faire en perant un trou dans la forme du clip road et en y laissant transparatre le clip side. Parmi les autres amliorations possibles, lune sera de placer les points de parcours dans un ordre spcique. Pour linstant, le jeu se termine lorsque le joueur atteint tous les points de parcours et franchit la ligne darrive. Lordre dans lequel ces points sont atteints nimporte pas. Techniquement, il serait donc parfaitement possible pour le joueur de rouler en sens inverse sur le circuit, de toucher tous les points de parcours et de gagner ds quil atteint le dernier point de parcours puisquil se trouve dj au-del de la ligne darrive. Le joueur nobtiendrait pas pour autant un meilleur temps, car il faut en perdre beaucoup pour effectuer un demi-tour. Vous pourriez ordonner les points de parcours en leur donnant des noms comme "waypoint0",
"waypoint1", et ainsi de suite. Vous pourriez ds lors examiner les points de parcours nominativement

au lieu de le faire en fonction de leur type, en vriant si la voiture se trouve auprs de lun dentre eux et sans les considrer tous la fois. Ce jeu de course indique le chemin que nous avons nous-mmes parcouru. Nous avons commenc au Chapitre 3 par un jeu de Memory, une sorte de jeu de puzzle qui utilisait les clics de souris en entre et testait la mmoire du joueur. Nous nous retrouvons maintenant avec un vritable jeu daction qui utilise le clavier et teste la dextrit du joueur. Voil qui illustre bien la grande varit des jeux qui peuvent tre crs avec Flash. Si vous tudiez chacun des chapitres de ce livre, vous devez donc tre capable de crer un grand nombre de jeux. Ltape suivante est entre vos mains. Modiez les jeux que vous avez crs dans ce livre ou commencez crer vos propres jeux en ralisant vos propres conceptions. Dans un cas comme dans lautre, visitez http://ashgameu.com pour en apprendre plus.

Index
A
AC_RunActiveContent.js 39 Actions, panneau 11 ActionScript boucles 220 chanes 324 classe de base 96 document 14 fonctions Math 249 historique 8 indexation 220 nombres alatoires 84 notions lmentaires 28 oprations numriques 29 syntaxe 28 tableaux 134 addChild 13, 47, 54, 242 addEnemies 408 addEventListener 51, 61, 62, 74, 104, 455 Airplane 178 Air Raid 176 arrire-plan 194 Air Raid II 255 Alatoire mlange de cartes 101 nombres 84 positionnement 28, 439 questions 384 squence 152 alpha, proprit 53, 62, 138, 278, 294, 297 altKey 63 Angle calculer 252 direction 199 rotation 47 Animation cartes Memory 124 crer 66 explosion de points 297 physiques 70 publier 36 temporelle 69, 170 arctangent 252 Array 85 Arrire-plan 94, 400 Air Raid 194 cartes 109 champ texte 332 Simon 152 sprite 17 askQuestion 371 Astrodes crer 279 taille 280 atan2 252 Atari 262 attribute 360 Avions 176 Air Raid 170 crer 189 mouvement 176 supprimer 179 Bibliothque, panneau 19, 298 Bitmap Voir Images Bote de dialogue 400, 424 Proprits audio 82 Proprits de liaison 47 Proprits du symbole 94 Rechercher et remplacer 22 Boucles 31 ActionScript 220 do while 31, 240 for 26, 31, 101, 110, 353 for in 192 imbriques 96, 286 variables incrmentales 27 while 31, 151, 306, 439 Bouton 13 ajouter un couteur 51 buttonMode 145 crer 49 jouer 114 rejouer 20, 115 souris 74, 345 survol 81 break 192, 227 Breakout 195 buttonMode 49, 130, 145, 162 bytesLoaded 83 bytesTotal 83

B
beginFill 59, 68 Bibliothque 19 clips 46 crer un clip vide 114 de classes 15 documentation 17 importer des sons 128 sons 83

C
Cadence d'images 67 augmenter 66 rotation 250 tester 43 calculateProgress 161

466

ActionScript 3.0 pour les jeux

Cartes 428 arrire-plan 109 centerMap 443 comparer 108 mlanger 85, 101 Memory 92 retourner 94 Casse-brique 195 Casual games 292 centerMap 443 Chane 324 convertir en tableaux 328 fonctions 328, 329 indexOf 325 jeu du pendu 337 search 326 substr 325 toLowerCase 325 Champ texte 13, 54, 324 arrire-plan 332 attribuer un couteur 57 proprit selectable 55 tabulation 382 charCode 62 Chargement donnes 78, 368 crans 83 erreurs 362 image 212, 220, 234 loadingDone 214 loadProgress 83 movieBytesLoaded 84 sons 144 URLRequest 214 XML 358 checkCollisions 286, 442, 446 checkForHits 190 child 360 Chronomtre 119, 376, 433, 448, 462 Circuit 451 Classe 14 dnition 16, 141 de base 96 externe 11 PointBurst 292, 420 spcier le chemin 299 unique 24, 197

Clavier 62, 275, 441 couteurs 104 gestion de l'entre 191 keyCode 183, 275 touches de modication 63 touches ches 181, 250 Cls 398 CLICK 230 clickDialogButton 424 clickDone 161 Clips 13, 46, 176 attribuer un couteur 49 buttonMode 130 crer 114 proprit currentFrame 67 proprit visible 264 supprimer 179 clockTime 121 Code commentaires 22 conseils 22 dboguer 32 chiers source 4 chier AS 114 tester 27 vrier la syntaxe 22 XML 361 Collision 190, 204, 418 astrodes 277, 286 mur 207, 415 objets 421 objets carrs 444 sol 416 voiture 442, 446 Commande addChild 13 addEventListener 51 break 192, 227 continue 306 copyPixels 215 endFill 53 gotoAndStop 115 import 141 moveCursor 81 pop 149

push 101 return 149 setChildIndex 61, 80 shift 149 start 68 switch 227 trace 9 Commentaires 22 bonnes pratiques 25 Comparaison 325 cartes 108 chevauchement 75 oprateur 30 Compilation 23 COMPLETE 214 Compte rebours 462 concat 147 Conseils de code 22 Console de dbogage, panneau 35 const, mot-cl 100 Constantes bonnes pratiques 99 environnementales 198 extraire du code 99 continue 306 copyPixels 215 Correspondances 312 Cos, fonction 246 Courier 338 Course points de parcours 460 createHero 406 createShipIcons 270 Cration animation 66 avions 189 boutons 49 clips vides 114 clip du jeu 112 document ActionScript 14 chier d'animation 94 tableau 85 variables 28 CSS 329 ctrlKey 63

Index

467

currentCount 68 currentFrame 67 currentLoc 221 currentTarget 105 Curseur invisible 80 personnalis 80 survol 49 curveTo 52

E
couteurs 70, 410 attribuer 49 bouton 51, 60 champs texte 57 clavier 104 crans chargement 83 n de partie 111 introduction 113 Effets 124 else 30 EMBED 77 endFill 53 Ennemis 396 addEnemies 408 mort 419 ENTER_FRAME 61, 66, 171, 189, 285, 294, 438 Entre utilisateur clavier 62, 275, 441 grer 191 Match Three 307 souris 61, 226, 349 texte 64 touches ches 250 Erreurs capturer 27 chargement 362 compilation 23 vnement addEventListener 74 CLICK 230 COMPLETE 214 currentTarget 105 couteurs 104 ENTER_FRAME 61, 66, 171, 189, 234, 285, 294, 438 EVENT_FRAME 410 KEY_DOWN 62 KEY_UP 62, 65 localX 75 MOUSE_DOWN 74, 234, 345 MOUSE_OVER 345 objets Timer 68 TIMER_COMPLETE 127, 229

EVENT_FRAME 410 examineLevel 409 Explosion de points 292

F
Fentres Document 18 Document:ActionScript 21 Document ActionScript 21 Nouveau document 9 Sortie 49 Fichier animation 94 de code 114 externes 14 multimdias 93 nouveau 94 QuickTime 37 son 144 source 4 SWF 19, 88 texte 78 XML 361 ndAndRemoveMatches 313 ndBlocks 439 ndGridPoint 350 reBullet 192 Flash aide 141 paramtres de publication 37 ash.display 15 ash.text 15 ashvars 78 oor 85 Fonction 16, 31 addChild 54, 242 addEnemies 408 addEventListener 104 Airplane 178 arctangent 252 atan2 252 calculateProgress 161 centerMap 443 checkCollisions 286, 442, 446

D
dataXML 365 Dbogage 32 check-list 40 dbogueur 34 dnir un point d'arrt 34 dsactiver les raccourcis clavier 43 options 22 pas pas 35 petits blocs 27 typage 42 types de bogues 32 defaultTextFormat 56, 332 Dnition alpha 294 classe 16, 434 defaultTextFormat 332 couteur 49 Dtection de collision 190, 204 do 31, 240 Donkey Kong 394 Donnes charger 78, 368 objets 136 stocker 358 structure 134 typage 225 XML 358 drawCircle 59, 68 drawEllipse 53 drawOutline 353 drawRect 52, 59 drawRoundRect 53 dx 173

468

ActionScript 3.0 pour les jeux

Fonction (Suite) checkForHits 190 clickDialogButton 424 clickDone 161 clockTime 121 concat 147 Cos 246 createHero 406 curveTo 52 de tableau 135, 136 drawEllipse 53 drawOutline 353 drawRect 52 drawRoundRect 53 examineLevel 409 ndAndRemoveMatches 313 ndBlocks 439 ndGridPoint 350 reBullet 192 oor 85 getChildAt 352 getLocal 79 getTimer 69, 86, 119, 172 hitTestObject 75, 418 hitTestPoint 75 indexOf 325 intersects 208 keyDownFunction 191 keyUpFunction 191 loadBitmap 220 loadingDone 214 loadProgress 83 lookForMatches 306, 314 makeBricks 200 makeSwap 308 moveBall 203 moveCar 250, 444 movePieceInDirection 228 movePlane 178 MovieClip 115 MovingCar 249 navigateToURL 89 newRockWave 282 noms descriptifs 26 placeLetters 346 placeTrash 439

playSound 129 PointBurst 295 random 84, 102 removeBullet 193 removeChild 166 removePlane 179, 192 search 326 showGameScore 192 shufe 236 shufePuzzlePieces 224 Sin 246 splice 209 startGameLevel 405 startPaddleBall 200 startTopDownDrive 437 startWordSearch 343 substr 325 toLowerCase 325 validMove 224 for 31, 96, 101, 110, 353 Format defaultTextFormat 332 GIF 212 JPEG 218 JPG 93, 212 PNG 212 publication 37 QuickTime 37 TextFormat 55, 143, 365 XML 78, 361 Formes 52 fromCharCode 62 function 16

Grille Match Three 305 Memory 96 puzzle 224

H
Hangman 338 Hello World 9 Hros 396 createHero 406 hitTestObject 75, 418 hitTestPoint 75 homeLoc 221 HTML 39 CSS 329 EMBED 77 OBJECT 77 passer des valeurs 77 htmlText 57

I
Icnes 271 if 30, 63, 108, 125, 186, 204, 207 Image chargement 220, 234 cl 11 dcouper 214, 221, 234 quiz 385 import 104, 141 Importation 15, 104 clip 46 protger contre 38 sons 128 trouver les classes requises 141 indexOf 325 Indices 378 Instruction conditionnelle 30 for 96 import 104 stop 83 intersects 208 isBuffering 83

G
gameMode 281 gameScore 268 getChildAt 352 getLocal 79 getTimer 69, 86, 119, 172 GIF 212 gotoAndStop 67, 115, 275 graphics 52 Gravit 70, 403 limiter la vitesse 413

Index

469

J
Jeu Air Raid 176 Air Raid II 255 cartes 428 casse-brique 195 casual games 292 conduite en vue arienne 428 course 451 dduction 151 de plate-forme 394 de simulation 452 Mastermind 152 Memory 92 navals 176 Newton's Nightmare 301 pendu 336 protger contre le vol 88 quiz 358 Simon 138 Space Rocks 262 supprimer les lments 166 Joueur interactions 61 mort 419 munitions 194 Joyaux 398 JPEG 218 JPG 93, 212

loadBitmap 220 Loader 212 LoaderInfo 78 loadingDone 214 loadProgress 83 localX 75 lookForMatches 306, 314

M
makeBricks 200 makeSwap 308 Mastermind 152 Match Three 292 correspondances 312 fonctionnalits 302 interaction du joueur 307 Math 246, 249 Mmoire librer 42, 179, 297 ramasse-miettes 166 Memory 92 Minuteurs Voir Timer Mots-cls const 100 function 16 private 32, 100 public 16 return 209 static 100 this 52 var 28 void 96 Mots mls 340 MOUSE_DOWN 74, 234, 345 MOUSE_OVER 345 MOUSE_UP 74 mouseEnabled 81 mouseX 61, 254 Mouvement alatoire 224 astrodes 282 avions volants 176 freinage 457 Match Three 310 missiles 284

personnages 412 puzzle 237 puzzle coulissant 219 raquette 203 rebonds 204 rotation 246, 266 sprites 72 touches ches 181, 250 voiture 443, 458 moveBall 203 moveCar 250, 444 moveCursor 81 movePieceInDirection 228 movePlane 178 movieBytesLoaded 84 movieBytesTotal 84 MovieClip 115 MovingCar 249 MP3 82, 130, 144 multiline 65 Munitions 194 Murs 395, 415

N
navigateToURL 89 newRockWave 282 Newton's Nightmare 301 Nintendo 394 Nombre alatoire 84, 151 d'images 11 octets 84 oprations 29 types 97 numChildren 61, 110

K
KEY_DOWN 62 KEY_UP 62, 65 keyCode 183, 275 keyDownFunction 191 keyUpFunction 191

O
OBJECT, balise 77 Object, type 136 Objet d'afchage 17 graphics 52 LoaderInfo 78

L
lineStyle 59 Liste beingDragged 238 d'afchage 17, 42, 47, 61 puzzleObjects 226

470

ActionScript 3.0 pour les jeux

Objet (Suite) Point 204 Rectangle 204 SimpleButton 51 TextField 13, 54 TextFormat 55 Timer 68 URLLoader 78 URLRequest 78 xmlLoaded 79 Opacit Voir Transparence Oprateur ajout 118 comparaison 30, 325 is 402 numrique 29

P
Panneau Actions 11 Bibliothque 19, 298 Console de dbogage 35 Proprits 16, 20 Sortie 9 Paquetages accolades 150 dclaration 96 importer 15 Paramtres de scurit 41 publication 36 Pendu, jeu du 336 Performances compression des sons 130 dnir le type 225 librer la mmoire 179 Permutation 310 placeLetters 346 placeTrash 439 play 82 playSound 129 PNG 212 Point d'arrt 34 de parcours 460

explosion 292 objet 204 PointBurst 397, 420 Polices Courier 338 symboles 298 pop 149 private 32, 100 Profondeur 61 Programmation constantes 99 de haut en bas 313 Proprits 16 alpha 53, 62, 138, 278, 294, 297 audio 82 buttonMode 49, 130, 145, 162 bytesLoaded 83 bytesTotal 83 currentCount 68 currentFrame 67 currentLoc 221 currentTarget 105 dnition anticipe 42 des symboles 94 homeLoc 221 htmlText 57 isBuffering 83 mouseEnabled 81 mouseX 61, 254 multiline 65 numChildren 61, 110 rotation 246, 256 scaleX 126, 417 selectable 55, 143 stageWidth 87 styleSheet 57 visible 264 public, mot-cl 16 Publication 36 chemin de classe 299 formats 37 paramtres de compression 130 paramtres Flash 37 paramtres HTML 39 push 101

Puzzle classique 231 connexion des pices 241 coulissant 217 mlange des pices 223, 236

Q
QuickTime 37 Quiz 358 Deluxe 375 images 385 indices 378 temps limite 376

R
Raccourcis clavier 43 Ramasse-miettes 166 random 84, 102 Rechercher 22 Rectangle 204 removeBullet 193 removeChild 166 removePlane 179, 192 return 149, 209 rocks 280 Rotation angle 47, 246 cadence d'images 250 dcomposer la tche 25 objets ronds 284 vitesse 266, 457 rotation 47, 246, 256

S
scaleX 48, 125, 126, 178, 297, 417 Scnario 20, 401 Scne 18 proprit stageWidth 87 Score 122, 268 explosion de points 292 indicateurs 449 Match Three 321

Index

471

objets 421 points 421 systme complexe 382 voiture 433 search 326 Scurit paramtres 41 vol des jeux 88 selectable 55, 143 setChildIndex 61, 80 shift 149 shiftKey 63 showGameScore 192 shufe 236 shufeAnswers 388 shufePuzzlePieces 224 Simon 138 arrire-plan 152 SimpleButton 51 Simulation 452 Sin 246 Sol 395, 415 Sons 128, 454 charger 144 compression 130 isBuffering 83 lire 81, 460 MP3 144 playSound 129 proprits audio 82 Sortie, panneau 9 Souris 61, 345 clic 349 localX 75 MOUSE_DOWN 74 relchement 350 Space Rocks 262 splice 209 Sprite animer 66 crer des groupes 58 currentLoc 221 dnir la profondeur 61 dnition 17 dplacer 72 faire glisser 74 homeLoc 221

lettres 344 niveaux 233 proprit mouseEnabled 81 scaleX 417 stageWidth 87 start 68 startGameLevel 405 startPaddleBall 200 startTopDownDrive 437 startWordSearch 343 static 100 Stockage 358 stop 83 Stratgie de programmation 24, 140 programmation de haut en bas 313 String 324 styleSheet 57 substr 325 Suppression lments du jeu 166 parcours reculons 190 Survol (bouton) 49, 81 SWF 19, 88 switch 227 Symboles polices 298 proprits 94

Test cadence d'images 43 dbogage 22, 27, 32, 34 sur serveur 43 Texte 54 anim 334 chanes 324 defaultTextFormat 332 entre utilisateur 64 chier 78 jeu de quiz 363 jeu du pendu 337 li 56 mots mls 340 tabulation 382 TextField 13, 54, 159, 329 TextFormat 55, 143, 329 dupliquer 367 this 52 Timer 68, 127, 189, 228, 377 currentCount 68 dmarrer 68 getTimer 69, 172 TIMER_COMPLETE 127, 229, 279 toLowerCase 325 Touches ches 267 trace 9, 86, 360 Transparence 53, 62, 138, 278, 297 Typage 42

T
Tableau 134 convertir en chanes 328 copier avec concat 147 mlanger 85 pop 149 rocks 280 shift 149 shufeAnswers 388 types 135 Tabulation 382 Temps chronomtre 119, 376, 433, 448, 462 clockTime 121 limiter 127, 376

U
URLLoader 78 URLRequest 78, 214

V-W
validMove 224 var 28 Variable 28, 99 dnition combine 188 dx et dy 173 externe 77 incrmentale 27 noms descriptifs 26 typage 42

472

ActionScript 3.0 pour les jeux

Vlocit 70, 199, 267 Vies 419 visible 264 Vitesse 266, 457 cadence d'images 250 limiter 413 missiles 284 void 96

Voitures 428 braquage 457 circuit 451 collisions 442 contrle 431 freinage 457 mouvement 443 moveCar 444 piloter 248 points de parcours 460 rotation 246 while 31, 151, 306, 439

X-Z
XML 78, 89, 358 attributs 360 importer 361 xmlLoaded 79, 361 Zone ractive 390

ActionScript 3.0 pour les jeux

Gary Rosenzweig, gourou des jeux Flash, rvle quel point il est facile de crer des jeux Web poustouants grce la puissance de dveloppement dActionScript 3.0 et de Flash CS3 Professionnal. Ce livre inclut 16 jeux complets et leur code source. Des commentaires dtaills sur leur construction fournissent tous les outils ncessaires pour vous permettre de raliser vos propres crations. Le code des exemples est tlchargeable sur le site daccompagnement de ldition originale et facilement personnalisable an que vous puissiez lutiliser dans vos propres projets et sur vos sites Web. Que vous cherchiez mieux comprendre la programmation de jeux en ActionScript ou souhaitiez simplement disposer dune bibliothque de code pour crer des jeux, ce livre est fait pour vous !

Mmory et jeux de dduction Jeux de tir Puzzles et casual games Mots mls Quiz et jeux de culture gnrale Jeux de plate-forme Jeux de conduite et dexploration

Niveau : Intermdiaire / Avanc Catgorie : Programmation Conguration : PC / Mac

Pearson Education France 47 bis, rue des Vinaigriers 75010 Paris Tl. : 01 72 74 90 00 Fax : 01 42 05 22 17 www.pearson.fr

ISBN : 978-2-7440-4013-9

You might also like