Licence CC BY-NC-SA

Les objets d'affichage

Publié :

Dans ce chapitre, nous allons aborder le système qui va nous permettre (enfin !) d'afficher des éléments (texte, dessins, images, etc.) à l'écran ! Mais nous ne pourrons réellement afficher quelque chose qu'au chapitre suivant, car il nous faut aborder quelques notions de base auparavant.

Nous allons voir notamment :

  • comment décrire une couleur en ActionScript,
  • le fonctionnement l'affichage sur un écran,
  • et enfin le système d'affichage de Flash.

C'est parti !

Introduction

Les couleurs

Composer une couleur

En informatique, les couleurs sont décomposées en couleurs principales : le rouge, le vert et le bleu. À partir de ces trois couleurs, il est possible de créer n'importe quelle autre couleur en les dosant (voir figure suivante).

Les couleurs principales de la lumière

Exemple : je souhaite créer une couleur orange. L'orange est constitué de jaune et de rouge. Ainsi, il nous faut d'abord faire du jaune (rouge + vert), puis rajouter du rouge (voir figure suivante). Au final, l'orange se crée grosso-modo avec deux quantités de rouge pour une quantité de vert.

Composition de la couleur orange

Notation hexadécimale

Pour décrire une couleur composée de rouge, de vert et de bleu, nous utiliserons la notation hexadécimale. On commence par écrire 0x pour signifier que l'on utilise la notation hexadécimale, puis on décrit les quantités de chacune des trois couleurs rouge, vert et bleu : deux chiffres, allant de 0 (le minimum) à F (le maximum) pour chacune, ce qui fait six chiffres.

Pourquoi jusqu'à F ? Depuis quand F est un chiffre ? o_O

Excellente question ! En réalité, il existe différents systèmes de notation pour les nombres. Celle que vous et moi utilisons tous les jours s'appelle la notation décimale. Cela signifie que nous utilisons les chiffres de 0 à 9 pour écrire les nombres. On dit aussi que nous écrivons les nombres en base dix. Une autre notation très connue est la notation binaire : nous décrivons les nombres avec seulement les chiffres 0 et 1. On parle alors de base deux. Par exemple, 5 en base dix s'écrit 101 en base deux !

La notation hexadécimale utilise non pas dix, mais seize chiffres ! On parle de base seize pour cette notation. Les chiffres vont de 0 à 15 ; avouez cependant qu'écrire un chiffre à l'aide de deux chiffres serait plutôt embêtant… Comment faire alors la différence entre 12 (le chiffre) et 12 (le nombre composé du chiffre 1 et du chiffre 2) ? Impossible !

Ainsi, nous utilisons les 6 premières lettres de l'alphabet pour remplacer les chiffres 10 à 15, ce qui est tout de même bien plus pratique.

Chiffre (décimal)

Notation hexadécimale

10

A

11

B

12

C

13

D

14

E

15

F

En dehors de l'ActionScript, on utilise plus généralement le # pour commencer une notation hexadécimale.

Ainsi, pour écrire notre chiffre 12, nous utilisons C ! Voici quelques exemples de nombre en base dix convertis en base seize :

Base dix

Base seize

12

C

5

5

31

1F

32

20

16

10

160

A0

66

42

Afin de décrire une couleur, nous utiliserons donc deux chiffres en hexadécimal pour le rouge, le vert et le bleu, de 00 à FF, ce qui fait de 0 à 255 en décimal. Par exemple, pour notre couleur orange, nous écrirons : 0xFF8000, car il y a deux doses de rouge pour une dose de vert (voir figure suivante).

Notation hexadécimale de la couleur orange

La plupart des logiciels de dessin et retouche d'image affichent la notation hexadécimale des couleurs, qu'il est alors facile de copier-coller. Il existe également des outils ou des sites web spécialisés dans la création de couleur, qui fournissent cette notation (comme par exemple, ColRD). Attention toutefois, il ne faut pas oublier qu'en ActionScript, la notation hexadécimale commence par 0x et non pas par # !

Stocker une couleur dans une variable

Le type qu'il faut utiliser pour stocker un nombre en notation hexadécimale est le type uint :

1
2
var orange:uint = 0xFF8000;
var orange2:uint = 0xff8000; // Les lettres peuvent aussi être notées en minuscule

La variable ainsi créée peut être manipulée comme n'importe quelle autre variable :

1
2
3
4
trace("La couleur orange vaut " + orange + " en base dix."); // 16744448
trace("La couleur orange vaut " + orange.toString(10) + " en base dix."); // 16744448
trace("La couleur orange vaut " + orange.toString(16) + " en base seize."); // FF8000
trace("La couleur orange vaut " + orange.toString(2) + " en base deux."); // 1111 1111 1000 0000 0000 0000

Vous remarquerez que la couleur est stockée sous la notation décimale, car c'est la seule notation supportée par les types de nombres. Par contre, il est facile de retrouver la notation hexadécimale ou binaire grâce à la méthode toString() comme dans l'exemple ci-dessus.

L'affichage sur un écran

Tous les écrans d'affichage sont composés d'une grille de petits carrés de lumière que l'on nomme pixels (voir figure suivante). Nous allons voir comment utiliser cette grille pour positionner des objets.

L'écran est composé d'une grille de pixels

Le repère

Les pixels forment donc une grille suivant deux axes : l'axe des X et l'axe des Y. On se situe alors sur un espace en 2D. Pour mieux visualiser la grille, nous allons utiliser à la figure suivante un repère, qui nous montre les axes et l'origine de la grille.

Repère de l'affichage

Une position (c'est-à-dire un point précis de ce repère) est décrite par deux coordonnées : la position en X, et la position en Y. On écrit toujours les coordonnées en 2D dans cet ordre : d'abord les X, puis les Y. Ainsi il n'est pas nécessaire de tout le temps préciser qui est quoi. Dans l'exemple à la figure suivante, le pixel que l'on a colorié en bleu se trouve à la position (5,6), c'est-à-dire à 5 pixels du bord gauche de l'écran, et à 6 pixels du bord supérieur de l'écran.

Exemple de position sur l'écran

Tout au long du cours, il faudra avoir ce repère en tête dès qu'il s'agira de positionner un objet à l'écran. Il faut savoir qu'il est possible que les coordonnées soient négatives, mais dans ce cas, les pixels qui dépassent ne seront pas affichés (faute de pixels sur votre écran :D ).

L'arbre des objets d'affichage

L'arbre d'affichage

Pour bien comprendre de quoi il s'agit, commençons par un exemple concret, et revenons sur notre chère voiture. Nous voulons maintenant l'afficher et l'animer sur notre écran ! Nous allons utiliser un modèle simplifié, celui de la figure suivante.

Votre magnifique voiture simplifiée

Supposons que cette voiture soit composée d'une carrosserie et de deux roues. Vue de l'extérieur, la voiture est un objet et un seul (voir figure suivante).

La voiture vue de l'extérieur

Mais en réalité, il y a trois objets à l'intérieur de cet objet (voir figure suivante) : la carrosserie en orange et les deux roues en bleu.

L'objet Voiture est composé d'autres objets

Lorsque nous voudrons afficher la voiture, nous créerons tout d'abord un conteneur (par exemple, avec la classe Sprite), puis nous ajouterons à l'intérieur trois autres objets d'affichage (voir figure suivante) : un pour la carrosserie, et un pour chaque roue.

Nous disposons les différents objets dans le conteneur Voiture

Ainsi, si nous bougeons le conteneur « voiture », les roues se déplaceront en même temps que la carrosserie ; si nous tournons le conteneur, l'ensemble fera une rotation comme s'il s'agissait d'un unique objet, à l'instar de ce qui se passerait dans la vraie vie ! La voiture pourrait elle-même se trouver dans un autre conteneur "rue", que l'on pourrait faire défiler comme un tout…

Ainsi, l'arbre d'affichage est une arborescence d'objets d'affichage inclus les uns dans les autres dans une certaine logique. Voici un schéma à la figure suivante représentant l'arbre d'affichage de notre application

L'arbre d'affichage de la voiture

Vous remarquerez que la racine de l'arbre est composée d'un objet que j'ai appelé scène principale. C'est un objet spécial de la classe Stage qui est toujours présent pour la gestion de l'affichage.

Maintenant, si nous voulons qu'il y ait deux voitures dans la rue, il suffit d'en ajouter une autre dans le conteneur « rue ».

Plusieurs voitures dans l'arbre d'affichage

Il est important de se rappeler que modifier l'apparence ou la position d'un conteneur impactera tous les enfants comme s'il s'agissait d'un seul et unique objet. Il est néanmoins possible de modifier les enfants séparément.

Les classes d'affichage

En ActionScript, il existe plusieurs classes différentes dédiées à l'affichage, comme on peut le constater à la figure suivante.

Extrait de l'arbre d'héritage des classes d'affichage

Par exemple, la classe TextField sert à afficher du texte ; nous en reparlerons dans le prochain chapitre. Elle est une sous-classe de InteractiveObject (pour les objets interactifs), elle-même sous-classe de DisplayObject. Ainsi, toutes les classes d'affichage sont des sous-classes de la classe DisplayObject.

Rappel : les classes abstraites ne peuvent pas être instanciées directement, c'est-à-dire que l'on ne peut pas créer de nouveaux objets de ces classes avec le mot-clé new. Il est toutefois possible de spécifier des paramètres de type de classes abstraites dans les méthodes, ce n'est pas gênant.

La classe DisplayObject (abstraite)

Il s'agit de la classe d'affichage de base. C'est à partir d'elle que toutes les autres classes d'affichage sont dérivées ; elle contient les propriétés utiles pour manipuler des objets d'affichage simples. Encore une fois, étant donné qu'il s'agit d'une classe abstraite, inutile d'essayer de créer un objet de la classe DisplayObject.

La classe Bitmap

Cette classe permet d'afficher des images composées de pixels. Les objets de cette classe sont purement visuels ; il est impossible de gérer directement les clics de souris dessus par exemple. Nous apprendrons à manipuler des images dans les prochains chapitres.

La classe Shape

Cette classe permet de créer des objets légers permettant de dessiner à l'écran : tracer des lignes, des formes, remplir… À l'instar des objets de la classe Bitmap, les objets de la classe Shape sont purement visuels.

La classe Video

Comme vous vous en doutez, cette classe permet l'affichage de vidéos (avec le son). C'est aussi une classe créant des objets purement visuels.

La classe InteractiveObject (abstraite)

Cette classe permet d'introduire de l'interactivité pour nos objets d'affichage : il sera ainsi possible de savoir si l'utilisateur clique sur un objet d'une sous-classe de la classe InteractiveObject.

La classe SimpleButton

Cette classe permet de fabriquer des boutons basiques rapidement : on peut ainsi lui spécifier quel objet sera affiché dans différents états (normal, souris au-dessus, cliqué, …), et automatiquement changer le curseur de la souris au-dessus en doigt. Cette classe est utilisée par Flash Pro d'Adobe pour créer les boutons.

La classe TextField

Avec cette classe, nous présenterons du texte à l'écran pendant le prochain chapitre. Il est possible de formater le texte à l'aide d'une forme très allégée d'HTML (le langage principal utilisé pour créer des sites web).

La classe DisplayObjectContainer (abstraite)

Cette dernière classe abstraite introduit la notion de conteneur : il est désormais possible d'ajouter plusieurs objets d'affichage enfants dans un seul conteneur, afin de les manipuler ensemble comme s'il s'agissait d'un seul objet (pensez à la fonction Grouper des logiciels de bureautique).

La classe Loader

Cette classe nous permettra de charger du contenu externe à notre application, à condition qu'il soit visuel.

La classe Stage (abstraite)

Les objets de cette classe sont des objets spéciaux qui représentent la scène d'affichage de l'application. Il est bien évidemment impossible de créer directement une instance de la classe Stage. Attention, la plupart des propriétés héritées des classes-mères ne fonctionnent pas sur eux (comme par exemple la position, l'opacité, etc.).

La classe Sprite

Non, il ne s'agit pas de la boisson ! :-° Les objets de cette classe sont les plus utilisés en tant que conteneurs, et en tant que dessins interactifs. Vous en userez (et abuserez) en programmant en ActionScript !

La classe MovieClip

Cette classe dérivée de la classe Sprite ajoute un composant complexe et plutôt lourd : une ligne de temps (ou timeline en anglais). Cela consiste en une série d'images-clés pouvant être réparties sur différents niveaux, afin de créer des animations complexes (voir figure suivante). Cette classe a tout d'abord été conçue pour être utilisée dans le logiciel d'animation Flash Pro d'Adobe ; ainsi, étant d'un intérêt limité pour une utilisation en ActionScript, nous ne l'utiliserons quasiment pas dans ce cours.

Un exemple de timeline dans Flash Pro

Il existe d'autres classes d'affichage que je n'ai pas mentionnées ici : nous ne les aborderons pas, étant trop avancées. Mais si vous êtes curieux, vous pouvez toujours explorer les possibilités supplémentaires qui s'offrent à vous en visitant la documentation.

Si nous reprenions notre exemple de la voiture, les schémas des arbres d'affichage ressembleraient aux deux figures suivantes.

L'arbre d'affichage de la voiture

Plusieurs voitures dans l'arbre d'affichage

Manipuler les conteneurs

Toutes les nouvelles propriétés (attributs et méthodes) que nous allons voir sont issues de la classe DisplayObjectContainer. Je vous conseille d'aller lire en parallèle la documentation officielle du langage ActionScript 3, en français et disponible à cette adresse. N'hésitez surtout pas à l'utiliser aussi souvent que vous en sentez le besoin, elle est très pratique ! ;)

Buvez du Sprite !

Comme nous l'avons vu précédemment, la classe Sprite va nous permettre de créer des conteneurs d'affichage très polyvalents tout en restant légers. Commençons par créer un conteneur que nous appellerons voiture.

1
2
// Création du conteneur 'voiture'
var voiture:Sprite = new Sprite();

Comme vous pouvez le remarquer, le constructeur de la classe Sprite ne prend pas de paramètre.

Ajouter des enfants

Pour ajouter des objets d'affichage enfants dans notre conteneur voiture, il faut utiliser la méthode addChild(enfant:DisplayObject):void fournie par la classe DisplayObjectContainer. Elle prend en paramètre l'enfant à ajouter dans le conteneur.

1
2
3
4
5
6
7
8
// Créons une roue
var roue:Sprite = new Sprite();
// Ajoutons-la dans la voiture
voiture.addChild(roue);

// Créons la rue et ajoutons la voiture dans la rue
var rue:Sprite = new Sprite();
rue.addChild(voiture);

L'objet roue1 est désormais affiché à l'intérieur du conteneur voiture, lui-même affiché dans le conteneur rue. Mais il manque quelque chose : il faut ajouter l'objet rue dans la scène principale, sinon il ne sera pas affiché ! ^^

Afficher un objet sur la scène principale

Dans notre projet, nous utilisons une classe principale que nous avons appelée Main (dans le fichier Main.as) :

 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
package {
    import flash.display.Sprite;
    import flash.events.Event;

    /**
     * ...
     * @author Guillaume
     */
    public class Main extends Sprite {

        public function Main():void {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point

            trace("Hello world !");
        }

    }

}

Regardez droit dans les yeux la déclaration de la classe Main : c'est une sous-classe de Sprite ! Notre classe principale est donc un conteneur, qui est automatiquement ajouté à la scène au démarrage de notre application ; ainsi, il ne nous reste plus qu'à ajouter nos objets dans le conteneur de classe Main qui nous est offert !

Pour ajouter notre rue sur la scène principale, nous procéderons ainsi :

1
this.addChild(rue);

Le code peut être raccourci en enlevant le mot-clé this :

1
addChild(rue);

Rappel : le mot-clé this permet d'accéder à l'objet courant. Si nous l'utilisons dans des méthodes non statiques de la classe Main, nous pointerons sur l'objet qui représente notre application. Il est toutefois possible d'omettre le mot-clé this si cela ne pose pas de problème de conflit de noms (typiquement, lorsque vous avez à la fois un attribut dans votre classe et un paramètre du même nom dans la méthode, il faut utiliser this pour accéder à l'attribut de la classe). Du coup, le code ci-dessus ne fonctionnera pas dans une autre classe ; il faudrait alors utiliser une variable pointant sur l'objet de la classe Main.

Voici le code complet de la classe Main :

 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
package {
    import flash.display.Sprite;
    import flash.events.Event;

    /**
     * ...
     * @author Guillaume
     */
    public class Main extends Sprite {

        public function Main():void {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point

            // Création du conteneur 'voiture'
            var voiture:Sprite = new Sprite();

            // Créons une roue
            var roue:Sprite = new Sprite();
            // Ajoutons-la dans la voiture
            voiture.addChild(roue);

            // Créons la rue et ajoutons la voiture dans la rue
            var rue:Sprite = new Sprite();
            rue.addChild(voiture);

            // On ajoute la rue sur la scène principale
            addChild(rue);
        }

    }

}

Si vous testez le code à ce stade, vous risquez d'être un peu déçus : en effet, les conteneurs sont vides par défaut ! Vous devrez vous contenter d'une triste scène vide, mais nous allons bientôt remédier à cela. ;)

Reprenons maintenant le schéma représentant l'arbre d'affichage, que nous avons détaillé plus haut (voir figure suivante).

L'arbre d'affichage de la voiture

Corrigeons-le pour y inclure notre objet de la classe Main (voir figure suivante).

L'arbre d'affichage de notre application

Un objet ne peut être affiché à deux endroits différents ; si jamais vous l'ajoutez à un conteneur alors que l'objet est déjà dans un autre conteneur, il sera automatiquement retiré de ce dernier avant d'être ajouté dans le nouveau conteneur.

L'index d'affichage

Cette notion correspond à l'ordre d'affichage des enfants dans un conteneur. Si un objet a un index plus grand qu'un autre, il sera affiché devant, et inversement. L'index est compris entre 0 et conteneur.numChildren - 1 (le nombre d'enfants moins un).

À la figure suivante par exemple, la voiture bleue est au-dessus des autres car elle a l'index d'affichage le plus élevé. En revanche, la voiture orange est tout en dessous car elle a un index égal à zéro.

L'index d'affichage de trois voitures superposées

Il est impossible de mettre un enfant à un index en dehors des bornes que nous avons définies : ainsi, on ne peut pas mettre un objet à un index inférieur à 0 ou supérieur à conteneur.numChildren - 1.

On peut obtenir l'index d'un enfant en utilisant la méthode getChildIndex():int (renvoyant un int), qui prend en paramètre l'objet enfant en question :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// On crée la rue
var rue:Sprite = new Sprite();

// On ajoute trois voiture dans la rue
var voiture1:Sprite = new Sprite();
rue.addChild(voiture1);

var voiture2:Sprite = new Sprite();
rue.addChild(voiture2);

var voiture3:Sprite = new Sprite();
rue.addChild(voiture3);

trace("La voiture1 est à l'index " + rue.getChildIndex(voiture1)); // Affiche 0
trace("La voiture2 est à l'index " + rue.getChildIndex(voiture2)); // Affiche 1
trace("La voiture3 est à l'index " + rue.getChildIndex(voiture3)); // Affiche 2

Ajouter un enfant à un index précis

Il existe une variante de la méthode addChild que nous avons vue il y a peu de temps. Il s'agit de la méthode addChildAt(enfant:DisplayObject, index:int):void, qui prend deux paramètres : l'enfant à ajouter, puis l'index d'affichage où il faut l'ajouter.

Voici un exemple, où l'on ajoute chaque nouvelle voiture en arrière-plan :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// On crée la rue
var rue:Sprite = new Sprite();

// On ajoute des voitures à la rue, en les mettant à l'arrière-plan à chaque fois
var voiture1:Sprite = new Sprite();
rue.addChildAt(voiture1, 0);

var voiture2:Sprite = new Sprite();
rue.addChildAt(voiture2, 0);

var voiture3:Sprite = new Sprite();
rue.addChildAt(voiture3, 0);

trace("La voiture1 est à l'index " + rue.getChildIndex(voiture1)); // Affiche 2
trace("La voiture2 est à l'index " + rue.getChildIndex(voiture2)); // Affiche 1
trace("La voiture3 est à l'index " + rue.getChildIndex(voiture3)); // Affiche 0

Comme vous pouvez le constater, l'index d'affichage de chaque objet varie, car il représente à tout instant la position en profondeur de celui-ci ; si jamais un objet passe derrière un autre par exemple, son index sera automatiquement modifié en conséquence !

Opérations sur les enfants

Nombre d'enfants

Pour obtenir le nombre d'enfants que contient un conteneur, vous pouvez utiliser le getter numChildren de type int.

Attention, c'est un attribut en lecture seule car aucun setter n'est défini dans la classe DisplayObjectContainer !

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// On crée une rue
var rue:Sprite = new Sprite();

// On ajoute trois voitures dans la rue
var voiture1:Sprite = new Sprite();
rue.addChild(voiture1);
var voiture2:Sprite = new Sprite();
rue.addChild(voiture2);
var voiture3:Sprite = new Sprite();
rue.addChild(voiture3);

trace("Il y a " + rue.numChildren + " voitures dans la rue."); // Affiche 3.

Accéder au parent d'un objet d'affichage

L'attribut parent permet d'accéder au conteneur parent qui contient l'objet d'affichage. Cette propriété est notamment utile à l'intérieur d'une classe, quand on ne peut pas savoir quel est le conteneur.

1
2
3
4
trace(rue == voiture1.parent); // Affiche true

trace("Nombre de voitures : " + rue.numChildren); // Affiche 3
trace("Nombre de voitures : " + voiture1.parent.numChildren); // Affiche 3 également

Modifier l'index d'un enfant

Une fois un objet d'affichage enfant ajouté à un conteneur, il est possible de modifier son index d'affichage. Pour cela, nous utiliserons la méthode setChildIndex(enfant:DisplayObject, index:int):void qui prend en paramètre l'enfant en question puis son nouvel index.

1
2
3
4
5
6
7
8
// On met successivement les voitures au premier-plan
rue.setChildIndex(voiture1, 2);
rue.setChildIndex(voiture2, 2);
rue.setChildIndex(voiture3, 2);

trace("La voiture1 est à l'index " + rue.getChildIndex(voiture1)); // Affiche 0
trace("La voiture2 est à l'index " + rue.getChildIndex(voiture2)); // Affiche 1
trace("La voiture3 est à l'index " + rue.getChildIndex(voiture3)); // Affiche 2

Rappel : la valeur de l'index doit être située entre 0 et conteneur.numChildren - 1 !

Échanger les index d'affichage de deux enfants

Il existe deux méthodes de la classe DisplayObjectContainer pour échanger la profondeur de deux objets enfants : swapChildren() qui prend en paramètre deux références des enfants du conteneur et swapChildrenAt() qui prend en paramètre deux index différents à échanger.

1
2
3
4
5
6
7
8
9
rue.swapChildren(voiture1, voiture2);
trace("La voiture1 est à l'index " + rue.getChildIndex(voiture1)); // Affiche 1
trace("La voiture2 est à l'index " + rue.getChildIndex(voiture2)); // Affiche 0
// La voiture 1 est affichée devant la voiture 2

rue.swapChildrenAt(0, 1);
trace("La voiture1 est à l'index " + rue.getChildIndex(voiture1)); // Affiche 0
trace("La voiture2 est à l'index " + rue.getChildIndex(voiture2)); // Affiche 1
// La voiture 1 est affichée en dessous de la voiture 2

Déterminer si un objet est enfant d'un conteneur

Une méthode très pratique de la classe DisplayObjectContainer renvoie un booléen pour le savoir : j'ai nommé contains() ! Elle prend en paramètre un objet de la classe DisplayObject et retourne true si cet objet est dans la liste d'affichage du conteneur (y compris parmi les petits-enfants, parmi les enfants des petits-enfants, etc.), ou s'il s'agit du conteneur lui-même (nous considérons que le conteneur se contient lui-même). Sinon, elle renvoie false.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var sprite1:Sprite = new Sprite();
var sprite2:Sprite = new Sprite();
var sprite3:Sprite = new Sprite();
var sprite4:Sprite = new Sprite();

sprite1.addChild(sprite2);
sprite2.addChild(sprite3);

trace(sprite1.contains(sprite1)); // Affiche: true
trace(sprite1.contains(sprite2)); // Affiche: true
trace(sprite1.contains(sprite3)); // Affiche: true
trace(sprite1.contains(sprite4)); // Affiche: false

Retirer des enfants

Pour retirer un enfant d'un parent, la méthode removeChild(enfant:DisplayObject):void est toute indiquée ! À l'instar de la méthode addChild(), cette fonction prend en paramètre l'enfant à enlever de l'affichage.

1
2
3
4
// On enlève les trois voitures de la rue
rue.removeChild(voiture1);
rue.removeChild(voiture2);
rue.removeChild(voiture3);

Il est également possible de supprimer un enfant à un certain index, sans savoir précisément duquel il s'agit, à l'aide de la méthode removeChildAt(index:int):void. Le paramètre que nous passons correspond à l'index de l'enfant que nous souhaitons enlever.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// On crée la rue
var rue:Sprite = new Sprite();

// On ajoute des voitures à la rue, en les mettant à l'arrière-plan à chaque fois
var voiture1:Sprite = new Sprite();
rue.addChildAt(voiture1, 0);

var voiture2:Sprite = new Sprite();
rue.addChildAt(voiture2, 0);

var voiture3:Sprite = new Sprite();
rue.addChildAt(voiture3, 0);

trace("La voiture1 est à l'index " + rue.getChildIndex(voiture1)); // Affiche 2
trace("La voiture2 est à l'index " + rue.getChildIndex(voiture2)); // Affiche 1
trace("La voiture3 est à l'index " + rue.getChildIndex(voiture3)); // Affiche 0

// On enlève a voiture le plus au fond
rue.removeChildAt(0); // voiture3 enlevée !

// On peut enlever les deux autres de la même manière
rue.removeChildAt(0); // voiture2 enlevée !
rue.removeChildAt(0); // voiture1 enlevée !

Et si on souhaite enlever tous les enfants du conteneur, n'y a-t-il pas un moyen moins fastidieux ?

La réponse est oui, grâce à la méthode removeChildren(beginIndex:int = 0, endIndex:int = 0x7fffffff):void qui permet de supprimer plusieurs enfants d'un coup d'un seul ! Les deux paramètres facultatifs spécifient à partir de quel index on supprime, et jusqu'à quel index. Par défaut, tous les enfants sont supprimés, donc si c'est ce que vous souhaitez faire, laissez les parenthèses vides. ;)

1
rue.removeChildren(); // Toutes les voitures sont enlevées d'un coup !

Propriétés utiles des objets d'affichage

Nous allons maintenant aborder des propriétés communes à tous les objets d'affichage, qui s'avèreront très utiles ! Toutefois, nous nous limiterons pour l'instant à l'affichage 2D dans le repère mentionné en début de chapitre.

Les attributs et méthodes que nous allons voir sont des propriétés de la classe DisplayObject, dont la documentation est disponible ici.

Position

Tout d'abord, commençons par la position de l'objet d'affichage : deux attributs, x et y, permettent de contrôler respectivement la position horizontale et verticale de l'origine d'un objet d'affichage.

Reprenons l'exemple de l'introduction, visible à la figure suivante.

Exemple de position sur l'écran

Pour déplacer l'origine d'un objet à cet endroit précis (5, 6), nous écrirons ceci :

1
2
3
4
5
var monObjet:Sprite = new Sprite();
// Modifions la position de l'objet !
monObjet.x = 5;
monObjet.y = 6;
addChild(monObjet);

La position par défaut de tout nouvel objet d'affichage est (0, 0), c'est-à-dire que x vaut 0 et que y vaut 0 si vous n'y touchez pas.

Un mot sur l'origine

L'origine d'un objet d'affichage est le point qui représente sa position actuelle. Par défaut, elle est située en haut à gauche (voir figure suivante), et elle ne peut pas être déplacée.

L'origine est en haut à gauche par défaut

Rotation du conteneur avec l'origine par défaut

Comment modifier l'origine de notre conteneur si on ne peut pas la déplacer ?

Et bien, c'est très simple, il suffit de déplacer les enfants à l'intérieur de notre conteneur, pour donner l'illusion de modifier l'origine (voir figure suivante) !

On déplace l'image de voiture à l'intérieur du conteneur

Et c'est gagné (voir figure suivante) !

Rotation du conteneur avec la nouvelle origine

L'affichage à l'écran de la voiture à la position (0, 0) ressemblerait alors à la figure suivante.

Dans le cas de l'origine par défaut

Dans le cas où l'on a centré l'origine

Par exemple, si vous ajoutez un objet d'affichage voiture dans votre conteneur rue, et que vous positionnez la voiture en négatif à 100 pixels de l'origine de la rue, une partie de votre voiture sera très certainement en dehors de l'écran. Mais l'origine de la rue n'a pas changé entre-temps : elle est toujours à sa position de départ (0, 0). Maintenant, vous pouvez faire réapparaître la voiture en entier en déplaçant la rue de 100 pixels vers la droite ! Son origine va ainsi changer et devenir (100, 0), ainsi la position de la voiture par rapport à la scène sera (0, 0) ! Tout est relatif ! ;)

Taille

Taille absolue

La taille absolue d'un objet d'affichage, c'est-à-dire la taille qu'il prend à l'écran, peut être lue ou modifiée à l'aide des attributs width (longueur) et height (hauteur), en pixels. La taille est toujours exprimée en valeurs positives.

1
2
3
4
5
var maVoiture:Voiture= new Voiture();
// Modifions la taille de la voiture pour qu'elle fasse 100x100 pixels !
maVoiture.width = 100;
maVoiture.height = 100;
addChild(maVoiture);

Modifier la taille d'un conteneur vide et sans dessin n'a aucun sens, et ne donnera aucun résultat. Ses deux attributs width et height seront toujours égaux à 0.

Taille relative

On peut également redimensionner un objet d'affichage à l'aide de pourcentages, grâces aux attributs scaleX pour redimensionner en longueur, et scaleY en hauteur. Les pourcentages ne sont pas directement exprimés en tant que tel : par exemple, scaleX = 1 signifie que la longueur de l'objet est à 100%, scaleY = 2 signifie que l'objet est deux fois plus haut que sa taille absolue d'origine et scaleY = 0.5 signifie que l'objet est moitié moins haut.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
var maVoiture:Voiture= new Voiture();
// Modifions la taille de la voiture pour qu'elle fasse 100x100 pixels !
maVoiture.width = 100;
maVoiture.height = 100;

// Réduisons la taille de la voiture de moitié !
maVoiture.scaleX = 0.5;
maVoiture.scaleY = 0.5;
trace(maVoiture.width); // Affiche: 50
trace(maVoiture.height); // Affiche: 50

// Remettons-là à sa taille normale :
maVoiture.scaleX = 1;
maVoiture.scaleY = 1;
trace(maVoiture.width); // Affiche: 100
trace(maVoiture.height); // Affiche: 100
addChild(maVoiture);

Avec ses propriétés, il est possible d'inverser un objet d'affichage à l'aide de valeurs négatives :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var maVoiture:Voiture= new Voiture();
// Modifions la taille de la voiture pour qu'elle fasse 100x100 pixels !
maVoiture.width = 100;
maVoiture.height = 100;

// Inversons horizontalement la voiture !
maVoiture.scaleX = -1;
trace(maVoiture.width); // Affiche: 100
trace(maVoiture.height); // Affiche: 100
addChild(maVoiture);

Rappel : les attributs de taille width et height sont toujours positifs.

Rotation

L'attribut rotation permet de faire tourner des objets d'affichage autour de leur origine (voir figure suivante), en utilisant des degrés. Les valeurs comprises entre 0 et 180 représentent la rotation en sens horaire ; les valeurs comprises entre 0 et -180 représentent la rotation en sens antihoraire. Les valeurs hors de cette plage sont alors réajustées (ajoutées ou soustraites de 360) pour obtenir une valeur comprise dans la plage. Par exemple, l’instruction voiture.rotation = 400 correspond à voiture.rotation = 40 (car 400 - 360 = 40).

Rotation d'un objet (avec l'origine par défaut)

Si vous voulez utiliser des valeurs en radians, il ne faut pas oublier de les convertir en degrés avant d'utiliser l'attribut rotation : on écrira par exemple voiture.rotation = maValeurEnRadians / Math.PI * 180; en utilisant la constant Math.PI qui contient une valeur assez précise du nombre pi.

Transparence

Visibilité

L'attribut visible vaut true si l'objet est visible, false s'il est invisible. Par défaut, sa valeur est true (l'objet est visible).

1
2
3
4
var maVoiture:Voiture= new Voiture();
// Rien ne sera affiché à l'écran
maVoiture.visible = false;
addChild(maVoiture);

Un objet d'affichage avec une visibilité à faux n'est pas du tout rendu à l'écran, et ne peut donc pas interagir avec la souris par exemple. Cela permet toutefois d'économiser des ressources de l'ordinateur pour améliorer les performances. Un bon conseil : si un objet doit être invisible, utilisez cette propriété à chaque fois que vous le pouvez ! ;)

Opacité

L'attribut alpha de type Number détermine l'opacité d'un objet d'affichage, c'est-à-dire s'il est plus ou moins transparent. Les valeurs vont de 0 (invisible) à 1 (opaque).

1
2
3
4
var maVoiture:Sprite = new Sprite();
// La voiture sera à moitié transparente
maVoiture.alpha = 0.5;
addChild(maVoiture);

L'opacité d'un conteneur est un multiplicateur de l'opacité de tous ces enfants, et ainsi de suite. Par exemple, si un enfant a une opacité de 0.5, et que le conteneur a une opacité de 0.5, l'opacité réelle de l'enfant sera de 0.5 x 0.5 = 0.25 : l'enfant est donc à trois quarts transparent.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var enfant:Sprite = new Voiture();
// L'enfant sera à moitié transparent
enfant.alpha = 0.5;

var conteneur:Sprite = new Sprite();
// Le conteneur sera aussi à moitié transparent
conteneur.alpha = 0.5;
conteneur.addChild(maVoiture);

// Au final, l'opacité de l'enfant vaut 0.25

Il est possible de mettre une valeur supérieure à 1 : cela aura pour effet d'augmenter l'opacité des enfants de l'objet. Par exemple, si un enfant a pour opacité 0.5, et que l'on met l'opacité de son conteneur à 2, l'opacité de l'enfant réelle sera 0.5 x 2 = 1 : l'enfant est donc entièrement opaque.

Un objet visible mais transparent (c'est-à-dire que sa visibilité est à vrai mais que son opacité est à 0) est quand même rendu à l'écran, et donc consomme des ressources de l'ordinateur. Toutefois, il reste interactif, il est possible de cliquer dessus par exemple.

Supprimer un objet d'affichage de la mémoire

À ce stade du cours, pour supprimer un objet d'affichage de la mémoire, il est nécessaire de respecter les points suivants :

  • l'objet ne doit pas faire partie de la liste d'affichage, c'est-à-dire qu'il ne doit pas être l'enfant d'un conteneur ;
  • il ne doit plus y avoir une seule référence à cet objet.

Nous étofferons cette liste au fur-et-à-mesure du cours, lorsque nous aborderons de nouvelles notions, afin que vous soyez experts en mémoire non-saturée ! ;)

Pour supprimer un objet de la liste d'affichage, vous pouvez utiliser la méthode removeChild() de la classe DisplayObjectContainer :

1
2
3
4
var maVoiture:Voiture = new Voiture();
rue.addChild(maVoiture);
// Supprimons la voiture de la liste d'affichage
rue.removeChild(maVoiture);

L'objet en question doit être un enfant du conteneur, sinon, une erreur sera envoyée à l'appel de la méthode removeChild().

Si jamais vous voulez supprimer l'objet d'affichage depuis sa propre classe, il faut utiliser l'attribut parent et ruser un peu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package
{
    import flash.display.Sprite;

    public class Voiture extends Sprite
    {
        public function Voiture()
        {

        }

        public function removeFromParent():void
        {
            // Vérifions que la voiture est sur la liste d'affichage (cad. que le parent existe) avant d'appeler removeChild()
            if (parent != null)
            {
                // Supprimons l'objet de la liste d'affichage
                parent.removeChild(this);
            }
        }
    }

}

Mais comment supprimer une référence à un objet ?

C'est très simple : il suffit d'affecter la variable en question avec le mot-clé null :

1
2
3
4
5
6
var maVoiture:Voiture = new Voiture();
rue.addChild(maVoiture);
// Supprimons la voiture de la liste d'affichage
rue.removeChild(maVoiture);
// Supprimons la référence à la voiture !
maVoiture = null;

À ce stade, l'objet de la classe Voiture n'a pas encore été supprimé : il est encore dans la mémoire de votre ordinateur. Il sera effectivement supprimé lorsque le ramasse-miette (garbage-collector en anglais) sera passé pour nettoyer la mémoire. Seulement, pour que le ramasse-miette puisse faire son travail, et déterminer quels objets doivent être supprimés, il faut respecter les points énumérés ci-dessus. On dit alors que ces objets sont éligibles au nettoyage par le ramasse-miette.

Vous remarquerez ainsi qu'il n'existe aucun moyen de supprimer un objet directement de la mémoire, sauf pour quelques rares exceptions. La plupart du temps, il faut laisser le ramasse-miette le faire à notre place. Cela marche donc pour tous les objets, pas seulement les objets d'affichage ; mais dans ce cas, inutile d'essayer de retirer de la liste d'affichage des objets qui n'ont rien à voir ! Supprimer leurs références suffit pour l'instant. ;)


En résumé

  • En ActionScript 3, les couleurs sont décrites en notation hexadécimale, précédées des caractères 0x ('zéro' et 'x').
  • L'affichage à un écran se fait dans un repère partant du coin supérieur gauche de l'écran. Les coordonnés en x vont de gauche à droite, et en y de haut en bas.
  • Les objets d'affichage sont contenus dans un arbre : ils peuvent contenir chacun des enfants pouvant eux-même contenir d'autres enfants.
  • On peut manipuler les enfants des conteneurs à l'aide des propriétés de la classe DisplayObjectContainer.
  • Une multitude de propriétés de la classe DisplayObject permettent de manipuler les objets d'affichage.
  • Il faut respecter quelques consignes pour qu'un objet d'affichage soit supprimé de la mémoire par le ramasse-miette.