Starfield Multidirectionnel version AS3
Introduction
Bonjour et bienvenue aux adeptes de l'AS3
Ce tutoriel a pour but de mettre en pratique les bases de l'ActionScript 3 et de la programmation orientée objet. Pour ce faire, nous allons créer un champ d'étoiles bougeant lors d'un appui sur les touches fléchées :
Appuyez sur les touches fléchées du clavier pour faire défiler les étoiles
Ce tutoriel fait suite à son équivalent en version AS2, lui-même écrit à partir d'un jeu créé par la communauté.
En guise de petit bonus par rapport à la version AS2 du tutoriel, nous verrons comment créer les étoiles à l'aide d'outils simples de dessin Flash (en version CS3, donc ça marche aussi pour la CS4 et la CS5). Nous utiliserons ensuite une classe de document afin de programmer la création du fond étoilé et les interactions avec l'utilisateur. Nous verrons également un ensemble de “bonnes pratiques” tout au long du tutoriel, car le but étant de vous apprendre à coder, mieux vaut que vous appreniez à coder “proprement” .
Pour les tout-débutants en AS3, ceux qui ne connaissent vraiment rien de rien à ce qu'est la POO, la notion de classe, d'objets et de méthodes… je les invite à aller voir les tutoriels bien détaillés sur ces notions :
Les bases de la programmation orientée objet
Les pratiques de la POO
Afin de programmer d'une façon toujours plus propre, il est recommandé de lire la page: Ecrire correctement en ActionScript
Je vous invite à la lire avant de vous lancer corps et âmes dans la programmation. Vous n'êtes pas obligés de respecter toutes les conventions citées dans cet ouvrage mais c'est un plus.
Vous trouverez également des références à divers tutoriels au fur et à mesure de votre lecture.
Enfin, si jamais vous bloquez sur un certain morceau de code, les “codes à connaître” regroupé en fin d'article vous fourniront des liens utiles pour mieux maîtriser ces petits morceaux. Je regroupe le tout à la fin de l'article afin de ne pas trop alourdir votre lecture.
Conventions des messages pour ce tutoriel :
Ce texte est important et il vous faut sûrement retenir quelque chose.
Ce texte vous met en garde, retenez cet avertissement si vous pensez qu'il vous concerne
Ceci est une petite astuce, elle vous resservira sûrement un jour.
Ce texte est purement informatif, vous pouvez le sauter en première lecture, mais il pourra sûrement vous apprendre quelque chose d'utile.
Bonne lecture !
Chapitre 1 : Dessinons !
Avant de pouvoir faire quoi que ce soit, nous avons besoin de matières premières avec lesquelles travailler.
Paramètres du document
Commencez-donc par créer un nouveau fichier Flash (AS 3.0). Donnez, au document, les propriétés suivantes :
- Largeur = 600 px
- Hauteur = 400 px
- Couleur de fond = blanche
- Cadence = 30 images / seconde
- Classe du document = Starfield
Pour ceux qui ne savent pas ce que c'est, lisez ce chapitre d'un autre magnifique tutoriel

Création des clips
Le fond
Dans la bibliothèque ajoutez un nouveau symbole de type Clip. Nommez-le Fond
(avec un F majuscule). Tracez un rectangle (à l'aide de l'outil rectangle), sélectionnez-le et donnez-lui les propriétés suivantes :
- Largeur = 600 px
- Hauteur = 400 px
- Couleur de fond = noire
- Couleur de contour = noire
- X = 0
- Y = 0
Ce clip contiendra tous les éléments affichés de notre starfield, à savoir le rectangle noir que nous venons de dessiner plus les étoiles que nous y ajouterons plus tard. Il sera l'élément ajouté en premier dans la scène et sera donc toujours le premier élément de la liste d'affichage. Ainsi, vous pourrez ultérieurement ajouter des éléments supplémentaires par dessus (vaisseau spatial, astéroïdes, etc) en étant sûrs que le ciel étoilé sera toujours bien affiché comme un fond (ou décors).
La liste d'affichage est une liste contenant tous les éléments ajoutés à la scène. Chaque fois que vous placez un élément à l'aide de l'instruction
addChild
, celui-ci vient s'ajouter à la fin de la liste d'affichage et donc au dessus de tous les éléments déjà créés. Ainsi le premier élément créé (indicé
0
dans la liste d'affichage) sera l'élément le plus au fond dans votre scène (donc en général un fond, un décor). Le dernier élément créé (indicé
numChildren - 1
dans la liste d'affichage) sera l'élément au devant de la scène (donc en général un personnage ou un vaisseau). Si vous voulez en savoir plus, je vous invite à lire le très détaillé chapitre 4 de l'ouvrage “Pratique d'ActionScript 3” de T.Imbert sur le sujet.
Fond
des étoiles à l'aide de code Actionscript. On dit alors que le fond joue un rôle de conteneur pour les étoiles.
Le clip des étoiles
Dans la bibliothèque, ajoutez un nouveau symbole de type Clip
et nommez-le Etoiles
et cliquez sur OK.
Création des étoiles :
Chose promise, chose due, nous allons créer des étoiles à l'aide d'outils simples que Flash propose. Commencez par modifier la couleur de la scène. Cliquez sur “Propriétés” et mettez une couleur d'arrière-plan noire.
Sélectionnez ensuite l'outil ovale (touche “o” du clavier). Prenez une couleur de remplissage autre que noire et ne mettez aucune couleur de contour. Dessinez un cercle, sélectionnez-le puis modifiez ses propriétés comme suit :
- Largeur : 15
- Hauteur : 15
- X : -7.5
- Y : -7.5
Modifier la couleur du cercle :
Faites un zoom sur votre cercle. Vérifiez qu'il est bien sélectionné puis ouvrez le panneau “Couleur”. Sélectionnez la couleur de remplissage puis prenez “Radial” comme type. Sélectionnez la première icône de couleur (un petit carré sur la barre en bas) puis allez chercher la couleur blanche.
Ajoutez une nouvelle couleur sur la barre (votre curseur affiche un ”+”), puis allez chercher une couleur bleue turquoise, modifiez sa propriété alpha à 25%. Sélectionnez enfin le troisième petit carré de couleur, allez également chercher une couleur turquoise puis modifiez sa propriété alpha à 0%. Vous pouvez jouer sur les 3 couleurs jusqu'à obtenir un résultat qui vous satisfait.
A un zoom à 2000% vous devez obtenir quelque chose du genre :
Vous pouvez rendre l'étoile plus ou moins claire, à votre convenance.
Créer les étoiles d'autre couleur :
Sélectionnez ensuite votre étoile, copiez-la puis créez de nouvelles images clés vides en image 2, 3, 4 et 5. Copiez dans chaque nouvelle image votre étoile (clique droit, coller en place ou Ctrl-Maj-V) et modifiez ses couleurs pour en avoir une blanche, une rouge, une bleue foncée et une jaune.
Et voilà ! Vous avez vos étoiles
N'oubliez pas de remettre la couleur d'arrière-plan de la scène sur blanche. En fait, nous pourrions tout aussi bien la laisser noire, mais :
- La laisser blanche vous permettra de vérifier que votre fond noir est bien ajouté à la scène
- Par usage, je préfère ne pas jouer sur la couleur de la scène et uniquement modifier la couleur du fond à l'aide de clips ou de graphismes.
Nous avons maintenant toute la matière première pour réaliser notre petit champ d'étoiles. Le chapitre suivant vous apprendra, à travers notre fond étoilé, quelques notions fondamentales à savoir sur les classes . Même si vous pensez tout savoir, je vous conseille d'y jeter un œil, vous y apprendrez sûrement quelque chose.
Le .fla
Comme je suis gentille et que je sais que certains programmeurs sont réticents à l'idée de tracer ne serait-ce que le moindre cercle sur Flash, je vous fournis le .fla avec les deux classes nécessaires et tous les paramètres comme il faut :
Chapitre 2 : Quelques notions fondamentales sur les classes
Documents .fla et .as associés ?
Maintenant que nous avons tous les éléments dans la bibliothèque du .fla, nous pouvons commencer à coder. Dans le cadre de ce tutoriel nous allons créer un fichier ActionScript codant la classe associée à notre document principal (.fla) :
- Faites “Fichier, Nouveau” (Contrôle + N) puis sélectionnez “Fichier ActionScript”.
- Enregistrez ce fichier nouvellement créé :
- Donnez-lui le même nom que celui de la classe que vous avez inscrit dans le champ “classe du document” des propriétés du document (normalement : Starfield.as) cela permet ainsi de lier les deux fichiers,
- Enregistrez-le dans le même dossier que votre fichier “fla”, cela simplifie toujours la tâche pour s'y retrouver.
Il est souvent plus simple - d'un point de vue organisation - d'enregistrer les fichiers de classe (.as) dans le même dossier que votre document principal (.fla), surtout lorsque vous ne manipulez que quelques classes. Pour les applications plus conséquentes, je vous invite à vous mettre au point sur l'organisation du disque et chemin de classe.
Par commodité et par usage, nous avons donné le même nom au fichier .fla et à sa classe. C'est également le même principe que j'utilise pour les clips : leur nom est le même que le nom de la classe qui leur est associé. Je trouve cela plus simple pour s'y retrouver. Le compilateur Flash se charge ensuite intelligemment de vérifier l'existence d'un fichier .as pour chaque classe créée.
Pour en savoir plus sur les classes : Tutoriel sur les classes
Package, Classes et propriétés
Pour vous rafraîchir la mémoire, nous allons passer en revu ce que doit toujours contenir une classe et dans quel ordre on les retrouve. Pour des raisons pratiques nous prendrons comme exemple la classe que nous venons juste de créer.
Nom du package
Dans un fichier .as la première ligne de code pour une classe créée est toujours :
package {
Après cette ligne et avant la création d'une classe dans un fichier .as, il est toujours nécessaire de spécifier à Flash de quelles bibliothèques la classe aura besoin. Pour cette classe de document nous aurons besoin de la bibliothèque relative aux Sprites :
/* Pour cette classe nous aurons besoin de la bibliothèque concernant les Sprites */ import flash.display.Sprite;
Vous pouvez ensuite insérer des commentaires comme bon vous semble. Il est généralement bien vu d'y placer un commentaire expliquant en bref l'utilité et la fonction de la classe pour le programme où elle intervient. Par exemple :
/*
Classe principale du jeu de shoot de l'espace gérant l'ensemble des éléments du jeu
*/
Nous pouvons maintenant créer notre classe :
public class Starfield extends Sprite { }
Notez le mot clé extends
il signifie que la classe que nous créons hérite des méthodes de la classe spécifiée, ici MovieClip
. La classe du document doit hériter de la classe MovieClip ou Sprite. Si votre scénario principal compte plusieurs images ce sera forcément un MovieClip, sinon préférez Sprite, c'est beaucoup plus léger.
Main
) ne va pas faire grand chose. En AS3 et surtout en POO, il est bon de prendre l'habitude de morceler le code dans différentes classes dont la fonction doit être unique et bien précise. Il en va de même pour les méthodes qui, en bonne pratique, doivent compter moins de 20 lignes de code.
Continuons… Après la déclaration de la classe, viennent les variables et constantes de cette classe dont il est préconisé de les déclarer comme ceci :
private var _ma_variable:type; private static const MA_CONSTANTE:type = valeur;
Notez surtout les préconisations pour les noms le _
au début du nom de variable et les lettres majuscules pour une constante. Concernant les mots clés private
et autres, je vous invite à lire le bloc d'information ci-dessous.
Petit tutoriel concernant les types de données : types de données primitives
Pour en savoir plus sur les variables : Qu'est-ce qu'une variable ?
Aide Abode, variables
Vous pouvez également trouver de plus amples informations sur tous ces sujets dans l'aide de Flash. N'hésitez pas à y faire une recherche sur les attributs ou les types, vous y apprendrez des choses intéressantes.

Sachez que par défaut on n'utilise pas le mot clé public
pour des variables. A la place, on les déclare en tant que private
et on crée des fonctions que l'on nomme communément Getter / Setter
. Autrement dit on récupère les variables et on les modifie à l'aide de fonctions et ce sont ces fonctions qui sont utilisées.
Après la déclaration des variables de classe vient la fonction constructrice de la classe.
Fonction constructrice / méthode constructeur
Pour notre tutoriel nous allons, bien sûr, utiliser une fonction constructrice. Ajoutez-la dès maintenant :
/* * Cette fonction est la fonction constructrice de la classe Starfield. * Elle fait appel à une fonction initialisant notre jeu. */ public function Starfield(){ initialiserJeu(); } } // On referme l'accolade correspondant à la classe } //et on referme bien l'accolade correspondant au package.
Aussi appelée méthode constructeur, cet article vous la présente très clairement.
Maintenant que nous avons le squelette de notre classe, continuons sans plus attendre et créons notre fond étoilé.
Pour l'instant, notre classe ne fait rien. Avant de continuer à la remplir, nous allons créer une classe Fond
associée au clip Fond
de la bibliothèque de votre fichier Starfield.fla. Nous aurons en effet besoin de cet élément dans notre classe Starfield.
Chapitre 3 : Des étoiles dans un fond noir !
Ce chapitre est entièrement consacré à la création du fond étoilé.
Classe Fond
En réalité c'est cette classe qui va s'occuper du gros du travail . Créons la sans plus attendre !
Puisque dans notre bibliothèque du document fla nous avons déjà un clip Fond
exporté pour ActionScript 3, nous allons créer une classe associée à ce clip et en créer une instance dans notre classe de document. Comme nous allons créer un véritable jeu et qu'il y aura pas mal de classes, nous allons utiliser le système de package.
Pour vous rafraîchir la mémoire : notion de package. Lisez-y également le paragraphe suivant concernant la définition des classes.

Pour les classes associées à un symbole de la bibliothèque, je vous invite à lire ce chapitre.
Liaison du symbole avec sa classe
Dans votre dossier où se situe le .fla, créez un nouveau dossier et appelez-le decor
. Retournez dans Flash puis sélectionnez votre clip Fond
dans la bibliothèque. Faites clique droit
puis propriétés
. Dans le champ Classe
insérez decor.Fond
et vérifiez que le champ Classe de base
pointe vers Sprite
(notre Fond ne nécessitera pas de scénario).
Cliquez ensuite sur le petit crayon à côté du nom de la classe, sélectionnez Flash Professional
puis cliquez sur ok
. Flash va vous créer directement la nouvelle classe avec le bon nom de package decor
qui correspond au chemin des dossiers où sera stocké la classe par rapport au fichier fla. N'oubliez pas d'enregistrer le nouveau fichier dans le dossier decor
et avec le même nom que la classe, à savoir Fond
, c'est très important. Vous noterez tout le code dors et déjà présent, c'est plutôt utile .
Et voilà ! Vous avez créé une classe associée à votre clip Fond
présent dans la bibliothèque de votre fichier fla. Lorsque vous êtes au sein d'une classe associée à un clip tout se passe comme ci vous interagissiez directement avec ce clip. Par exemple, la ligne de code :
width = 200;
Modifiera votre clip Fond
pour lui donner 200 pixels de largeur.
width
équivaut à this.width
où this
correspond à la classe elle-même. Lors de la création d'une instance de la classe, cela agira directement sur les propriétés de cette instance. Comme nous sommes au sein d'une classe, le this
est sous-entendu.
Variables et constantes de la classe Fond
Nous allons maintenant définir les variables de classe dont nous aurons besoin pour notre fond étoile. Il nous faudra donc :
- D'une constante pour limiter l'augmentation de la vitesse de déplacement des étoiles,
- D'une constante pour déterminer l'accélération et d'une autre pour la décélération,
- D'une constante pour définir le nombre d'étoiles désiré,
- D'un tableau stockant les étoiles créées.
En fait les constantes nous allons les déclarer dans une autre classe. Par usage il semble qu'il soit préférable de rassembler toutes les constantes dans une même classe servant uniquement à les définir et les instancier. Pourquoi préférable ? Car les constantes sont des paramètres que l'on doit pouvoir modifier facilement car très souvent ils correspondent à des caractéristiques fondamentales du jeu comme c'est le cas ici avec la vitesse limite et le nombre d'étoiles générées.
Mais tout d'abord terminons avec les variables de classe de notre fichier Fond.as. Ajoutons le tableau pour stocker les étoiles ainsi que deux variables stockant les dimensions initiales de notre clip Fond.
/* Le tableau suivant permettra de stocker chacune des étoiles créées pour * y accéder plus facilement */ private var _tableau_etoiles:Array; /* 2 variables pour stocker la hauteur et la largeur initiale du clip "Fond" */ private var _largeur_fond:Number, _hauteur_fond:Number;
Il nous reste donc à déclarer et initialiser les constantes.
Classe ''Constantes''
Petit aparté sur la classe chargée de répertorier toutes les constantes. Dans Flash cliquez sur Fichier / Nouveau
. Sélectionnez Classe d'ActionScript 3.0
. Mettez Constantes
comme nom de classe et appuyez sur ok. Cette classe n'a pas besoin d'hériter d'une autre. Elle n'a même pas forcément besoin d'imports. Elle se contente juste de déclarer des constantes et de les initialiser. Donc pour l'heure, elle doit contenir le code suivant :
package { /* Classe chargée de déclarer et d'initialiser les constantes utilisées pour le jeu Starfield */ public final class Constantes { /* * Nous aurons besoin de quelques constantes : * - Une pour limiter la vitesse de déplacement * - Une pour modifier facilement l'accélération des vitesses * - Une pour modifier facilement les décélérations des vitesse * - Une pour pouvoir facilement modifier le nombre d'étoiles */ public static const VITESSE_MAX:int = 5; public static const ACCELERATION:Number = 0.3; public static const DECELERATION:Number = 0.9; public static const NBR_ETOILES:int = 100; public function Constantes() { // constructor code } } }
final
? Final est un mot clé pour indiquer que la classe ne pourra être parente d'aucune autre. C'est par exemple le cas de la classe Math
. Vous ne pourrez donc jamais avoir public class MaClasse extends Math
. Ca vous affichera une erreur. Il est de bon ton de mettre ce mot clé à une classe comme Constantes où nous sommes sûres qu'elle ne sera jamais parente d'une autre classe.
Et c'est tout .
Remplissons le fond avec des étoiles !
La fonction constructrice de notre classe Fond ne va pas faire de grandes choses non plus. J'ai pris pour habitude de garder le code des fonctions constructrices aussi simple que possible, j'ai lu quelque part (je ne sais plus où si vous le lisez aussi, dites le moi) que c'était rudement conseillé pour je ne sais plus quelle bonne raison.
Donc ! La fonction constructrice va prendre en paramètre le nombre d'étoiles que notre fond devra contenir et fera appel à une autre fonction qui s'occupera de la création des étoiles à proprement parlé. Nous en profitons pour lui ajouter la fonction “classique” d'initialisation, qui paramétra toutes les propriétés initiales de notre fond.
/* La fonction constructeur délègue la création des étoiles à une autre fonction * et prend en paramètre le nombre d'étoiles à créer pour faciliter les éventuelles * évolutions du jeu. */ public function Fond(nbr_etoiles:int) { initialiserFond(); remplirDEtoiles(nbr_etoiles); addEventListener(Event.REMOVED_FROM_STAGE, nettoyerFond); }
Eh mais… Attend ! Pourquoi tu nous as fait créer la constante pour le nombre d'étoiles ? Ah mais c'est une bonne question ! Le fait est que nous utiliserons cette constante dans la classe Starfield.as. Mais ici je place cette information importante en tant que paramètre pour faciliter d'éventuelles évolutions du jeu. On ne sait jamais, peut-être qu'il vous viendrait l'envie de remplir le fond d'un nombre aléatoire d'étoiles pour faire en sorte que le joueur ait l'impression qu'il ne joue jamais dans la même galaxie. De même entre deux niveaux il sera plus simple de modifier le nombre d'étoiles que contient le fond, etc.
Eh ! Moi j'ai une autre question ! C'est quoi ce addEventbiduletruc ?!
Ca aussi c'est une bonne question. La réponse est simple, c'est une bonne pratique. Il faut prendre pour habitude de nettoyer chaque clip lorsque celui-ci est retiré de la scène. Cela se gère à l'aide de cet écouteur d'événement. Lorsque notre Fond sera supprimé de la scène nous ferons en sorte de supprimer également toutes les étoiles qu'il contient. C'est pour des raisons de performances.
ramasse-miette
de Flash. Ce ramasse-miette est chargé de libérer la mémoire de votre ordinateur dès qu'un élément de l'application est supprimé. Oui mais en fait personne ne sait vraiment comment il fonctionne, et on ne sait pas jusqu'à quel niveau il libère la mémoire… Imaginez qu'un de vos éléments possèdent 1 enfant possédant lui-même 1 enfant et lui-même 1 enfant etc…
Jusqu'où le ramasse-miette va ? Et qu'en est-il des écouteurs d'événement ? Sont-ils bien supprimés ? Je n'ai pas trouvé de réponses à ces questions, donc la bonne pratique c'est de tout supprimer explicitement de sorte que le ramasse-miette soit sûr qu'il est autorisé à libérer la mémoire occupée par ces éléments.
Un ciel étoilé
Continuons, et codons la fonction remplirDEtoiles
. Que doit-elle faire au juste ?
Elle doit :
- Créer autant d'étoiles que spécifié par la variable
nbr_etoiles
, - Tirer aléatoirement la couleur de l'étoile parmi toutes les couleurs présentes dans le clip Etoiles,
- Placer aléatoirement ces étoiles de façon à ce qu'elles remplissent toute la largeur et la hauteur du fond,
- Associer à chaque étoile une vitesse aléatoire qui lui est propre, afin de donner une impression de 3dimensions.
- Modifier aléatoirement, pour chaque étoile, ses propriétés Alpha (transparence), scaleX et scaleY (sa taille) pour que chaque étoile soit véritablement unique et plus ou moins lumineuse,
- Ajouter chaque étoile au fond noir puis la stocker dans le tableau
tableau_etoiles
.
Stocker des objets créés dans un tableau est une des multiples façons de faire pour pouvoir accéder facilement à ces objets ultérieurement. Une des applications courantes de cette méthode est un nettoyage propre et net de la scène lorsqu'on arrive à la fin d'un jeu ou d'une animation.
En réalité notre fonction ne va pas faire tout ça, encore une fois, elle va déléguer la tâche. Bon nombre des lignes de code à écrire pour faire ce qui est listé ci-dessus sont plus simples à écrire au sein même de la classe Etoiles
. Eh oui, vous l'avez deviné, nous allons créer une classe Etoiles
associée à notre clip etoiles
.
Une étoile aléatoire s'il vous plait !
Comme les étoiles font également parti du décor, le procédé pour créer la classe est quasi-identique à celui que nous avons suivi pour créer la classe associée au clip Fond. Clic droit sur le clip Etoiles dans la bibliothèque de votre fichier Flash, propriété
et zou, on y va.
Dans le champ Classe
remplissez decor.Etoiles
. Dans le champ Classe de base
laissez flash.display.MovieClip
, en effet, notre clip contient plusieurs images dans son scénario, autant qu'il y a d'étoiles différentes, c'est donc forcément un MovieClip. Et hop vous êtes près à cliquer sur le petit crayon à droite du champ Classe
.
Poum ! On a notre classe toute belle toute vide. Enregistrez-la sans plus attendre dans votre dossier decor
. Cette fois nous allons ajouter du code un peu plus actif
. Comme nous voulons que les étoiles aient chacune une vitesse propre, vous comprenez rapidement qu'il s'agit là d'une propriété de la classe et donc d'une variable globale de la classe. La fonction constructrice, quant à elle, va encore déléguer.
package decor { import flash.display.MovieClip; /* * Cette class est dédiée à la création aléatoire d'une étoile. * Elle est utilisée au niveau de la classe "Fond" pour créer * une multitude d'étoiles différentes. */ public class Etoiles extends MovieClip { /* Cette propriété stocke une vitesse propre à chaque étoile. * C'est elle qui donne une impression de 3 dimensions dans les mouvements */ private var _vitesse_propre:Number; /* Fonction constructrice, délègue son travail à la fonction "parametrerEtoile" */ public function Etoiles(largeur_fond:Number, hauteur_fond:Number) { parametrerEtoile(largeur_fond, hauteur_fond); }
Que doit faire la fonction parametrerEtoile
?
Elle doit :
- Tirer aléatoirement la couleur de l'étoile parmi toutes les couleurs présentes dans le clip Etoiles,
- Associer à chaque étoile une vitesse aléatoire qui lui est propre, afin de donner une impression de 3dimensions,
- Définir aléatoirement les positions x et y de chaque étoile en fonction de la taille et la hauteur du fond, cela aura pour effet de placer aléatoirement chaque étoile,
- Modifier aléatoirement, pour chaque étoile, ses propriétés Alpha (transparence), width et height (sa taille) pour que chaque étoile soit véritablement unique et plus ou moins lumineuse (effet obtenu grâce à une modification de la propriété alpha).
Vous voyez qu'elle se charge de 4 des fonctionnalités initialement prévues pour la fonction remplirDEtoiles
de la classe Fond
.
plus tard
(dans 3 ans que vous voudrez revoir le code).
Dans un premier temps nous voulons tirer aléatoirement une couleur d'étoile parmi toutes celles que nous avons pu créer. Pour ce faire nous aurons besoin de deux fonctions : Math.random() et gotoAndStop(). Et comme je suis gentille, je vais vous donner une fonction aléatoire très pratique et toute faite permettant de tirer un nombre entier ou non entre un minimum et un maximum et de façon inclusive ou exclusive. Suis sympa hein ? (Comment ça vous avez rien compris à ce que je viens de dire ?).
Aparté sur un tirage aléatoire
Vous pouvez créer la fonction tirageAleatoire
soit dans la classe Etoiles
où elle sera utilisée soit dans une autre classe que vous créerez.
Fonctions
ou FonctionsStarfield
et qui contiendra toutes les fonctions que vous serez amené à réutiliser très souvent dans de multiples projets différents. J'ai même tendance à regrouper ces classes dans un dossier code commun
voire dans un dossier externe et utilisé par tous mes projets Flash.
Moi je vais créer une classe spécifique, car m'est avis que cette fonction nous resservira plus tard pour notre jeu . Je pense que vous connaissez la marche à suivre, allez, une petite dernière fois. Sous Flash, faites
fichier
, nouveau
, classe d'actionscript 3.0
, Fonctions
dans le champ Nom de classe
et Ok
.
Cette classe tout comme la classe Constantes
ne sera parente d'aucune autre, on lui ajoute donc le mot clé final
et on l'enregistre à la racine de notre projet.
Dans cette classe, j'ajoute donc ma fonction tirageAleatoire
qui doit prendre en paramètre un minimum, un maximum, et deux booléens pour indiquer selon si elle doit être inclusive ou exclusive et si elle doit retourner un entier ou non. Cette fonction doit également être déclarée comme static
de sorte qu'elle puisse être appelée directement sur la classe, sans avoir à créer d'instance.
Nous testons tout d'abord que le min est bien inférieur au max, dans le cas contraire on renvoie une erreur :
package { /* Classe chargée de stocker quelques fonctions bien utiles */ public final class Fonctions { public function Fonctions() { } /* Tirage aléatoire : prend un minimum/maximum de type Number, * La propriété "inclusive" permet d'inclure (true) ou non (false) le maximum dans le tirage. * La propriété "entier" force l'arrondi du résultat à l'entier inférieur si elle est fixée à "true". */ public static function tirageAleatoire(min:Number, max:Number, inclusive:Boolean=true, entier:Boolean=true):Number{ var tirage:Number; if (min <= max) { }else { throw(new Error(''Attention mauvaise valeur pour l'aléatoire : min > max'')); }
=true
? C'est très simple, il permet d'indiquer une valeur par défaut au paramètre de la fonction. Ces paramètres sont alors facultatifs. Bien faire attention que tout paramètre obligatoire (sans valeur par défaut) doit se trouver avant tout paramètre facultatif, autrement vous aurez une erreur ^^.
Ici, par défaut, notre fonction est donc inclusive et elle renvoie un entier compris entre min et max.
Nous testons ensuite si le tirage doit être inclusif (inclut le max) ou exclusive (exclut le max) et si elle doit retourner un entier (on arrondit) ou non (on arrondit pas) et selon la valeur de ces booléens nous adaptons la formule pour avoir au final :
public static function tirageAleatoire(min:Number, max:Number, inclusive:Boolean=true, entier:Boolean=true):Number{ var tirage:Number; if (min <= max) { if (inclusive) tirage = min + Math.random() * (max - min + 1); else tirage = min + Math.random() * (max - min); if (entier) return Math.floor(tirage); else return tirage; }else { throw(new Error(''Attention mauvaise valeur pour l'aléatoire : min > max'')); } }
Remarquez Math.floor
qui arrondit le nombre à sa valeur inférieure, sachant que Math.random() tire un nombre entre 0 et 1 exclus, cette méthode fonctionne très bien .
Fin de l'aparté
Dans la fonction parametrerEtoile
on tire donc la couleur de l'étoile aléatoirement. Grâce à la propriété total_frames
qui contient le nombre d'images totales du scénario du MovieClip associé à la classe, on obtient ainsi le maximum à passer à notre nouvelle fonction aléatoire. Le tout se fait en deux ligne de code :
/* Fonction appelée dès la création d'une étoile et paramétrant chaque étoile * différemment grâce à des tirages aléatoires. */ private function parametrerEtoile():void { /* On tire un nombre aléatoire entre 1 et le nombre total d'images différentes * dans notre clip étoile, on accède ensuite à l'image correspondante à ce nombre * grâce à ''gotoAndStop'' s'opérant directement sur le clip ''étoile'' (souvenez * vous du ''this'' facultatif). */ var num_image:int = Fonctions.tirageAleatoire(1, totalFrames); gotoAndStop(num_image);
Bien ! Maintenant que vous avez compris le principe, les trois tâches qu'il nous reste à développer doivent vous paraître plus simples. Donc, sans plus tarder occupons-nous de donner une valeur aléatoire à la propriété _vitesse_propre
de notre classe Etoile. Cette propriété étant de type Number
nous nous payons le luxe de tirer un nombre non entier aléatoirement, de cette façon aucune étoile n'aura exactement la même vitesse.
/* Fonction appelée dès la création d'une étoile et paramétrant chaque étoile * différemment grâce à des tirages aléatoires. */ private function parametrerEtoile():void { /* On tire un nombre aléatoire entre 1 et le nombre total d'images différentes * dans notre clip étoile, on accède ensuite à l'image correspondante à ce nombre * grâce à ''gotoAndStop'' s'opérant directement sur le clip ''étoile'' (souvenez * vous du ''this'' facultatif). */ var num_image:int = Fonctions.tirageAleatoire(1, totalFrames); gotoAndStop(num_image); /* On tire une vitesse propre aléatoirement comprise entre 0.1 et 5 */ _vitesse_propre = Fonctions.tirageAleatoire(0.1, 5.0, true, false); }
Remarquez que le minimum pour notre tirage vaut 0.1
, en effet, même si la probabilité est très faible, je préfère éviter d'avoir des étoiles statiques
(mais rien ne vous empêche de mettre 0 ^^). Je passe donc le deuxième paramètre booléen à false pour récupérer une valeur de type Number
.
Pour la suite, rappelons quelques propriétés fondamentales d'un MovieClip que notre classe Etoile possède également grâce à l'héritage (i.e. grâce à ce petit morceau de code : extends MovieClip
) :
mon_clip.x
: coordonnée demon_clip
selon l'axe des abscisses (x),mon_clip.y
: coordonnée demon_clip
selon l'axe des ordonnées (y),mon_clip.alpha
: propriété de transparence du clip,mon_clip.scaleX
: échelle demon_clip
selon l'axe des X,mon_clip.scaleY
: échelle demon_clip
selon l'axe des Y.
Rappelons également que l'axe des ordonnées est orienté vers le bas dans Flash. Ainsi un clip dont l'ordonnée vaut 0 se retrouvera tout en haut de la scène. Passons aux choses sérieuses, le tirage aléatoire de ces différentes propriétés ne va guère être différent de ce que nous venons de faire pour la vitesse. Seule les propriétés x
et y
nous demanderons un peu plus de travail.
Commençons par le plus simple :
/* On tire une vitesse propre aléatoirement comprise entre 0.1 et 5 */ _vitesse_propre = Fonctions.tirageAleatoire(0.1, 5.0, true, false); /* On tire la propriété alpha et la taille de l'étoile * aléatoirement, cela donne l'impression que les étoiles sont plus ou moins lumineuses * et plus ou moins grande et renforce la sensation de 3 dimensions. */ this.alpha = Fonctions.tirageAleatoire(0.1, 1, true, false); this.scaleX = this.scaleY = Fonctions.tirageAleatoire(0.1, 1, true, false);
C'est pas plus compliqué que ça. Cette fois j'ai indiqué le this
pour que l'on ait bien conscience que l'on agit directement sur les propriétés de nos (futurs) clips Etoile
. Notez bien que pour que nos étoiles restent parfaitement ronde
nous faisons en sorte de leur donner la même échelle en largeur que en hauteur grâce à this.scaleX = this.scaleY = …
.
Reste les propriétés x et y. Pour celles-ci nous allons avoir besoin de la largeur du clip de fond et de sa hauteur en pixels. Notre classe étoile a donc besoin de les récupérer. Pour ce faire, nous allons les passer en paramètre lors de la création d'une nouvelle étoile, donc au sein de la fonction constructrice :
public function Etoiles(largeur_fond:Number, hauteur_fond:Number) { parametrerEtoile(largeur_fond, hauteur_fond); }
Nous passons tout de suite ces deux nouvelles variables à notre fonction parametrerEtoile
puisque c'est elle qui est chargée de modifier les propriétés de nos étoiles. Le tirage aléatoire des propriétés x / y se fait donc entre 0 et largeur_fond / hauteur_fond. Notre fonction parametrerEtoile
devient donc finalement :
/* * Fonction chargée de paramétrer chaque étoile, elle prend en paramètre * la largeur et la hauteur du fond pour tirer les coordonnées x/y * aléatoirement. */ private function parametrerEtoile(largeur_fond:Number, hauteur_fond:Number):void { /* On tire un nombre aléatoire entre 1 et le nombre total d'images différentes * dans notre clip étoile, on accède ensuite à l'image correspondante à ce nombre * grâce à ''gotoAndStop'' s'opérant directement sur le clip ''étoile'' (souvenez * vous du ''this'' facultatif). */ var num_image:int = Fonctions.tirageAleatoire(1, totalFrames); gotoAndStop(num_image); /* On tire une vitesse propre aléatoirement comprise entre 0.1 et 5 */ _vitesse_propre = Fonctions.tirageAleatoire(0.1, 5.0, true, false); /* On tire la propriété alpha et la taille de l'étoile * aléatoirement, cela donne l'impression que les étoiles sont plus ou moins lumineuses * et plus ou moins grande et renforce la sensation de 3 dimensions. */ this.alpha = Fonctions.tirageAleatoire(0.1, 1, true, false); this.scaleX = this.scaleY = Fonctions.tirageAleatoire(0.1, 1, true, false); /* On tire enfin les coordonnées aléatoirement */ this.x = Fonctions.tirageAleatoire(0, largeur_fond, true, false); this.y = Fonctions.tirageAleatoire(0, hauteur_fond, true, false); }
Et voilà ! Nous en avons terminé pour notre classe Etoile, toutes nos étoiles seront différentes les unes des autres.
Un joli ciel étoilé, enfin !
Nous pouvons enfin nous occuper de notre fonction remplireDetoiles
de la classe Fond
. Alors… Comment faire pour créer autant d'étoiles que la valeur de la constante nbr_etoiles
?
Une des méthodes consiste à utiliser une boucle for. Nous allons justement utiliser cette boucle pour notre programme :
/* Fonction remplissant le fond d'étoiles */ private function remplirDEtoiles(nbr_etoiles:int):void { var etoile:Etoiles; //On déclare notre variable étoile /* Pour chaque étoile devant être créée : */ for (var i:int = 0; i < nbr_etoiles; i++) {
Ici, on commence à i=0 et on augmente i de 1 à chaque étape. On arrête la boucle lorsque i vaut 100, on créera donc 100 étoiles.
On crée ensuite une nouvelle étoile. Il est important que cette ligne figure dans la boucle for, autrement vous modifieriez 100 fois la même étoile. Notez que la fonction constructrice Etoiles
attend en paramètre la largeur et la hauteur du fond. Nous allons donc récupérer ces valeurs AVANT la boucle for. (Pour savoir pourquoi, lisez le TIP ci-après). Enfin nous ajoutons les étoiles à notre fond et les stockons dans notre _tableau_etoiles
. Voici donc nos nouveaux morceaux de code :
Variables globales :
/* Le tableau suivant permettra de stocker chacune des étoiles créées pour * y accéder plus facilement */ private var _tableau_etoiles:Array; /* 2 variables pour stocker la hauteur et la largeur initiale du clip "Fond" */ private var _largeur_fond:Number, _hauteur_fond:Number;
Fonction constructrice :
/* La fonction constructeur délègue la création des étoiles à une autre fonction * et prend en paramètre le nombre d'étoiles à créer pour faciliter les éventuelles * évolutions du jeu. */ public function Fond(nbr_etoiles:int) { initialiserFond(); remplirDEtoiles(nbr_etoiles); addEventListener(Event.REMOVED_FROM_STAGE, nettoyerFond); }
Fonction intialiserFond
:
/* Fonction initialisant quelques paramètres pour notre fond */ private function initialiserFond():void { _largeur_fond = this.width; _hauteur_fond = this.height; _tableau_etoiles = new Array(); }
Fonction remplirDetoiles
:
/* Fonction remplissant le fond d'étoiles */ private function remplirDEtoiles(nbr_etoiles:int):void { var etoile:Etoiles; //On déclare notre variable étoile /* Pour chaque étoile devant être créée : */ for (var i:int = 0; i < nbr_etoiles; i++) { /* On crée un nouvel objet étoile, on dit qu'on crée une instance de la classe Etoiles */ etoile = new Etoiles(_largeur_fond, _hauteur_fond); //trace("largeur " + this.width + " hauteur " + this.height); /* On ajoute enfin chaque étoile au fond et au tableau devant les stocker */ addChild(etoile); _tableau_etoiles.push(etoile); } }
Fonction nettoyerFond
/* Fonction chargée du nettoyage du fond pour libérer efficacement la mémoire * lors de la suppression du clip Fond */ private function nettoyerFond(e:Event):void { removeEventListener(Event.REMOVED_FROM_STAGE, nettoyerFond); for each(var etoile:Etoiles in _tableau_etoiles) { removeChild(etoile); } _tableau_etoiles = []; }
Nous en avons profité pour terminer la fonction nettoyerFond
qui supprimera toutes les étoiles lorsque le fond sera retiré de la scène.
_largeur_fond
et _hauteur_fond
plutôt que directement this.width
et this.height
? Bonne question ! Et la réponse est toute simple : un clip
enfant
ajouté à un autre clip parent
ne peut pas sortir
de ce dernier. Cela signifie que le clip parent
sera redimensionné pour que ses clips enfants
soient toujours totalement inclus dans le clip parent
. Il en va de même pour la scène. C'est pour cela qu'il vaut mieux utiliser des constantes ou des propriétés pour la largeur et la hauteur des clips si on doit les utiliser dans le code, car les propriétés width
et height
seront modifiées dynamiquement et vous n'aurez pas l'effet voulu. Dans notre cas ce n'est pas gênant pour le moment mais dès que nous devrons déplacer les étoiles, si nous récupérons
this.width
et this.height
pour les limites du fond lors du déplacement, le fond s'agrandira indéfiniment et les étoiles ne seront jamais replacées de l'autre côté de la scène. Pour vous convaincre de mes dires, enlever les slash de commentaire à la ligne : trace(
largeur + this.width +
hauteur + this.height);
et à la place de _largeur_fond
et _hauteur_fond
lors de la création des étoiles mettez plutôt : etoile = new Etoiles(this.width, this.height);
Vous verrez que la largeur et la hauteur du fond seront légèrement modifiées. Faites bien attention à ces petits pièges de Flash où certaines propriétés des clips parents peuvent être modifiées selon ce qu'ils contiennent et prenez l'habitude d'utiliser des fonctions
trace
pour bien voir ce qu'il se passe sur la propriété à laquelle vous souhaitez accéder.
Très bien, jusque là vous me suivez ? Pour pouvoir enfin afficher notre fond étoilé il ne nous reste plus qu'à placer le fond sur notre scène dans notre classe principale. Donc, de retour dans Starfield.as
nous allons créer un nouveau fond et l'ajouter à notre jeu.
La fonction constructrice de notre classe de document est donc toute simple :
/* * Cette fonction est la fonction constructrice de la classe Starfield. * Elle fait appel à une fonction initialisant notre jeu. */ public function Starfield(){ initialiserJeu(); }
La fonction initialiserJeu
s'occupe de tout le boulot concernant… l'initialisation du jeu et entre autre le placement du décor. Avant de poursuivre, nous allons ajouter une variable globale de classe que je nomme objets
visant à stocker tous les enfants que nous ajoutons à notre classe Starfield
:
/* Déclaration du tableau ''objets'' stockant tous les enfants de Starfield */ private var _objets:Array; /* * Cette fonction est la fonction constructrice de la classe Starfield. * Elle fait appel à une fonction initialisant notre jeu. */ public function Starfield(){ initialiserJeu(); } /* Fonction chargée d'initialiser le jeu */ private function initialiserJeu():void { var fond:Fond = new Fond(Constantes.NBR_ETOILES); // Initialisation du tableau objets _objets = new Array(); }
J'utilise principalement le tableau objets
pour supprimer tous les enfants d'une classe lorsque cette classe est supprimée. Dans le cadre de la classe Starfield
le tableau objets nous servira à nettoyer notre scène entre deux phases de jeu (entre la page de présentation et le jeu, par exemple).
Il ne nous reste plus qu'à ajouter notre fond :
private function initialiserJeu():void { var fond:Fond = new Fond(Constantes.NBR_ETOILES); // Initialisation du tableau objets _objets = new Array(); addChild(fond); _objets.fond = fond; }
On crée donc un nouveau fond en passant notre constante NBR_ETOILES
, on ajoute le fond en tant qu'enfant de notre document et on stocke le fond dans le tableau des objets. Notez cette façon particulière de stocker le fond _objets.fond
. Cette méthode permet d'accéder beaucoup plus facilement à notre fond par la suite sans avoir à créer de nouvelle variable globale spécifiquement pour le fond.
Et voilà, un petit ctrl + entrée
vous permettra de tester votre code. Vous devriez voir un fond étoilé s'afficher :
Chapitre 4 : déplaçons les étoiles
Pour déplacer quelque chose en Flash il n'y a pas 36 manières, cela passe forcément au travers d'une interaction avec le joueur et pour gérer ça il faut des écouteurs d'événements.
Nous commencerons donc par gérer les interactions avec le clavier.
Gestion des événements clavier
Ce sera notre classe de document qui va se charger de gérer les interactions avec le joueur. Je trouve cela plus simple d'avoir toutes les gestions des interactions regroupées au même endroit dans le code et quoi de plus naturel que ce soit dans la classe principale, sommes toute elle est la mieux placée pour faire le pont entre ce que fait le joueur et ce que doit faire le jeu.
Ajoutons sans plus attendre les variables globales dont nous allons avoir besoin :
/* Nous avons encore besoin de quelques variables : - 1 booléen par direction, astuce couramment utilisée pour bien gérer les appuis sur les touches fléchées - 1 variable de vitesse par direction que, par ''usage (mathématique)'' on appelle - dx pour la vitesse horizontale - dy pour la vitesse verticale - 1 timer pour gérer la fréquence de la mise à jour des éléments */ private var _haut:Boolean, _bas:Boolean, _gauche:Boolean, _droite:Boolean; private var _dx:Number, _dy:Number; private var _timer:Timer;
Les booléens servent à enregistrer quelles touches sont enfoncées. Les variables _dx et _dy enregistre et mettent à jour respectivement les vitesses selon l'axe des abscisses et selon l'axe des ordonnées. Enfin, la variable _timer sera un timer s'exécutant toutes les X milli-secondes pour lancer la mise à jour des différents éléments du jeu (où X est inférieur ou égal au FrameRate de votre animation).
Lors de l'initialisation du jeu nous initialisons le Timer puis ajoutons les écouteurs d'événements qui vont bien :
private function initialiserJeu():void { var fond:Fond = new Fond(Constantes.NBR_ETOILES); // Initialisation du tableau objets _objets = new Array(); addChild(fond); _objets.push(fond); _timer = new Timer(20); _timer.addEventListener(TimerEvent.TIMER, miseAJour); _timer.start(); stage.addEventListener(KeyboardEvent.KEY_DOWN, toucheEnfoncee); stage.addEventListener(KeyboardEvent.KEY_UP, toucheRelachee); }
J'ai choisi 20 milli-secondes comme laps de temps entre deux mises à jour de nos éléments. C'est en général un chiffre qui va bien : ni trop long ni trop court. Faites bien attention que nous ajoutons les écouteurs d'événement à la scène. Vous pourrez essayer de les ajouter à la classe principale (sans stage) et vous verrez qu'il ne se passe rien.
ENTER_FRAME
? Pourquoi êtes-vous si curieux ? Non mais si en fait vous avez raison, allez donc voir cette discussion (en fait dans le même sujet que celui associé à ce tutoriel) pour connaître toutes les réponses à ce sujet.
Les fonctions que nous avons appelées toucheEnfoncee
et toucheRelachee
ne sont pas complexes. Nous utiliserons cette méthode pour gérer l'appui des touches au clavier. Commençons par programmer la fonction toucheEnfoncee
. En tant que méthode recevant un événement KeyboardEvent
elle doit récupérer un paramètre de type KeyboardEvent
:
/* Fonction s'exécutant lors de l'appuie d'une touche * modifie simplement les différents bouléens */ private function toucheEnfoncee(e:KeyboardEvent):void { switch(e.keyCode) { case Keyboard.LEFT: _gauche = true; break; case Keyboard.RIGHT: _droite = true; break; case Keyboard.UP: _haut = true break; case Keyboard.DOWN: _bas = true; break; default: trace ("Attention, touche " + e.charCode + " non gérée"); break; } }
default
dans une instruction switch
, cela fait parti des bonnes pratiques. De plus, dans notre cas, vous savez comme ça si la touche que vous appuyez est gérée ou non. Dans le cas où cette touche est sensée faire quelque chose, cela peut rapidement vous indiquer que vous avez simplement oublié d'ajouter sa gestion dans l'instruction switch

default
. Pour vous rafraîchir la mémoire, le cas default
est celui exécuté si aucun autre cas n'est vrai.
La fonction toucheRelachee
fonctionne sur le même procédé, rien de nouveau ici :
/* Fonction s'exécutant lors du relâchement d'une touche * modifie simplement les différents bouléens */ private function toucheRelachee(e:KeyboardEvent):void { switch(e.keyCode) { case Keyboard.LEFT: _gauche = false; break; case Keyboard.RIGHT: _droite = false; break; case Keyboard.UP: _haut = false; break; case Keyboard.DOWN: _bas = false; break; default: trace ("Attention, touche " + e.charCode + " non gérée"); break; } }
Reste à créer notre fonction miseAJour
. Cette dernière doit se charger de mettre à jour la vitesse à laquelle se déplace notre environnement et fera appel à la fonction deplacerEtoiles
de notre classe Fond que nous n'avons pas encore créée. Nous allons faire tout ça dans la partie suivante.
Déplacement des étoiles
La fonction miseAJour
est appelée à chaque diffusion de l'événement TIMER de notre timer. A notre cadence, elle s'exécute donc 20 fois par seconde. Cette fonction est la plus importante de ce code et s'occupe de beaucoup de choses. Que doit-elle faire ?
- Tester si une touche fléchée est enfoncée et incrémenter/décrémenter _dx ou _dy selon la direction en faisant bien attention de ne pas dépasser la constante
vitesse_limite
que nous avons défini au tout début. Le rendu sera une accélération, - Faire en sorte de faire tendre _dx/_dy vers 0 si aucune touche n'est appuyée. Le rendu sera une décélération,
- Mettre à jour tous les éléments de notre jeu en appelant les bonnes fonctions et en leur donnant toutes les informations nécessaires. Le rendu sera le déplacement d'une centaine d'étoiles ^^.
Bon ! … Nous allons attaquer chaque problème un à un. Commençons par gérer l'accélération des étoiles lors d'un appui sur une ou plusieurs touches. Avant toutes choses, initialisons les variables _dx / _dy dans la fonction d'initialisation du jeu :
private function initialiserJeu():void { var fond:Fond = new Fond(Constantes.NBR_ETOILES); // Initialisation du tableau objets _objets = new Array(); addChild(fond); _objets.fond = fond; _dx = 0; _dy = 0; //[...] }
Nous pouvons maintenant modifier les valeurs de ces deux variables selon les touches appuyées, que nous connaissons grâce aux booléens introduits auparavant.
/* Fonction chargée de mettre à jour l'univers de notre jeu */ private function miseAJour(e:TimerEvent):void { /* Les 4 tests suivants regardent quelle touche a été enfoncée. Si la vitesse dans la direction considérée ne dépasse pas la vitesse limite alors on l'incrémente / décrémente (selon la direction). C'est ce qui donne cette impression d'accélération rapide. */ if(_gauche && _dx <= Constantes.VITESSE_MAX){ _dx += Constantes.ACCELERATION; } if(_droite && _dx >= - Constantes.VITESSE_MAX){ _dx -= Constantes.ACCELERATION; } if(_haut && _dy <= Constantes.VITESSE_MAX){ _dy += Constantes.ACCELERATION; } if(_bas && _dy >= - Constantes.VITESSE_MAX){ _dy -= Constantes.ACCELERATION; } }
Tout est déjà expliqué dans le commentaire. Décortiquons le premier if
pour que vous compreniez bien :
if(_gauche && _dx ⇐ Constantes.VITESSE_MAX)
Si le booléen _gauche
vaut true
(donc si la touche fléchée Gauche est enfoncée) et si _dx
est inférieur ou égal à la vitesse limite alors :
_dx += Constantes.ACCELERATION
On augmente la variable _dx
de 0,3. Cette écriture équivaut à : dx = dx + 0.3
. Le principe est le même pour les autres conditions.
Le fait d'enchaîner ainsi les blocs
if
plutôt que des blocs if… else…
permet de tester chaque booléen et donc l'appui simultané de 2 touches fléchées. On peut alors se déplacer en diagonale.
Occupons-nous de faire ralentir les étoiles si aucune touche n'est enfoncée ou si les touches de direction opposée sont enfoncées en même temps. (Si vous allez en même temps à droite et à gauche, c'est donc que vous ne bougez plus ^^) :
/* Les 2 tests suivants étudient si on n'appuie plus sur une des touches de chaque direction ou si on appuie sur les touches de sens contraire. Si c'est le cas, on réduit progressivement les variables _dx / _dy, c'est ce qui produit cet effet de décélération */ if(_gauche == _droite){ _dx *= Constantes.DECELERATION; } if(_haut == _bas){ _dy *= Constantes.DECELERATION; }
Là encore j'ai tout expliqué dans les commentaires, mais nous allons tout de même décortiquer le premier if
:
if(gauche == droite)
Si les booléens _gauche
et _droite
valent tous les deux false
ou si ils valent tous les deux true
alors on exécute :
_dx *= 0.9
Ce code équivaut à _dx = _dx * 0.9
, on multiplie donc _dx par 0.9 ce qui permet de le faire tendre vers 0 qu'il soit négatif (déplacement vers la droite) ou positif (déplacement vers la gauche).
Pour faciliter les modifications de l'accélération des étoiles et du facteur de décélération, notez que j'ai mis ces valeurs dans ma classe Constantes
:
/* Classe chargée de déclarer et d'initialiser les constantes utilisées pour le jeu Starfield */ public final class Constantes { /* * Nous aurons besoin de quelques constantes : * - Une pour limiter la vitesse de déplacement * - Une pour modifier facilement l'accélération des vitesses * - Une pour modifier facilement les décélérations des vitesse * - Une pour pouvoir facilement modifier le nombre d'étoiles */ public static const VITESSE_MAX:int = 5; public static const ACCELERATION:Number = 0.3; public static const DECELERATION:Number = 0.9; public static const NBR_ETOILES:int = 100;
Rappelez-vous que la fonction
miseAJour
est exécutée lors de la diffusion de l'événement TimerEvent.TIMER
. Les variables _dx et _dy varient donc en douceur grâce aux décrémentations/incrémentations/multiplications et grâce au fait que la fonction s'exécute régulièrement
. Le fait que leur type soit Number
est également très important, car nous pouvons ainsi les faire évoluer plus doucement que si elles étaient des entiers. Les valeurs ont été trouvées après plusieurs tests pour un bon rendu final.
Reste à déplacer chacune des 100 étoiles en fonction des valeurs de _dx
et _dy
.
Boucle principale
Pour déplacer les étoiles il faut pouvoir accéder à chacune d'elles. Heureusement, nous avons pensé à stocker chaque étoile dans un tableau dans notre classe Fond
! Il ne nous reste plus qu'à intervenir sur chaque élément du tableau _tableau_etoiles
. Nous allons donc balayer ce tableau et déplacer chaque étoile en fonction de sa vitesse propre et des variables _dx, _dy
.
Nous créons une fonction deplacerEtoiles
au sein de la classe Fond
et la déclarons comme public
de sorte qu'on puisse l'appeler dans notre classe principale. Cette fonction recupère les valeurs de _dx et _dy que nous avons modifiées dans la fonction miseAJour de la classe principale. Une fois ces valeurs récupérées, il suffit de balayer le tableau des étoiles et de modifier leurs coordonnées en multipliant leur vitesse propre par dx/dy respectivement.
Vous vous souvenez que nous avions assigné une vitesse propre tirée aléatoirement à chaque étoile ? C'est ici qu'elle va donc intervenir. Le hic c'est que nous avons déclaré cette variable en tant que “private” au sein de la classe “Etoiles”. Nous allons donc créer ce que les programmeurs ont l'habitude d'appeler un “getter”. C'est rien de compliqué, c'est une fonction qui, comme son nom l'indique, permet de récupérer la valeur d'une variable. Voici sa syntaxe :
Dans le fichier Etoiles.as :
public function get vitesse_propre():Number { return _vitesse_propre; }
Vous voyez le mot clé “get” ? C'est lui qui indique que cette fonction est un “getter” et qui permet d'accéder à la valeur de la variable _vitesse_propre de la façon suivante : “etoile.vitesse_propre”. Donc, tout se passe comme si nous avions déclaré la variable comme “public” sauf que ce n'est pas le cas. La différence majeure est que si vous essayez d'assigner une valeur de cette façon : “etoile.vitesse_propre = 5”, si la variable est déclarée en tant que public, ce sera possible, ici, cela retournera une erreur. Bien entendu, c'est toujours possible mais il faut alors créer ce qu'on appelle un “setter”. Donc la syntaxe est la suivante :
public function set vitesse_propre(vitesse:Number):Number { _vitesse_propre = vitesse; }
Mais ici, nous n'en aurons pas besoin. Attelons-nous plutôt à compléter la fonction “deplacerEtoiles”, maintenant que nous avons tous les éléments :
public function deplacerEtoiles(dx:Number, dy:Number):void { /* Pour chaque étoile */ for each(var etoile in _tableau_etoiles){ /* on les déplace selon leur vitesse et les dx/dy actuels */ etoile.x += etoile.vitesse_propre*dx; etoile.y += etoile.vitesse_propre*dy; } }
Pour chaque étoile on incrémente leur coordonnée x / y en fonction de la valeur dx / dy multiplié par leur vitesse propre que nous récupérons à l'aide du code tableau_etoiles[i].vitesse
. Il reste un problème : si vous testez, vous voyez que vos étoiles partent pour ne jamais revenir… (sauf si vous allez dans la direction opposée bien sûr).
Il nous reste à gérer le mouvement perpétuel. L'astuce consiste à déplacer instantanément une étoile d'une extrémité à l'autre du fond lorsque celle-ci arrive près d'un bord. Cette manipulation doit se faire dans la boucle déplaçant chaque étoile. C'est bête mais fallait y penser . Il n'y a rien de nouveau ici, ce ne sont que des instructions
if
modifiant les coordonnées x/y des étoiles lorsque les conditions sont réalisées :
public function deplacerEtoiles(dx:Number, dy:Number):void { /* Pour chaque étoile */ for each(var etoile in _tableau_etoiles){ /* on les déplace selon leur vitesse et les dx/dy actuels */ etoile.x += etoile.vitesse_propre*dx; etoile.y += etoile.vitesse_propre * dy; /* Si les étoiles dépassent l'écran d'un bord ou un autre on les fait réapparaître de l'autre côté. C'est ce qui donne le mouvement perpétuel */ if(etoile.x > _largeur_fond){ etoile.x = 0; }else if(etoile.x < 0){ etoile.x = _largeur_fond; } if(etoile.y > _hauteur_fond){ etoile.y = 0; }else if(etoile.y < 0){ etoile.y = _hauteur_fond; } } }
Décortiquons la première condition, c'est tout simple : si la valeur de la coordonnée x
de l'étoile dépasse la largeur du fond, alors on déplace instantanément l'étoile de l'autre côté du fond, donc à x = 0
. Le else if
est là pour la forme… On suit juste l'idée logique que si l'étoile est à un bord de l'écran elle n'est pas en même temps sur le bord opposé de l'écran.
Conclusion
Et voilà ! Nous avons terminé le code pour cette animation. Pour les expérimentés, je suis désolée si vous vous êtes ennuyés, mais il était bien question ici d'un tutoriel ludique pour les débutants en ActionScript 3 et en programmation orientée objet.
Si tout s'est bien passé, vous pouvez tester votre animation et vous devriez avoir ceci :
Fin
Merci de m'avoir lue ! J'espère sincèrement que cette lecture vous aura été profitable. A partir de maintenant, vous devriez être capable de créer n'importe quel fond déroulant (ou presque).
Section "Code à connaître"
addChild()
addChild()
est une méthode permettant de faire apparaître à l'écran (sur la scène) l'objet d'affichage passé en paramètre. La méthodeaddChild()
peut être appelée uniquement sur des objets d'affichage. Ceux-ci doivent donc déjà faire partie de la liste d'affichage pour que le nouvel objet s'affiche également à l'écran. Le conteneur par défaut est ''this''.
Sachez que le premier conteneur de la liste d'affichage doit forcément être ajouté en tant qu'enfant de l'objet Stage (la scène/l'écran). Vous pouvez également ajouter directement des éléments à la scène avec le code :stage.addChild(nomObjet)
.
Pour supprimer un objet de l'affichage, il suffit de faire :clipParent.removeChild(clipEnfant)
.
Pour en apprendre plus sur la liste d'affichage, je vous invite à lire ce chapitre du livre de Thibault Imbert.
Propriétés d'une instance de classe
Pour accéder aux propriétés d'une instance de classe, en AS3, la syntaxe est la suivante :
nominstance.propriété;
. N'oubliez pas les méthodesgetter/setter
et évitez d'utiliser l'attributpublic
.
_
”, il a tout bonnement disparu sauf pour les variables globales mais là c'est nous qui le rajoutons explicitement ^^.
addEventListener
En ce qui concerne cette méthode, je vous invite à lire les articles suivants (qui expliquent tout en détail) :
La méthode addEventListener
La gestion des touches en AS3
Lisez attentivement le deuxième article.
Notez que vous pouvez utiliser les écouteurs d'événements dans une classe, uniquement si vous avez correctement importé la bibliothèque des événements correspondants. Exemple si vous souhaitez gérer des événements clavier :
import flash.events.KeyboardEvent;
Les événements Clavier
Vous trouverez ici : Keyboard - référence, la liste complète des codes des touches.
Si vous voulez en apprendre plus sur la classe KeyboardEvent, c'est par ici : Classe KeyboardEvent
Instruction ''switch''
En ce qui concerne le switch, je vous invite à lire la documentation Adobe : Aide Adobe Switch; Documentation Switch
Les boucles en AS3
Je vous conseille de lire cet article : >utilisation des boucles en AS3. Lisez-y attentivement les chapitres concernant les bouclesfor each in
etfor in
, moins connues.
La classe Math, ses amies et ses méthodes
Si vous voulez en connaître plus sur les méthodes et classes globales : Niveau supérieur d'AS3
Si vous voulez en apprendre plus sur la classe Math : Classe Math
La classe MovieClip
Pour en savoir plus sur la classe MovieClip, ses méthodes et ses propriétés publiques : Guide de référence - MovieClip.
La classe Error
Je vous invite à lire la documentation concernant cette classe : Documentation Adobe - Error.
Les Array et ses méthodes
Je ne saurais que vous conseiller ce tutoriel de Nataly : tout sur les tableaux.
Les sources
Vos retours
Je vous invite à participer à la discussion autour de ce tutoriel, d'apporter vos retours, de poser des questions, etc. :
Discussion
Pour des demandes de correction dans le tutoriel en lui-même ou dans le code, ce sera plutôt par ici :
Corrections
Annexe: Histoire de Starfield
Ce tutoriel a une longue histoire en réalité, que je vais tenter de romancer ici par respect pour tous ceux qui se sont investis dans ce projet (et surtout parce que c'est grâce à eux que je peux continuer aujourd'hui ce tutoriel) :
Histoire de Starfield, chapitre 1 :
La création de ce tutoriel est partie d'une folle envie de plusieurs habitués de Flash MediaBox de créer en commun un projet de jeu d'astéroïde avec une discussion transformée (malheureusement) en monologue à cause d'un incident technique.
Histoire de Starfield, chapitre 2 :
Face à l'intérêt marqué envers ce projet des divers protagonistes et de nouveaux venus, M.Spi (que je salue) a désiré en tirer un petit tutoriel qui reprendrait la petite pierre que chacun a apporté. Faute de temps il ne put totalement mener à bien ce vaste projet mais en a tout de même tiré un excellent tutoriel qui constitue la version AS2 que j'ai introduite précédemment.
Histoire de Starfield, chapitre 3 :
Thade arrive ensuite avec sa nouvelle version du logiciel Flash et propose un portage AS3 du projet. Nataly s'est ensuite occupée d'ajouter une version AS3 du code pour enrichir le tutoriel de M.Spi.
Histoire de Starfield, chapitre 4 :
Puis, un beau jour, alors que je traine dans les rubriques du forum je découvre le magnifique tutoriel de M.Spi apprenant à réaliser un fond étoilé tout beau avec une impression de 3D, exactement ce qu'il me fallait pour un de mes jeux. En utilisant son travail, j'ai ensuite trouvé dommage qu'il n'existe pas une version AS3 du tutoriel. Certes, le code AS3 existait, mais il manquait une page complète sur le sujet. Je me suis alors proposée pour reprendre le projet de tutoriel de M.Spi, et avec son accord je me suis mise au travail. Aujourd'hui, grâce à la grande communauté de Flash Mediabox, je peux m'amuser à créer un vaste tutoriel autour d'un jeu sympathique (une sorte de rêve qui devient réalité :P je sais, j'ai des rêves bizarres). Pour me permettre de réaliser ce projet, je remercie tous les auteurs et acteurs s'étant investis dans ce projet avant, pendant et après moi.
Fin de la petite histoire,
Merci à ceux qui ont pris le temps de la lire. Comprenez bien que vous avez entre les mains un travail collaboratif entre de multiples acteurs qu'il convient de respecter comme il se doit.
Remerciements
Je remercie toute l'équipe de MédiaBox parce qu'ils sont géniaux mais également Monsieur_Spi qui m'a permis de faire une version AS3 de son tutoriel ainsi que Lilive notre fameux bibliothécaire et Nataly qui m'a bien accueillie et puis toute la communauté qui s'est déjà investi dans ce vaste projet !
Et puis je remercie surtout ceux qui ont eu le courage de tout lire !
