• 12 heures
  • {0} Facile|{1} Moyenne|{2} Difficile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Mis à jour le 30/04/2014

Dessiner avec l'Actionscript

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans ce chapitre, nous allons apprendre à dessiner directement depuis l'Actionscript ! Je suis certain que beaucoup parmi vous attendaient ce moment depuis fort longtemps, c'est pourquoi nous essaierons de présenter un maximum de notions tout en prenant le temps de bien les expliquer. Nous présenterons en premier la classe Graphics qui est à l'origine de tout tracé en Actionscript. Puis nous présenterons alors les différentes méthodes de dessin que possède cette classe.

Enfin, je vous proposerais un petit exercice où nous réaliserons ensemble une illustration d'un mouton. Ce sera alors l'occasion de revenir sur ces méthodes de dessin et mieux comprendre toute la philosophie qui se cache derrière le dessin en Flash !

L'objet Graphics

Introduction

Une propriété de type Graphics

Nous avons vu précédemment qu'il existait différents types d'objets d'affichage. Parmi eux, certains possèdent déjà tout le nécessaire pour dessiner. Il s'agit des classes Shape, Sprite et MovieClip (voir figure suivante) !

La classe Shape dans l'arbre des classes d'affichage
La classe Shape dans l'arbre des classes d'affichage

Ce qui les différencie des autres classes c'est que celles-ci ont un attribut très particulier : une instance de la classeGraphics. En réalité, c'est cette dernière classe qui dispose de l'ensemble des méthodes permettant de tracer différentes formes. Ainsi, en déclarant des objets de type Shape, Sprite ou MovieClip, vous pourrez dessiner à l'intérieur de ceux-ci. En particulier, la classe Shape est spécialement faite pour cela puisque celle-ci ne contient que cet attribut et l'accesseur correspondant comme vous pouvez le voir à la figure suivante.

La classe Shape exclusivement utilisé pour sa propriété graphics
La classe Shape exclusivement utilisé pour sa propriété graphics

Cette classe est allégée, ce qui implique de meilleures performances, mais une instance de la classe Shape ne peut pas contenir d'enfants et elle n'est pas interactive (il est impossible de savoir si l'utilisateur clique dessus).

Pourquoi ne pas utiliser directement l'objet Graphics ?

Il se peut que vous vous soyez déjà demandé pourquoi ne pas créer directement une occurrence de la classe Graphics et utiliser ainsi ses différentes méthodes de dessin. En réalité, l'Actionscript favorise l'utilisation des sous-classes de DisplayObject dont n'hérite pas la classe Graphics. C'est pourquoi celle-ci est non instanciable : vous ne pourrez donc pas utiliser la syntaxe « new Graphics() » et vous serez donc obligés de passer par l'utilisation de l'une des trois classes décrites plus haut. De plus, elle est de type final, ce qui signifie que l'on ne peut pas créer de sous-classes héritant de la classe Graphics.

Je vous invite donc à créer une instance de la classe Shape que nous utiliserons dans la suite :

var monDessin:Shape = new Shape();
Dessin vectoriel

La classe Graphics est utilisée pour créer des dessins vectoriels !
Ce terme est peut-être nouveau pour vous, mais ne vous inquiétez pas, nous allons ici présenter ce qui différencie ce type d'images par rapport aux images « bitmap ». Vous ne vous êtes jamais demandés comment les images étaient stockées à l'intérieur de votre ordinateur ?
En fait le stockage des images peut être réalisé de deux manières différentes. Lorsque l'on parle d'images « bitmap », celles-ci sont enregistrées à partir des couleurs de chacun des pixels. En revanche, dans les images vectorielles, ce sont les formes en elles-mêmes qui sont sauvegardées. Cela fait donc une énorme différence lors de la lecture du fichier et de l'affichage à l'écran.

Pour mieux comprendre ce dont il s'agit, nous allons prendre l'exemple de la figure suivante.

Image de base
Image de base

Cette image est quelconque et pourrait très bien être enregistrée en tant qu'image « bitmap » ou vectorielle. L’inconvénient du format « bitmap » est justement qu'il retient des pixels. Ainsi, si vous ne respectez plus les dimensions des pixels, l'image va être déformée. Je m'explique ; imaginez que vous ayez besoin, pour une raison quelconque, d'agrandir votre image. Les pixels vont donc être redimensionnés et l'image n'aura plus l'aspect lisse qu'elle avait au départ. Au contraire, une image vectorielle est définie à partir de formes. Ainsi, lorsque celle-ci va être redimensionnée, l'affichage sera adapté pour correspondre à nouveau à la forme désirée.

Voyez plutôt la différence à la figure suivante entre l'image « bitmap » à gauche et l'image vectorielle à droite, toutes les deux redimensionnées à 300%.

Redimensionnement de l'image de base
Redimensionnement de l'image de base

Dans ce chapitre, nous allons donc parler exclusivement de dessin vectoriel, l'un des atouts de cette technologie Flash !

Des contours et des remplissages

Le principe

Si vous avez déjà utilisé des classes de dessin dans d'autres langages de programmation, vous allez voir qu'ici le principe est assez différent. Avant d'entrer plus avant dans les détails, je vous invite à découvrir les différents termes que nous serons amenés à utiliser dans la suite de ce chapitre. Pour cela je vous propose tout d'abord un petit dessin d'exemple à la figure suivante.

Composition d'un élément graphique
Composition d'un élément graphique

Dans cet exemple, nous pouvons voir une bulle de pensée comme on en trouve dans les bandes dessinées. Cette bulle est composée de 4 objets : un « nuage » et trois ovales. Ces objets correspondent à des tracés différents qu'il faudrait réaliser les uns après les autres.
Chaque tracé est donc défini de la façon suivante :

  • Le remplissage : surface représentée en bleu sur le dessin précédent.

  • Le contour : ligne qui délimite le remplissage.

  • La ligne : trait visible qui suit le contour et pouvant avoir différentes apparences.

Ainsi, pour réaliser un tracé en Flash, il nous faut définir le contour de celui-ci en indiquant quel style adopter pour le remplissage et la ligne.

Définir le style des lignes

Tout d'abord, veuillez noter que nous parlons ici de lignes et non de contours, il s'agit donc uniquement du côté esthétique des traits qui effectivement suivent le contour.
Pour définir le style des lignes, nous utiliserons la méthode lineStyle() de la classe Graphics. Cette méthode possède beaucoup de paramètres, mais tous sont facultatifs. C'est pourquoi, je ne vous parlerai ici que des trois premiers qui sont les plus intéressants. Le premier sert à définir la largeur de la ligne, le deuxième sa couleur, et enfin le dernier permet de préciser l'opacité de celle-ci.
Voici un exemple dans lequel nous définissons des lignes de largeur 2, de couleur noire et transparentes à 50% :

monDessin.graphics.lineStyle(2, 0x000000, 0.5);

Comme nous l'avons dit, la méthode lineStyle() ne possède que des paramètres facultatifs. Ainsi, si vous ne souhaitez pas de lignes sur votre tracé mais uniquement un remplissage, il vous suffit d'utiliser cette méthode sans paramètres, comme ceci :

monDessin.graphics.lineStyle();
Définir un remplissage

Contrairement aux lignes, les remplissages nécessitent l'utilisation de deux méthodes : beginFill() et endFill().
La première permet de définir les différentes caractéristiques du remplissage, à savoir sa couleur et son opacité. En revanche, dans notre cas de figure, la couleur est un paramètre obligatoire et ne peut donc pas être omise. Voici par exemple comment définir une couleur blanche au remplissage :

monDessin.graphics.beginFill(0xFFFFFF);

L'utilisation de la seconde méthode est justifiée par la définition même d'un remplissage. En effet, pour remplir l'intérieur d'un contour, celui-ci doit être fermé !
La méthode endFill() sert donc à refermer un contour, pour pouvoir lui appliquer un remplissage. Ainsi, si lors du tracé de votre contour, le point final n'est pas identique au premier, une ligne droite sera alors tracée entre ces deux points pour fermer le contour.
Cette méthode endFill() ne prend aucun paramètre et s'utilise donc simplement de la manière suivante :

monDessin.graphics.endFill();

Dessinez, c'est gagné !

Ça y est, vous allez enfin pouvoir dessiner en Actionscript ! :lol:
Nous allons maintenant voir quelles sont les différentes méthodes de la classe Graphics, et apprendre à nous en servir. Ensuite, nous réaliserons un petit exercice à la fin de ce chapitre qui devrait vous aider à mieux utiliser cette classe.

Les lignes et les courbes

Une histoire de curseur

À l'origine, l'ensemble des tracés en Flash étaient conçus à l'intérieur du logiciel Flash Professionnal. Ceux-ci étaient donc réalisés graphiquement à l'aide de votre souris, aussi connue sous le nom de curseur. Depuis l'arrivée de l'Actionscript 3, il n'est plus nécessaire de posséder le logiciel pour pouvoir effectuer des tracés. En effet, il est maintenant possible de faire exactement la même chose grâce au code. Cependant, les instructions s'exécutent en conservant la logique utilisée pour dessiner dans le logiciel.

Ainsi, lorsque vous dessinerez en Actionscript, vous devrez imaginez les différents gestes que vous réaliseriez avec la souris de votre ordinateur. Par exemple, si vous souhaitez tracer une ligne, vous déplacerez d'abord votre curseur à l'endroit où vous voudrez démarrer celle-ci, puis vous la tracerez. Une fois celle-ci dessinée, votre curseur se trouverait alors à l'autre extrémité de la ligne. Vous pourriez alors continuer votre tracé à partir du même point ou bien déplacer avant votre curseur vers une autre partie de l'écran.

Revenons maintenant à ce qui nous intéresse : l'Actionscript !
Lorsque vous dessinez grâce à la classe Graphics, vous disposez un curseur fictif que vous pouvez déplacer n'importe où sur l'écran. Pour modifier la position de celui-ci, vous devez utiliser la méthode moveTo() en spécifiant le nouvel emplacement, comme ci-dessous :

var _x:Number = 25;
var _y:Number = 50;
monDessin.graphics.moveTo(_x, _y);
Les lignes droites

Pour réaliser des contours, il est possible de créer des lignes droites. Pour cela, la classe Graphics dispose de la méthode lineTo(), qui trace une ligne entre la position actuelle du curseur et le nouveau point spécifié en paramètre. Voici un exemple qui permet de tracer une droite horizontale d'épaisseur 10 entre les points de coordonnées (10,10) et (10,100) :

monDessin.graphics.lineStyle(10, 0x000000);
monDessin.graphics.moveTo(10, 10);
monDessin.graphics.lineTo(200, 10);

Si vous lancez votre projet, vous verrez apparaître la belle ligne visible à la figure suivante.

Une ligne
Une ligne

À la suite de votre ligne horizontale, vous pourriez très bien continuer le tracé de votre contour avec une ligne verticale par exemple :

monDessin.graphics.lineTo(200, 200); // Le curseur est à la position (200,10) avant l'instruction
Les courbes

Les lignes droites c'est bien, mais celles-ci sont vite limitées lorsqu'il s'agit de réaliser un dessin complexe avec des formes arrondies. Par conséquent, il a été mis en place ce qu'on appelle les courbes de Bézier !
Le principe de ces courbes est d'utiliser un point de contrôle en plus des deux points d’ancrage. Ce point de contrôle sert à définir la courbure de la ligne en direction de ce point. Pour mieux comprendre l'effet de celui-ci sur la courbe, je vous propose un exemple :

monDessin.graphics.lineStyle(4, 0x000000);
monDessin.graphics.beginFill(0x55BBFF);
monDessin.graphics.moveTo(10, 100);
monDessin.graphics.curveTo(100, 10, 200, 100);
monDessin.graphics.endFill();

Ici, la méthode curveTo() prend deux paires de coordonnées en paramètres. La première correspond au point de contrôle et la seconde au point d'ancrage final. Voyez plutôt à la figure suivante le résultat du tracé où j'ai ajouté les trois points.

Une courbe décrite par trois points
Une courbe décrite par trois points

Les formes prédéfinies

Pour les formes géométriques particulières, il existe des méthodes permettant de simplifier leur tracé. Nous pouvons notamment citer les cercles, les ellipses et les rectangles.

Les formes elliptiques

Lorsqu'on parle de formes elliptiques, on inclut généralement les cercles et les ellipses. Nous allons donc voir à présent comment tracer chacune de ces formes.
Tout d'abord, occupons-nous des cercles. Nous disposons pour cela d'une méthode nommée drawCircle(), dans laquelle nous devons spécifier les coordonnées x et y du centre du cercle ainsi que le rayon r de celui-ci :

monDessin.graphics.drawCircle(x, y, r);

Pour les ellipses, la méthode a utiliser est drawEllipse(). Celle-ci prend cette fois quatre paramètres différents : la largeur et la hauteur de l'ellipse ainsi que les coordonnées x et y du coin supérieur gauche de la zone à tracer :

monDessin.graphics.drawEllipse(x, y, largeur, hauteur);

Nous verrons dans l'exercice à venir comment utiliser ces fonctions, mais je vous invite grandement à faire des tests de votre côté pour bien voir l'influence des différents paramètres. N'oubliez pas également de définir un style de ligne ou un remplissage avant l'utilisation de telles méthodes.

Les rectangles

En plus des formes elliptiques, la classe Graphics vous permet de tracer des formes rectangulaires. La méthode drawRect() est ainsi définie exactement de la même façon que drawEllipse(), à la seule différence qu'elle trace cette fois un rectangle.
L'instruction ci-dessous ne présente donc aucune surprise :

monDessin.graphics.drawRect(x, y, largeur, hauteur);

Il se peut que vous ayez besoin, à un moment ou à un autre, de tracer un rectangle dont les angles sont arrondis. Pour cela, vous disposez également de la méthode drawRoundRect(), où vous devrez renseigner en plus la valeur de l'arrondi :

monDessin.graphics.drawRoundRect(x, y, largeur, hauteur, arrondi);

Techniques avancées

Dessiner une trajectoire

Lorsque vous créerez des contours à l'aide des méthodes lineTo() et curveTo(), il est probable que vous ayez une série d'instructions similaires afin de parcourir l'ensemble de votre contour. C'est pourquoi, il existe une méthode drawPath() qui permet d'effectuer l'ensemble de ces tracés en une seule instruction.
Cette méthode prend donc en paramètres deux tableaux de type Vector.<int> et Vector.<Number>. Le premier permet de définir le type de commande, quant au second, il contient l'ensemble des coordonnées des différents points d'ancrage et points de contrôle. En ce qui concerne les commandes, celles-ci sont définies comme suit :

  • 1moveTo().

  • 2lineTo().

  • 3curveTo().

Pour mieux comprendre ce dont il est question, je vous propose de prendre l'exemple suivant :

monDessin.graphics.lineStyle(2, 0x000000);
monDessin.graphics.moveTo(0, 0);
monDessin.graphics.lineTo(100, 0);
monDessin.graphics.curveTo(200, 0, 200, 100);

L'ensemble de ces tracés pourrait également être réalisés grâce à la méthode drawPath() de la façon suivante :

var commandes:Vector.<int> = new Vector.<int>();
commandes.push(1, 2, 3);
var coordonnees:Vector.<Number> = new Vector.<Number>();
coordonnees.push(0, 0);
coordonnees.push(100, 0);
coordonnees.push(200, 0, 200, 100);
monDessin.graphics.lineStyle(2, 0x000000);
mouton.graphics.drawPath(commandes, coordonnees);

N'est-ce pas plus compliqué et plus long au final ?

Je vous avoue que cette écriture fait peur et est au final plus longue à écrire que la version originale. Cependant, mettez-vous en tête que cette nouvelle version s'exécute plus rapidement que la précédente. Ceci vient du fait que le tracé à l'écran se fait en une seule fois contrairement au premier code où il faut retracer à chaque instruction. Utilisez donc cette méthode au maximum dès que vous le pouvez.

Superposition de remplissages

Lorsque vous tracez différents contours, ceux-ci peuvent être amenés à se superposer. Dans ce cas, il est alors possible de supprimer le remplissage dans la zone de superposition. Pour cela, définissez les deux contours à l'intérieur d'un même remplissage, c'est-à-dire sans fermeture du contour entre les deux par la fonction endFill().
Pour vous montrer l'effet créé, voici le code que je vous invite à tester :

monDessin.graphics.lineStyle(4, 0x000000);
monDessin.graphics.beginFill(0x0000FF);
monDessin.graphics.drawCircle(100, 100, 50);
monDessin.graphics.drawCircle(175, 100, 50);
monDessin.graphics.endFill();

Vous verrez alors deux disques de couleur bleu dont l'intersection est non remplie comme sur la figure suivante.

Exclusion des deux cercles
Exclusion des deux cercles
Un petit pas vers la 3D

Avant de terminer la théorie sur cette classe Graphics, je vais rapidement vous parler d'une méthode un peu spéciale : drawTriangles().
Comme son nom l'indique, cette méthode permet de dessiner des triangles. Cette manière de découper une géométrie en faces triangulaires, est une pratique courante lorsqu'il s'agit de 3D. Cela permet notamment de pouvoir déformer une image en la divisant sur plusieurs faces orientées différemment. Ainsi, il est possible d'appliquer ce que l'on appelle une texture, sur un objet 3D modélisé à partir d'une multitude de faces.

Dans ce chapitre, nous n'aborderons pas toutes ces techniques qui sont un peu trop avancées pour nous. Toutefois, je vais vous présenter tout de même comment utiliser cette méthode drawTriangles() avec des lignes et des remplissages. Le principe est de créer une liste de points que nous nommerons des sommets, à l'intérieur d'un tableau de type Vector.<Number> contenant leurs coordonnées. Ces sommets sont alors numérotés dans l'ordre de leur déclaration avec pour premier indice 0. Un second tableau de type Vector.<int> permet ensuite créer des triangles en reliant les sommets par trois. Ainsi, le premier triangle est généralement constitué des sommets 0, 1 et 2.

Conscient que tout cela est certainement encore flou dans votre tête, je vous propose un petit exemple où nous aurons 5 sommets. Ensuite, nous allons créer quatre triangles composés respectivement des sommets (0,1,2), (1,2,3), (2,3,4) et enfin (2,4,5). Voici le code correspondant à ces manipulations :

var sommets:Vector.<Number> = Vector.<Number>([10, 10, 10, 100, 100, 10, 100, 100, 190, 100, 190, 10]);
var indices:Vector.<int> = Vector.<int>([0, 1, 2, 1, 2, 3, 2, 3, 4, 2, 4, 5]);
monDessin.graphics.lineStyle(4, 0x000000);
monDessin.graphics.beginFill(0xAA00FF); 
monDessin.graphics.drawTriangles(sommets, indices);
monDessin.graphics.endFill();

Vous verrez donc apparaître nos quatre triangles formant ensemble un rectangle qui pourrait être la base de la modélisation d'un intérieur quelconque par exemple. Voyez à la figure suivante l'affichage correspondant, où j'ai volontairement rajouté les indices des sommets pour que vous puissiez mieux comprendre :

Conception à base de triangles
Conception à base de triangles

Exercice : Dessine-moi un mouton

Conception du dessin

Introduction

Dans cet exercice, nous allons réaliser une petite illustration représentant un mouton, pas à pas.

Avant de nous lancer tête baissée, je vous invite à préparer votre projet afin d'obtenir un résultat similaire au mien à la fin de l'exercice. Vous allez donc changer les dimensions de votre scène principale pour que celle-ci fasse 280 x 220 pixels. Vous pouvez laisser la couleur d'arrière-plan en blanc étant donné que nous allons redéfinir un fond dans peu de temps.
Nous allons également déclarer deux variables _x et _y pour contrôler la position du mouton, puis une variable Mouton de type Shape qui nous servira à effectuer l'ensemble de nos tracés. Enfin, n'oubliez pas d'ajouter notre Mouton à notre conteneur principal grâce à la fonction addChild().

Voici donc notre classe Main au début de l'exercice :

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.display.Shape;
    
    public class Main extends Sprite 
    {
        private var _x:int;
        private var _y:int;
        
        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
            _x = 160;
            _y = 40;
            var mouton:Shape = new Shape();
                        
            this.addChild(mouton);
        }
        	
    }
    
}
Le fond

Afin de faire ressortir notre mouton blanc, nous allons tracer une zone rectangulaire de couleur bleue comme arrière-plan de notre dessin. Pour cela, nous nous servirons de la fonction drawRoundRect() qui permet d'obtenir un rectangle aux coins arrondis, ce qui rendra l'ensemble plus esthétique.
Ici, aucune difficulté, nous aurons donc le code suivant :

// Fond
mouton.graphics.beginFill(0x10879D);
mouton.graphics.drawRoundRect(0, 0, 280, 220, 40, 40);
mouton.graphics.endFill();
Le corps

La réalisation du corps du mouton est certainement la partie la plus longue et fastidieuse de cet exercice. Néanmoins, j'ai déjà effectué l'opération, vous n'aurez donc qu'à suivre mes instructions.
Pour dessiner le corps du mouton, nous allons dans un premier temps définir les différents paramètres de remplissage et de contour. Puis, nous commencerons par tracer une courbe de Bézier qui sera le point de départ pour la suite. Voici donc un premier bout de code :

// Corps
mouton.graphics.lineStyle(4, 0x3A281E, 1.0);
mouton.graphics.beginFill(0xFFFFFF);
mouton.graphics.moveTo(_x, _y);
mouton.graphics.curveTo(_x + 20, _y - 20, _x + 40, _y);
mouton.graphics.endFill();

Comme vous l'imaginez, nous ne pouvons pas dessiner l'intégralité du corps du mouton d'une seule traite. Ainsi, comme vous pouvez le voir à la figure suivante, il faut procéder étape par étape :

Mise en place du premier arrondi
Mise en place du premier arrondi
Création pas à pas du corps
Création pas à pas du corps

Tracer chaque « bosse » du corps est une étape qui peut être extrêmement longue suivant vos talents en dessin. De plus, il est peu probable que vous obteniez rapidement un rendu proche du mien, c'est pourquoi je vous épargne cette tâche périlleuse et je vous propose déjà le code final permettant de dessiner l'intégralité du corps :

// Corps
mouton.graphics.lineStyle(4, 0x3A281E, 1.0);
mouton.graphics.beginFill(0xFFFFFF);
mouton.graphics.moveTo(_x, _y);
mouton.graphics.curveTo(_x + 20, _y - 20, _x + 40, _y);
mouton.graphics.curveTo(_x + 60, _y - 10, _x + 70, _y + 10);
mouton.graphics.curveTo(_x + 90, _y + 10, _x + 90, _y + 30);
mouton.graphics.curveTo(_x + 110, _y + 40, _x + 100, _y + 60);
mouton.graphics.curveTo(_x + 120, _y + 80, _x + 100, _y + 90);
mouton.graphics.curveTo(_x + 110, _y + 110, _x + 90, _y + 110);
mouton.graphics.curveTo(_x + 80, _y + 140, _x + 60, _y + 120);
mouton.graphics.curveTo(_x + 40, _y + 150, _x + 20, _y + 130);
mouton.graphics.curveTo(_x, _y + 150, _x -20, _y + 130);
mouton.graphics.curveTo(_x -40, _y + 140, _x -50, _y + 120);
mouton.graphics.curveTo(_x -70, _y + 120, _x -70, _y + 100);
mouton.graphics.curveTo(_x -100, _y + 90, _x -90, _y + 70);
mouton.graphics.curveTo(_x -110, _y + 50, _x -90, _y + 40);
mouton.graphics.curveTo(_x -90, _y + 20, _x -60, _y + 20);
mouton.graphics.curveTo(_x -50, _y, _x -30, _y + 10);
mouton.graphics.curveTo(_x -20, _y -10, _x, _y);
mouton.graphics.endFill();

Vous devriez maintenant avoir un beau corps de mouton (voir figure suivante) qui, je l'avoue, ressemble pour l'instant plus à un nuage qu'à autre chose.

Le corps du mouton
Le corps du mouton
La tête

À présent, nous allons nous occuper de la tête de notre mouton. Nous lui ferons donc deux oreilles, puis nous ajouterons la forme globale de sa tête. Les yeux, quant à eux, seront réalisés plus tard car ils demanderont un peu plus de travail.

Commençons par les oreilles, que nous créerons à partir de courbes de Bézier. La partie haute des oreilles sera dissimulée plus tard, il est donc inutile de s'attarder dessus. C'est pourquoi nous tracerons uniquement une courbe pour chaque oreille et nous laisserons le soin à la fonction endFill() de refermer chacun de nos remplissages.
Ainsi, le code présenté ci-dessous permet de réaliser les deux oreilles de la bête :

// Tête
mouton.graphics.beginFill(0xF9D092);
mouton.graphics.moveTo(_x - 30, _y + 50);
mouton.graphics.curveTo(_x - 90, _y + 165, _x - 10, _y + 60);
mouton.graphics.endFill();
mouton.graphics.beginFill(0xF9D092);
mouton.graphics.moveTo(_x + 50, _y + 50);
mouton.graphics.curveTo(_x + 100, _y + 165, _x + 30, _y + 60);
mouton.graphics.endFill();

Bien évidemment, nous avons utilisé une nouvelle couleur de remplissage pour donner un effet de peau à nos oreilles que vous pouvez voir sur la figure suivante.

Mise en place des oreilles
Mise en place des oreilles

Je suggère maintenant que nous passions à la tête. Pour dessiner celle-ci, nous allons commencer par tracer une ellipse. Puis nous utiliserons une ligne droite ainsi qu'une courbe de Bézier sans remplissage pour représenter le museau de l'animal.
Là encore, il n'y a aucune difficulté, il suffit de faire les choses dans l'ordre :

mouton.graphics.beginFill(0xF9D092);
mouton.graphics.drawEllipse(_x - 30, _y +20, 80, 150);
mouton.graphics.endFill();
mouton.graphics.moveTo(_x - 5, _y + 155);
mouton.graphics.curveTo(_x + 10, _y + 165, _x + 25, _y + 155);
mouton.graphics.moveTo(_x + 10, _y + 160);
mouton.graphics.lineTo(_x + 10, _y + 170);

Voici donc notre mouton qui commence doucement à prendre forme comme le montre la figure suivante.

Notre mouton et sa tête
Notre mouton et sa tête
Les cheveux

Nous allons à présent dessiner ce que j'ai appelé les "cheveux", mais qui correspond en réalité à la petite touffe de laine présente sur le dessus de la tête.
La technique utilisée ici est similaire à celle employée pour le corps, cependant nous allons utiliser cette fois la méthode drawPath(). Afin de rendre le code plus lisible, je vous conseille encore une fois d'ajouter les différentes coordonnées par commande. Voici donc le code que j'ai réalisé pour tracer les cheveux de notre beau mouton :

// Cheveux
var commandes:Vector.<int> = new Vector.<int>();
commandes.push(1, 3, 3, 3, 3, 3, 3, 3, 3);
var coordonnees:Vector.<Number> = new Vector.<Number>();
coordonnees.push(_x - 20, _y + 20);
coordonnees.push(_x, _y - 10, _x + 20, _y + 10);
coordonnees.push(_x + 40, _y, _x + 50, _y + 30);
coordonnees.push(_x + 80, _y + 30, _x + 60, _y + 50);
coordonnees.push(_x + 70, _y + 70, _x + 40, _y + 70);
coordonnees.push(_x + 20, _y + 90, _x, _y + 70);
coordonnees.push(_x - 20, _y + 90, _x - 30, _y + 60);
coordonnees.push(_x - 60, _y + 50, _x - 40, _y + 30);
coordonnees.push(_x - 40, _y, _x - 20, _y + 20);
mouton.graphics.beginFill(0xFFFFFF);
mouton.graphics.drawPath(commandes, coordonnees);
mouton.graphics.endFill();

Nous avons cette fois quelque chose qui commence réellement à ressembler à un mouton (voir figure suivante).

Mise en place des cheveux
Mise en place des cheveux
Les pattes

Continuons l'exercice en dessinant les pattes pour lesquelles je n'ai pas réussi à trouver l'effet que je souhaitais. Ce n'est pas grave, contentons-nous de dessiner deux rectangles arrondis en guise de pieds. Rien de plus simple, ceci est réalisable en quatre instructions :

// Pattes
mouton.graphics.beginFill(0xF9D092);
mouton.graphics.drawRoundRect(_x - 60, _y + 155, 40, 20, 20, 20);
mouton.graphics.drawRoundRect(_x + 40, _y + 155, 40, 20, 20, 20);
mouton.graphics.endFill();

Voici donc à la figure suivante notre mouton qui peut à présent se tenir debout sur ses pattes.

Notre mouton se tient debout
Notre mouton se tient debout
Les yeux

Notre mouton est très beau, mais il est pour l'instant aveugle !
Nous allons maintenant nous occuper des yeux. Pour ceux-ci, nous n'utiliserons que des cercles, ou plutôt des disques. Il nous en faudra trois pour chaque œil : un pour l’œil en lui-même, un pour la pupille et enfin un dernier pour simuler le reflet blanc à l'intérieur de celle-ci. Un petit détail supplémentaire, nous n'aurons pas besoin de contours pour les deux derniers disques. C'est pourquoi, nous définirons un style de lignes transparent pour ceux-ci.
Je vous propose donc de découvrir le code correspondant à l'ensemble de ces manipulations :

// Yeux
mouton.graphics.beginFill(0xFFFFFF);
mouton.graphics.drawCircle(_x - 10, _y + 100, 15);
mouton.graphics.drawCircle(_x + 25, _y + 100, 20);
mouton.graphics.endFill();
mouton.graphics.lineStyle(1, 0x3A281E, 0.0);
mouton.graphics.beginFill(0x000000);
mouton.graphics.drawCircle(_x - 10, _y + 100, 8);
mouton.graphics.drawCircle(_x + 25, _y + 100, 8);
mouton.graphics.endFill();
mouton.graphics.beginFill(0xFFFFFF);
mouton.graphics.drawCircle(_x - 8, _y + 98, 2);
mouton.graphics.drawCircle(_x + 27, _y + 98, 2);
mouton.graphics.endFill();

Cette petite touche finale vient donner vie à notre mouton qui nous scrute maintenant du regard (voir figure suivante) !

Le mouton intégral
Le mouton intégral
La bulle

J'aurai pu laisser ce « chef-d’œuvre » tel quel, mais je trouvais qu'il manquait un petit quelque chose. J'ai donc ajouté une bulle au mouton comme si on se trouvait dans une bande dessinée.
Rien de nouveau ici, il s'agit presque exclusivement de cercles remplis ainsi que d'un rectangle arrondi. Encore une fois, la seule difficulté est de placer les éléments au bon endroit. Voici comment faire :

// Bulle
mouton.graphics.beginFill(0x3A281E);
mouton.graphics.drawCircle(_x - 60, _y + 70, 5);
mouton.graphics.drawCircle(_x - 80, _y + 50, 10);
mouton.graphics.drawRoundRect(_x - 150, _y - 25, 90, 60, 60, 60);
mouton.graphics.endFill();
mouton.graphics.beginFill(0xFFFFFF);
mouton.graphics.drawCircle(_x - 120, _y + 15, 5);
mouton.graphics.drawCircle(_x - 105, _y + 15, 5);
mouton.graphics.drawCircle(_x - 90, _y + 15, 5);
mouton.graphics.endFill();

Cette fois, nous avons à la figure suivante le résultat final de notre dessin.

L'illustration complète
L'illustration complète

Code final

Pour terminer ce chapitre, je vous ai réécrit l'intégralité du code afin que vous puissiez effectuer vos propres tests.

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.display.Shape;
    
    public class Main extends Sprite 
    {
        private var _x:int;
        private var _y:int;
        
        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
            _x = 160;
            _y = 40;
            var mouton:Shape = new Shape();
            
            // Fond
            mouton.graphics.beginFill(0x10879D);
            mouton.graphics.drawRoundRect(0, 0, 280, 220, 40, 40);
            mouton.graphics.endFill();
            
            // Corps
            mouton.graphics.lineStyle(4, 0x3A281E, 1.0);
            mouton.graphics.beginFill(0xFFFFFF);
            mouton.graphics.moveTo(_x, _y);
            mouton.graphics.curveTo(_x + 20, _y - 20, _x + 40, _y);
            mouton.graphics.curveTo(_x + 60, _y - 10, _x + 70, _y + 10);
            mouton.graphics.curveTo(_x + 90, _y + 10, _x + 90, _y + 30);
            mouton.graphics.curveTo(_x + 110, _y + 40, _x + 100, _y + 60);
            mouton.graphics.curveTo(_x + 120, _y + 80, _x + 100, _y + 90);
            mouton.graphics.curveTo(_x + 110, _y + 110, _x + 90, _y + 110);
            mouton.graphics.curveTo(_x + 80, _y + 140, _x + 60, _y + 120);
            mouton.graphics.curveTo(_x + 40, _y + 150, _x + 20, _y + 130);
            mouton.graphics.curveTo(_x, _y + 150, _x -20, _y + 130);
            mouton.graphics.curveTo(_x -40, _y + 140, _x -50, _y + 120);
            mouton.graphics.curveTo(_x -70, _y + 120, _x -70, _y + 100);
            mouton.graphics.curveTo(_x -100, _y + 90, _x -90, _y + 70);
            mouton.graphics.curveTo(_x -110, _y + 50, _x -90, _y + 40);
            mouton.graphics.curveTo(_x -90, _y + 20, _x -60, _y + 20);
            mouton.graphics.curveTo(_x -50, _y, _x -30, _y + 10);
            mouton.graphics.curveTo(_x -20, _y -10, _x, _y);
            mouton.graphics.endFill();
            
            // Tête
            mouton.graphics.beginFill(0xF9D092);
            mouton.graphics.moveTo(_x - 30, _y + 50);
            mouton.graphics.curveTo(_x - 90, _y + 165, _x - 10, _y + 60);
            mouton.graphics.endFill();
            mouton.graphics.beginFill(0xF9D092);
            mouton.graphics.moveTo(_x + 50, _y + 50);
            mouton.graphics.curveTo(_x + 100, _y + 165, _x + 30, _y + 60);
            mouton.graphics.endFill();
            mouton.graphics.beginFill(0xF9D092);
            mouton.graphics.drawEllipse(_x - 30, _y +20, 80, 150);
            mouton.graphics.endFill();
            mouton.graphics.moveTo(_x - 5, _y + 155);
            mouton.graphics.curveTo(_x + 10, _y + 165, _x + 25, _y + 155);
            mouton.graphics.moveTo(_x + 10, _y + 160);
            mouton.graphics.lineTo(_x + 10, _y + 170);
            
            // Cheveux
            var commandes:Vector.<int> = new Vector.<int>();
            commandes.push(1, 3, 3, 3, 3, 3, 3, 3, 3);
            var coordonnees:Vector.<Number> = new Vector.<Number>();
            coordonnees.push(_x - 20, _y + 20);
            coordonnees.push(_x, _y - 10, _x + 20, _y + 10);
            coordonnees.push(_x + 40, _y, _x + 50, _y + 30);
            coordonnees.push(_x + 80, _y + 30, _x + 60, _y + 50);
            coordonnees.push(_x + 70, _y + 70, _x + 40, _y + 70);
            coordonnees.push(_x + 20, _y + 90, _x, _y + 70);
            coordonnees.push(_x - 20, _y + 90, _x - 30, _y + 60);
            coordonnees.push(_x - 60, _y + 50, _x - 40, _y + 30);
            coordonnees.push(_x - 40, _y, _x - 20, _y + 20);
            mouton.graphics.beginFill(0xFFFFFF);
            mouton.graphics.drawPath(commandes, coordonnees);
            mouton.graphics.endFill();
            
            // Pattes
            mouton.graphics.beginFill(0xF9D092);
            mouton.graphics.drawRoundRect(_x - 60, _y + 155, 40, 20, 20, 20);
            mouton.graphics.drawRoundRect(_x + 40, _y + 155, 40, 20, 20, 20);
            mouton.graphics.endFill();
            
            // Yeux
            mouton.graphics.beginFill(0xFFFFFF);
            mouton.graphics.drawCircle(_x - 10, _y + 100, 15);
            mouton.graphics.drawCircle(_x + 25, _y + 100, 20);
            mouton.graphics.endFill();
            mouton.graphics.lineStyle(1, 0x3A281E, 0.0);
            mouton.graphics.beginFill(0x000000);
            mouton.graphics.drawCircle(_x - 10, _y + 100, 8);
            mouton.graphics.drawCircle(_x + 25, _y + 100, 8);
            mouton.graphics.endFill();
            mouton.graphics.beginFill(0xFFFFFF);
            mouton.graphics.drawCircle(_x - 8, _y + 98, 2);
            mouton.graphics.drawCircle(_x + 27, _y + 98, 2);
            mouton.graphics.endFill();
            
            // Bulle
            mouton.graphics.beginFill(0x3A281E);
            mouton.graphics.drawCircle(_x - 60, _y + 70, 5);
            mouton.graphics.drawCircle(_x - 80, _y + 50, 10);
            mouton.graphics.drawRoundRect(_x - 150, _y - 25, 90, 60, 60, 60);
            mouton.graphics.endFill();
            mouton.graphics.beginFill(0xFFFFFF);
            mouton.graphics.drawCircle(_x - 120, _y + 15, 5);
            mouton.graphics.drawCircle(_x - 105, _y + 15, 5);
            mouton.graphics.drawCircle(_x - 90, _y + 15, 5);
            mouton.graphics.endFill();
            
            this.addChild(mouton);
        }
        	
    }
    
}
En résumé
  • La classe Graphics renferme toutes les méthodes permettant de dessiner directement depuis le code.

  • Pour accéder à cette classe Graphics, il est nécessaire de passer par l'instanciation de l'une de ces trois classes : Shape, Sprite ou MovieClip.

  • En Flash, les dessins réalisés sont de type vectoriels et s'adaptent à la taille de l'affichage.

  • Pour dessiner en Actionscript, nous devons définir un contour puis spécifier les styles de remplissages et de lignes qui doivent lui être appliqués.

  • Les contours peuvent être réalisés grâce à des lignes droites ou des courbes de Bézier.

  • Des formes prédéfinies facilitent le tracé de formes géométriques simples, telles que les cercles, les ellipses et les rectangles.

Exemple de certificat de réussite
Exemple de certificat de réussite