Deux fois par mois, nous relisons certaines des publications favorites de nos lecteurs dans Activetuts + history. Le didacticiel rétro-actif de cette semaine, publié pour la première fois en avril, est un guide des vecteurs euclidiens: leur nature, leur utilisation, et leur implémentation en Flash avec AS3.
Les vecteurs euclidiens sont des objets en géométrie avec certaines propriétés qui sont très utiles pour développer des jeux. Ils peuvent être vus comme des points, mais ils ont aussi une magnitude et une direction. Elles sont représentées par des flèches allant du point initial au point final, et nous allons les dessiner dans cet article..
Les vecteurs euclidiens sont couramment utilisés en mathématiques et en physique pour un grand nombre de choses: ils peuvent représenter la vitesse, l'accélération et les forces en physique, ou aider à prouver de nombreux théorèmes importants en mathématiques. Dans ce tutoriel, vous allez apprendre à connaître les vecteurs euclidiens et à construire une classe que vous pourrez utiliser dans vos propres projets Flash..
Veuillez noter que les vecteurs euclidiens sont différents de la classe Vector d'ActionScript et également différents du dessin vectoriel..
Les vecteurs peuvent être utilisés dans l'environnement Flash pour vous aider à réaliser des tâches complexes qui, autrement, demanderaient beaucoup d'efforts si elles étaient effectuées sans eux. Dans cet article, vous apprendrez à les utiliser en Flash, ainsi qu’à apprendre beaucoup de trucs sympas avec des vecteurs.
Avant de sauter dans les vecteurs, introduisons le système de coordonnées de Flash. Vous connaissez probablement le système de coordonnées cartésien (même si vous ne le connaissez pas par son nom):
Le système de Flash est très similaire. La seule différence est que l'axe des ordonnées est à l'envers:
Lorsque nous commençons à travailler avec des vecteurs en flash, nous devons nous en souvenir. Cependant, bonne nouvelle: ce système différent ne fait pas beaucoup de différence. Travailler avec des vecteurs dedans sera fondamentalement comme travailler avec des vecteurs dans le système cartésien.
Pour les besoins de ce didacticiel, nous allons définir et utiliser les points initiaux de tous les vecteurs comme étant le point d’enregistrement de la scène, comme ils sont couramment utilisés en mathématiques. Un vecteur sera alors défini comme un point commun, mais il aura des propriétés de magnitude et d’angle. Jetez un coup d’œil à quelques exemples de vecteurs définis dans la scène:
Comme vous pouvez le constater, un vecteur est représenté par une flèche et chaque vecteur a une certaine longueur (ou ordre de grandeur) et pointe le long d'un certain angle. La queue de chaque vecteur est au point d'enregistrement (0, 0)
.
Nous allons créer une classe EuclideanVector simple pour ce tutoriel, en utilisant la classe Point pour contenir les coordonnées du vecteur. Créons maintenant la classe de vecteur de base:
package import flash.geom.Point; public class EuclideanVector public var position: Point; public var magnitude: Number; angle var public: Nombre; fonction publique EuclideanVector (endPoint: Point) position = endPoint;
Au cours de ce tutoriel, nous parlerons de la sens et le direction d'un vecteur. Notez que la direction définit simplement une ligne qui "contient" le vecteur. Le sens est ce qui définit le sens du vecteur le long de cette ligne.
Dans ce tutoriel, nous utiliserons l'expression "inverse d'un vecteur". L'inverse d'un vecteur est un autre vecteur de même amplitude et direction, mais ayant un sens contraire. Cela se traduit par un vecteur avec le signal opposé aux coordonnées du premier vecteur. Donc, un vecteur avec un point final de (x, y) aurait un vecteur inverse avec un point final de (-x, -y).
Ajoutons une fonction à notre classe EuclideanVector pour renvoyer le vecteur inverse:
fonction publique inverse (): EuclideanVector retourne un nouveau EuclideanVector (nouveau Point (-position.x, -position.y));
Maintenant que nous avons appris à définir un vecteur, apprenons à ajouter deux vecteurs: il suffit d’ajouter leurs coordonnées séparément. Regardez cette image:
Si vous remarquez dans l'image, le résultat de l'ajout de deux vecteurs est un autre vecteur et vous pouvez voir que ses coordonnées sont la somme des coordonnées des deux autres vecteurs. En code, cela ressemblerait à ceci:
fonction publique sum (otherVector: EuclideanVector): EuclideanVector position.x + = otherVector.position.x; position.y + = otherVector.position.y; retournez ceci;
On peut donc dire que:
vecR == vec1.sum (vec2);
La soustraction fonctionne presque comme l’addition, mais nous ajouterons le inverse du second vecteur au premier vecteur.
On sait déjà comment additionner deux vecteurs, voici donc le code de soustraction:
fonction publique soustraire (otherVector: EuclideanVector): EuclideanVector position.x - = otherVector.position.x; position.y - = otherVector.position.y; retournez ceci;
Ce code est extrêmement utile pour obtenir un vecteur qui va du point d’un vecteur à un autre. Regardez encore l'image et vous verrez que c'est vrai. Il sera beaucoup utilisé dans les derniers exemples.
La multiplication entre un vecteur et un nombre (les nombres normaux sont appelés "scalaires" en mathématiques vectorielles) donne un vecteur dont la magnitude a été multipliée par ce nombre, mais qui pointe toujours dans la même direction; il est "étiré" si le scalaire est supérieur à 1 et écrasé si le scalaire est compris entre 0 et 1. Le sens du nouveau vecteur sera le même que celui du vecteur d'origine si le scalaire est positif, ou l'inverse s'il est négatif. Fondamentalement, ce nombre "met à l'échelle" le vecteur. Regarde l'image:
Dans le code, nous ne multiplions que les coordonnées d'un vecteur par le nombre, ce qui redimensionnera ensuite le vecteur:
fonction publique multiplier (nombre: nombre): EuclideanVector position.x * = nombre; position.y * = nombre; retournez ceci;
Afin d'obtenir la magnitude d'un vecteur, nous allons utiliser le théorème de Pythagore. Si vous avez oublié de quoi il s'agit, voici un bref rappel:
(Plus d'infos ici.)
Le code est très simple:
fonction publique magnitude (): Number return Math.sqrt ((position.x * position.x) + (position.y * position.y));
Vous devriez également supprimer la ligne public var magnitude: Number
, comme c'est ce que nous allons utiliser à partir de maintenant.
La magnitude d'un vecteur sera toujours positive, car c'est la racine carrée de la somme de deux nombres positifs.
L'angle d'un vecteur est l'angle entre l'axe des x et la ligne directrice du vecteur. L'angle est mesuré en partant de l'axe des x et en tournant dans le sens inverse des aiguilles d'une montre jusqu'à la ligne directrice dans le système cartésien:
Cependant, dans le système de coordonnées de Flash, l'axe des y étant orienté à l'envers, cet angle est mesuré en rotation dans le sens des aiguilles d'une montre:
Ceci peut être facilement calculé en utilisant le code suivant. L'angle sera renvoyé en radians, dans une plage allant de 0 à 2pi. Si vous ne savez pas ce que sont les radians ni comment les utiliser, ce tutoriel de Michael James Williams vous aidera beaucoup.
fonction publique angle (): Number var angle: Number = Math.atan2 (position.y, position.x); si (angle < 0) angle += Math.PI * 2; return angle;
Le produit scalaire entre deux vecteurs est un nombre apparemment vide de sens, mais il a deux utilisations utiles. Voyons d'abord comment le produit scalaire peut être calculé:
Mais il peut aussi être obtenu par les coordonnées de chaque vecteur:
Le produit scalaire peut nous en dire beaucoup sur l'angle entre les vecteurs: s'il est positif, l'angle varie de 0 à 90 degrés. Si c'est négatif, l'angle va de 90 à 180 degrés. Si c'est zéro, l'angle est de 90 degrés. Cela se produit car, dans la première formule, seul le cosinus est chargé de donner un "signal" au produit scalaire: les grandeurs sont toujours positives. Mais nous savons qu'un cosinus positif signifie que l'angle varie de 0 à 90 degrés, et ainsi de suite pour les cosinus négatifs et zéro.
Le produit scalaire peut également être utilisé pour représenter la longueur d'un vecteur dans la direction de l'autre vecteur. Pensez-y comme une projection. Cela s'avère extrêmement utile dans des domaines comme le SAT (Separation of Axis Theorem) et son implémentation dans AS3 pour la détection de collision et la réponse dans les jeux..
Voici le code pratique pour obtenir le produit scalaire entre deux vecteurs:
fonction publique point (otherVector: EuclideanVector): Number return (position.x * autreVector.position.x) + (position.y * autreVector.position.y);
L'angle entre les vecteurs, comme indiqué à l'étape 9, peut être donné par le produit scalaire. Voici comment le calculer:
fonction publique angleBetween (otherVector: EuclideanVector): Number return Math.acos (dot (otherVector) / / magnitude () * otherVector.magnitude ()));
Il existe également un autre moyen de calculer l'angle, qui donne des résultats entre -pi et pi et calcule toujours l'angle qui va du premier vecteur au deuxième vecteur; Ceci est utile lorsque vous souhaitez intégrer facilement la rotation d'un objet d'affichage (qui va de -180 à 180)..
La méthode fonctionne en obtenant l'angle des deux vecteurs, puis en soustrayant les angles et en travaillant sur le résultat..
Le code:
fonction publique rangedAngleBetween (otherVector: EuclideanVector): Number var firstAngle: Number; var secondAngle: Number; angle var: nombre; firstAngle = Math.atan2 (otherVector.position.y, otherVector.position.x); secondAngle = Math.atan2 (position.y, position.x); angle = secondAngle - firstAngle; while (angle> Math.PI) angle - = Math.PI * 2; tandis que (angle < -Math.PI) angle += Math.PI * 2; return angle;
Notez que cet angle est positif si secondAngle est plus élevé que premierAngle, de sorte que l'ordre dans lequel vous obtenez l'angle à distance affectera le résultat!
Normaliser un vecteur signifie que sa magnitude soit égale à 1, tout en préservant la direction et le sens du vecteur. Pour ce faire, nous multiplions le vecteur par 1 / magnitude
. De cette façon, son ampleur sera réduite ou augmentée à 1.
fonction publique normalize (): EuclideanVector var m: Number = magnitude (); position.x / = m; position.y / = m; retournez ceci;
le Ordinaire d’un vecteur est un autre vecteur qui fait un angle de 90 degrés avec le premier. Il peut être calculé avec les formules suivantes:
Les formules reposent sur le fait que, puisque la normale est toujours perpendiculaire à un vecteur, il suffit de changer l’ordre des coordonnées x et y et d’en inverser une pour obtenir une normale. L'image suivante montre le processus:
Dans l'image, Vec est le vecteur d'origine, Vec2 est le vecteur avec Vecest échangé des coordonnées, et Vec3 est un vecteur avec Vec2La coordonnée y est négative. Ang et Ang2 sont variables, mais l'angle entre Vec et Vec3 est toujours à 90 degrés.
Et le code est simple
public function normalRight (): EuclideanVector retourne un nouveau EuclideanVector (nouveau Point (-position.y, position.x)); public function normalLeft (): EuclideanVector retourne un nouveau EuclideanVector (nouveau Point (position.y, -position.x));
Pour faire pivoter un vecteur, nous supposons que la position (0, 0) (son point initial) sera le centre de rotation. Le point pivoté est donné par la formule:
Cette formule est obtenue en appliquant une matrice de rotation à ce vecteur. Nous irions au-delà de la portée de ce didacticiel si nous examinions la matrice et son fonctionnement. Je vais donc laisser la formule ici..
Le code est à peu près le même:
fonction publique rotation (angleInRadians: Number): EuclideanVector var newPosX: Number = (position.x * Math.cos (angleInRadians)) - - (position.y * Math.sin (angleInRadians)); var newPosY: Number = (position.x * Math.sin (angleInRadians)) + (position.y * Math.cos (angleInRadians)); position.x = newPosX; position.y = newPosY; retournez ceci;
C'est la fin de nos opérations vectorielles de base. Vous verrez ensuite comment utiliser cette classe pour faire des choses intéressantes. Voici notre cours jusqu'à présent:
package import flash.geom.Point; public class EuclideanVector public var position: Point; angle var public: Nombre; fonction publique EuclideanVector (endPoint: Point) position = endPoint; fonction publique inverse (): EuclideanVector retour new EuclideanVector (new Point (nouveauPosition (xposition.x, -position.y))); public function sum (otherVector: EuclideanVector): EuclideanVector position.x + = otherVector.position.x; position.y + = otherVector.position.y; retournez ceci; fonction publique soustraction (otherVector: EuclideanVector): EuclideanVector position.x - = otherVector.position.x; position.y - = otherVector.position.y; retournez ceci; fonction publique multiplier (nombre: nombre): EuclideanVector position.x * = nombre; position.y * = nombre; retournez ceci; fonction publique magnitude (): Number return Math.sqrt ((position.x * position.x) + (position.y * position.y)); fonction publique angle (): Number var angle: Number = Math.atan2 (position.y, position.x); si (angle < 0) angle += Math.PI * 2; return angle; public function dot(otherVector:EuclideanVector):Number return (position.x * otherVector.position.x) + (position.y * otherVector.position.y); public function angleBetween(otherVector:EuclideanVector):Number return Math.acos(dot(otherVector) / (magnitude() * otherVector.magnitude())); public function rangedAngleBetween(otherVector:EuclideanVector):Number var firstAngle:Number; var secondAngle:Number; var angle:Number; firstAngle = Math.atan2(otherVector.position.y, otherVector.position.x); secondAngle = Math.atan2(position.y, position.x); angle = secondAngle - firstAngle; while (angle > Math.PI) angle - = Math.PI * 2; tandis que (angle < -Math.PI) angle += Math.PI * 2; return angle; public function normalize():EuclideanVector position.x /= magnitude(); position.y /= magnitude(); return this; public function normalRight():EuclideanVector return new EuclideanVector(new Point(-position.y, position.x)); public function normalLeft():EuclideanVector return new EuclideanVector(new Point(position.y, -position.x)); public function rotate(angleInRadians:Number):EuclideanVector var newPosX:Number = (position.x * Math.cos(angleInRadians)) - (position.y * Math.sin(angleInRadians)); var newPosY:Number = (position.x * Math.sin(angleInRadians)) + (position.y * Math.cos(angleInRadians)); position.x = newPosX; position.y = newPosY; return this;
L'action commence ici. Déterminer si un point se trouve ou non dans un polygone est un sujet très intéressant, et il existe de nombreuses méthodes pour le réaliser. Dans cet article, je présenterai les trois méthodes généralement utilisées:
Tous ces algorithmes reposent sur le fait que vous connaissez les coordonnées des sommets (coins) qui définissent le polygone.
Cet algorithme peut être utilisé pour n'importe quelle forme. Voici ce que vous lisez: n'importe quelle forme, qu'elle soit perforée ou non, qu'elle soit convexe ou non. Il est basé sur le fait que tout rayon lancé du point que vous souhaitez vérifier à l'infini traversera un nombre pair d'arêtes si le point se trouve en dehors de la forme, ou un nombre impair d'arêtes si le point se trouve à l'intérieur de la forme. Cela peut être prouvé par le théorème de la courbe de Jordan, ce qui implique que vous devrez traverser une frontière entre certaines régions pour pouvoir passer d’une région à l’autre. Dans notre cas, nos régions sont "dans la forme" et "hors de la forme".
Le code de cet algorithme est le suivant:
fonction publique isPointInsideShape1 (point: EuclideanVector, shapeVertices: Vector.): Boolean var numberOfSides: int = shapeVertices.length; var i: int = 0; var j: int = numberOfSides - 1; var oddNodes: Boolean = false; alors que je < numberOfSides) if ((shapeVertices[i].position.y < point.position.y && shapeVertices[j].position.y >= point.position.y) || (shapeVertices [j] .position.y < point.position.y && shapeVertices[i].position.y >= point.position.y)) if (shapeVertices [i] .position.x + (((point.position.y - shapeVertices [i] .position.y) / / shapeVertices [j] .position.y - shapeVertices [i] .position.y)) * (shapeVertices [j] .position.x - shapeVertices [i] .position.x)) < point.position.x) oddNodes = !oddNodes; j = i; i++; return oddNodes;
Il reviendra faux
si le point n'est pas à l'intérieur de la forme, ou vrai
si le point est à l'intérieur de la forme.
le algorithme du nombre d'enroulement utilisez la somme de tous les angles faits entre le point à vérifier et chaque paire de points définissant le polygone. Si la somme est proche de 2pi, le point en cours de vérification se trouve à l'intérieur du vecteur. S'il est proche de 0 alors le point est en dehors.
fonction publique isPointInsideShape2 (point: EuclideanVector, shapeVertices: Vector.): Boolean var numberOfSides: int = shapeVertices.length; var i: int = 0; angle var: Nombre = 0; var rawAngle: Number = 0; var firstVector: EuclideanVector; var secondVector: EuclideanVector; alors que je < numberOfSides) firstVector = new EuclideanVector(new Point(shapeVertices[i].position.x - point.position.x, shapeVertices[i].position.y - point.position.y)); secondVector = new EuclideanVector(new Point(shapeVertices[(i + 1) % numberOfSides].position.x - point.position.x, shapeVertices[(i + 1) % numberOfSides].position.y - point.position.y)); angle += secondVector.rangedAngleBetween(firstVector); i++; if(Math.abs(angle) < Math.PI) return false; else return true;
Le code utilise l'angle à distance entre les vecteurs et laisse de la place pour les imprécisions: remarquez comment nous vérifions les résultats de la somme de tous les angles. Nous ne vérifions pas si l'angle est exactement nul ou 2pi. Au lieu de cela, nous vérifions si elle est inférieure à pi et supérieure à pi, une valeur médiane considérable.
le algorithme de polygone concave repose sur le fait que, pour un polygone concave, un point à l'intérieur se trouve toujours à gauche des arêtes (si nous les parcourons dans le sens inverse des aiguilles d'une montre) ou à droite des arêtes (si nous parcourons dans le sens des aiguilles d'une montre).
Imaginez-vous debout dans une pièce ayant la forme de l'image ci-dessus et marchant sur ses bords avec votre main gauche traînant le long du mur. Au point le long du mur où vous vous trouvez le plus près du point qui vous intéresse, s'il est à votre droite, il doit se trouver à l'intérieur de la pièce; si c'est sur votre gauche alors il doit être à l'extérieur.
Le problème consiste à déterminer si un point se trouve à gauche ou à droite d'un bord (qui est essentiellement un vecteur). Ceci est fait par la formule suivante:
Cette formule renvoie un nombre inférieur à 0 pour les points situés à droite du bord et supérieur à 0 pour les points situés à gauche. Si le nombre est égal à 0, le point se trouve sur le bord et est considéré à l'intérieur de la forme. Le code est le suivant:
fonction publique isPointInsideShape3 (point: EuclideanVector, shapeVertices: Vector.): Boolean var numberOfSides: int = shapeVertices.length; var i: int = 0; var firstEdgePoint: EuclideanVector; var secondEdgePoint: EuclideanVector; var leftOrRightSide: Boolean; alors que je < numberOfSides) firstEdgePoint = shapeVertices[i]; secondEdgePoint = shapeVertices[(i + 1) % numberOfSides]; if(i == 0) // Determining if the point is to the left or to the right of first edge // true for left, false for right leftOrRightSide = ((point.position.y - firstEdgePoint.position.y) * (secondEdgePoint.position.x - firstEdgePoint.position.x)) - ((point.position.x - firstEdgePoint.position.x) * (secondEdgePoint.position.y - firstEdgePoint.position.y)) > 0; else // Tous les bords doivent maintenant se trouver du même côté si (leftOrRightSide && ((point.position.y - firstEdgePoint.position.y) *) (secondEdgePoint.position.x - firstEdgePoint.position.x)) - ( point.position.x - firstEdgePoint.position.x) * (secondEdgePoint.position.y - firstEdgePoint.position.y)) < 0) // Not all edges are on the same side! return false; else if(!leftOrRightSide && ((point.position.y - firstEdgePoint.position.y) * (secondEdgePoint.position.x - firstEdgePoint.position.x)) - ((point.position.x - firstEdgePoint.position.x) * (secondEdgePoint.position.y - firstEdgePoint.position.y)) > 0) // Tous les bords ne sont pas du même côté! retourne faux; i ++; // Nous avons parcouru tous les sommets et n'avons pas détecté les différents côtés qui retournent la valeur true;
Ce code fonctionne que vous ayez défini les sommets de la forme dans le sens des aiguilles d'une montre ou dans le sens inverse..
Le lancer de rayons est une technique souvent utilisée pour la détection et le rendu des collisions. Il consiste en un rayon qui est projeté d'un point à un autre (ou à l'infini). Ce rayon est constitué de points ou de vecteurs et s’arrête généralement quand il frappe un objet ou le bord de l’écran. De la même manière que les algorithmes de point-en-forme, il existe de nombreuses manières de lancer des rayons, et nous en verrons deux dans ce post:
Dans les deux prochaines étapes, nous examinerons les deux méthodes. Après cela, nous verrons comment faire en sorte que notre rayon s’arrête quand il frappe un objet. Ceci est très utile lorsque vous devez détecter une collision avec des objets se déplaçant rapidement..
Cet algorithme est très souvent utilisé en infographie et dépend de la convention selon laquelle la ligne sera toujours créée pointant vers la droite et vers le bas. (Si une ligne doit être créée en haut et à gauche, tout est inversé par la suite.) Entrons dans le code:
Fonction publique createLineBresenham (startVector: EuclideanVector, endVector: EuclideanVector): Vector.points var: vecteur. = nouveau vecteur. (); var steep: Boolean = Math.abs (endVector.position.y - startVector.position.y)> Math.abs (endVector.position.x - startVector.position.x); var échangé: Boolean = false; if (raide) startVector = new EuclideanVector (new Point (startVector.position.y, startVector.position.x)); endVector = new EuclideanVector (new Point (endVector.position.y, endVector.position.x)); // Faire descendre la ligne si (startVector.position.x> endVector.position.x) var temporaire: Number = startVector.position.x; startVector.position.x = endVector.position.x; endVector.position.x = temporaire; temporaire = startVector.position.y; startVector.position.y = endVector.position.y endVector.position.y = temporaire; permuté = vrai; var deltaX: Number = endVector.position.x - startVector.position.x; var deltaY: Number = Math.abs (endVector.position.y - startVector.position.y); erreur var: Number = deltaX / 2; var currentY: Number = startVector.position.y; var step: int; si (startVector.position.y < endVector.position.y) step = 1; else step = -1; var iterator:int = startVector.position.x; while (iterator < endVector.position.x) if (steep) points.push(new EuclideanVector(new Point(currentY, iterator))); else points.push(new EuclideanVector(new Point(iterator, currentY))); error -= deltaY; if (error < 0) currentY += step; error += deltaX; iterator++; if (swapped) points.reverse(); return points;
Le code produira un vecteur AS3 de vecteurs euclidiens qui feront la ligne. Avec ce vecteur, nous pouvons plus tard vérifier les collisions.
Une mise en œuvre de la Analyseur différentiel numérique est utilisé pour interpoler des variables entre deux points. Contrairement à l'algorithme de ligne de Bresenham, cette méthode ne créera que des vecteurs avec des positions entières par souci de simplicité. Voici le code:
Fonction publique createLineDDA (startVector: EuclideanVector, endVector: EuclideanVector): Vector.points var: vecteur. = nouveau vecteur. (); var dx: nombre; var dy: nombre; var _x: Number = startPoint.position.x; var _y: Number = startPoint.position.y; var m: nombre; var i: int; dx = endPoint.position.x - startPoint.position.x; dy = endPoint.position.y - startPoint.position.y; if (Math.abs (dx)> = Math.abs (dy)) m = Math.abs (dx); sinon m = Math.abs (dy); points.push (nouveau EuclideanVector (nouveau Point (int (_x), int (_y))))); i = 1; alors que je <= m) _x += dx / m; _y += dy / m; points.push(new EuclideanVector(new Point(int(_x), int(_y)))); i++; return points;
Ce code renverra également un vecteur AS3 de vecteurs euclidiens.
Vérifier les collisions par rayons est très simple. Comme un rayon est composé de plusieurs vecteurs, nous vérifierons les collisions entre chaque vecteur et une forme jusqu'à ce que l'un soit détecté ou que la fin du rayon soit atteinte. Dans le code suivant, forme pour vérifier
sera une forme semblable à celles que nous avons utilisées aux étapes 13 à 16. Voici le code:
fonction publique checkRayCollision (ray: Vector., forme: vecteur. ): Boolean var rayLength: int = ray.length; var i: int = 0; alors que je < rayLength) if(isPointInsideShape1(ray[i], shape)) return true; i++; return false;
Vous pouvez utiliser n'importe quelle fonction point-dedans-forme avec laquelle vous vous sentez à l'aise, mais faites attention aux limites de la dernière.!
Vous êtes prêt à utiliser cette connaissance partout maintenant! Cela vous sera utile plusieurs fois et vous évitera beaucoup de calculs supplémentaires lorsque vous tenterez de faire des tâches plus complexes dans Flash..