Imaginer une animation en termes de vecteurs est intuitif, mais comprendre les mathématiques vectorielles est une douleur. Dans ce didacticiel, j'espère soulager cette douleur et apporter une solution aux problèmes d'animation à l'aide d'une classe Vector2D écrite personnalisée. Nous aborderons quelques concepts fondamentaux de la cinématique linéaire dans l'approche eulérienne: déplacement, vitesse et accélération. Ensuite, nous allons construire une application simple avec elle.
Jetons un coup d'œil au résultat final sur lequel nous allons travailler. Cliquez sur le panneau Flash ci-dessous et contrôlez la flèche en appuyant sur les quatre touches directionnelles..
Toutes les quantités vectorielles ont deux composantes: magnitude et direction.
Un changement dans les quantités vectorielles fait référence à l'un des cas suivants:
Le déplacement, la vitesse et l'accélération sont des quantités vectorielles. Leurs définitions sont les suivantes:
L'animation ci-dessous montre le déplacement que nous allons implémenter dans Flash plus tard..
La vélocité est illustrée par l'animation ci-dessous. Notez que la vitesse est constante, ce qui signifie que l'accélération est absente dans ce scénario. Si la vitesse est nulle, le déplacement restera constant.
L'accélération est illustrée par l'animation ci-dessous. Remarque: la cinématique implique constant accélération. Si l’accélération change avec le temps, elle relève du thème dynamique. La dynamique est l’étude des forces qui font que l’accélération varie dans le temps. Une de ces forces est la gravité et j'ai écrit un article sur l'animation.
Maintenant que vous avez une brève compréhension des grandeurs de la cinématique linéaire et que vous pouvez les associer à des vecteurs, nous pouvons commencer à construire notre classe de projectiles. Nous voudrions que le projectile puisse capturer toutes ces quantités: déplacement, vitesse et accélération - afin qu'il puisse être manipulé sur chaque image..
Vous trouverez ci-dessous les données que nous enregistrerons dans notre classe de projectiles:
var privé déplacer: Vector2D; velo var privé: Vector2D; accès var privé: Vector2D;
Lors de l’initiation de cette classe de projectiles, nous initialiserons les variables mentionnées et en tirerons la représentation graphique..
fonction publique Projectile () // dessine des graphiques this.draw (); // initie toutes les quantités vectorielles displace = new Vector2D (this.x, this.y); velo = nouveau Vector2D (0, 0); acc = nouveau Vector2D (0, 0); function protégée draw (): void // dessin de la flèche arrow height: Number = 30; var width: Nombre = 60; graphics.beginFill (0x0000FF); graphics.moveTo (0, 0); graphics.lineTo (width / -3, height / -2); graphics.lineTo (width / 2, 0); graphics.lineTo (width / -3, height / 2); graphics.lineTo (0, 0); graphics.endFill ();
Ce qui suit sont des accesseurs de nos variables privées - déplacer
, velo
, acc
- dans la classe projectile.
fonction publique setDisp (mag: nombre, angle: nombre): void displace.redefine (mag, angle); fonction publique getDisp (): Vector2D return displace; fonction publique setVelo (mag: nombre, angle: nombre): void velo.redefine (mag, angle); fonction publique getVelo (): Vector2D return velo; fonction publique setAcc (mag: nombre, angle: nombre): void acc.redefine (mag, angle); fonction publique getAcc (): Vector2D return acc
Lors de l'actualisation de chaque image, nous devons mettre à jour la vitesse (en utilisant l'accélération) et à mettre à jour le déplacement (en utilisant ladite vitesse). Ceci peut être réalisé en utilisant les fonctions suivantes. Pour une explication détaillée sur l’ajout de Vector, visitez ce superbe post de Daniel Sidhon.
fonction publique applyVelo (): void this.displace = this.displace.add (velo); fonction publique applyAcc (): void this.velo = this.velo.add (acc); // met à jour la position de l'image-objet par déplacement. fonction publique animate (): void this.x = this.displace.x; this.y = this.displace.y;
Nous devrons également mettre à jour l'orientation du Sprite. Ceci peut être réalisé par le rotation
propriété de Sprite.
fonction publique orient (): void this.rotation = Math2.degreeOf (velo.getAngle ());
J'ai également mis en place un Math2
classe statique, dans laquelle j'ai écrit une fonction permettant de convertir facilement des unités de degrés et de radians de l'angle.
Fonction statique publique radianOf (deg: Number): Number return deg / 180 * Math.PI; fonction statique publique degreeOf (rad: Number): Number return rad / Math.PI * 180;
Maintenant que nous avons établi nos classes Projectile et Math2, nous pouvons commencer à coder notre classe principale. Nous aurons également besoin d'une classe Vector2D bien qu'une explication détaillée ne soit pas incluse en raison de l'article susmentionné sur Vectors de Daniel Sidhon. Je suppose que les lecteurs comprennent la classe Vector2D après l'avoir lue. Cependant, si des éclaircissements sont nécessaires, n'hésitez pas à me poser des questions..
Tout d’abord, nous devons connaître les variables privées de cette classe.
private var b1: Projectile; // indicateurs de pression de touches private var UP: Boolean = false; private var DOWN: Boolean = false; private var LEFT: Boolean = false; var privé RIGHT: Boolean = false;
À l’initialisation de Main, fonction init
sera lancé. Cette fonction créera un nouveau projectile et définira sa vitesse initiale. Ensuite, les auditeurs d'événements seront affectés.
fonction privée init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // point d'entrée b1 = new Projectile (); stage.addChild (b1); // définition de la vitesse initiale b1.setVelo (5, Math2.radianOf (30)); // définition des écouteurs d'événement b1.addEventListener (Event.ENTER_FRAME, proj_enterFrame); stage.addEventListener (KeyboardEvent.KEY_DOWN, handle_keyDown); stage.addEventListener (KeyboardEvent.KEY_UP, handle_keyUp);
J'ai défini le contrôle utilisateur en appuyant sur les touches fléchées Haut, Gauche, Bas et Gauche. En appuyant sur ces touches et en les relâchant, les variables de drapeau de Main (étape 11) deviennent vraies et fausses. Sur la base de ces indicateurs, les quantités de vecteur seront manipulées sur chaque image. Notez également que j'ai divisé les contrôles en manipulateurs d'axe horizontal et vertical.
fonction privée handle_keyDown (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = true; sinon si (e.keyCode == Keyboard.DOWN) DOWN = true; if (e.keyCode == Keyboard.LEFT) LEFT = true; else if (e.keyCode == Keyboard.RIGHT) RIGHT = true; fonction privée handle_keyUp (e: KeyboardEvent): void if (e.KeyCode == Keyboard.UP) UP = false; sinon si (e.keyCode == Keyboard.DOWN) DOWN = false; if (e.keyCode == Keyboard.LEFT) LEFT = false; else if (e.keyCode == Keyboard.RIGHT) RIGHT = false;
Lors du rafraîchissement de chaque image, le code suivant sera exécuté. C'est long, mais ne t'inquiète pas; viens de lire.
fonction privée proj_enterFrame (e: Event): void // définir l'accélération var accMag: Number = 0.1; si (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc (); else if (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc (); if (LEFT) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc (); else if (DROIT) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc (); // décélère lorsque vous appuyez sur rien pour simuler un frottement. if (UP + DOWN + LEFT + RIGHT == 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); if (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc (); b1.applyVelo (); // restriction de l'image-objet aux limites de l'étape b1.getDisp (). x = Math2.implementBound (0, stage.stageWidth, b1.getDisp (). x); b1.getDisp (). y = Math2.implementBound (0, stage.stageHeight, b1.getDisp (). y); b1.animate (); b1.orient ();
La mise à jour de la motion doit être effectuée dans l'ordre suivant:
J'ai mis en évidence les codes pour faciliter l'identification de ces étapes.
fonction privée proj_enterFrame (e: Event): void // définir l'accélération var accMag: Number = 0.1; si (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc (); else if (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc (); if (LEFT) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc (); else if (DROIT) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc (); // décélère car rien n’est pressé pour simuler un frottement. if (UP + DOWN + LEFT + RIGHT == 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); if (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc (); b1.applyVelo (); // restriction de l'image-objet aux limites de l'étape b1.getDisp (). x = Math2.implementBound (0, stage.stageWidth, b1.getDisp (). x); b1.getDisp (). y = Math2.implementBound (0, stage.stageHeight, b1.getDisp (). y); b1.animate (); b1.orient ();
Vous constaterez peut-être qu'il existe d'autres fonctions insérées entre ces codes en surbrillance. Que sont-ils? L’une consiste à appliquer un autre vecteur pour ralentir notre projectile car l’utilisateur n’appuie sur aucune touche. Ceci est appliqué avant d'ajouter la vitesse à notre déplacement.
// décélère lorsque vous appuyez sur nothng pour simuler un frottement. if (UP + DOWN + LEFT + RIGHT == 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); if (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc ();
La prochaine est de limiter notre projectile à rester toujours sur la scène, sinon il va voler hors de l'écran. Encore, ImplementBound
est une fonction que j'ai incluse dans la classe statique Math2. Étant donné une limite supérieure, une limite inférieure et une valeur aléatoire, ImplementBound
retournera une valeur qui est dans les limites.
Après avoir appliqué ces contraintes sur notre déplacement (et seulement après), nous actualisons la position du Sprite avec cette valeur de déplacement..
// restriction de l'image-objet aux limites de l'étape b1.getDisp (). x = Math2.implementBound (0, stage.stageWidth, b1.getDisp (). x); b1.getDisp (). y = Math2.implementBound (0, stage.stageHeight, b1.getDisp (). y);
Avant de laisser ce sprite tel quel, nous devons l’orienter de manière à ce qu’il pointe toujours dans la position qu’il dirige en utilisant function Orient
.
Maintenant tout est prêt à partir. Lorsque vous lancez cette pièce en appuyant sur Ctrl + Entrée, vous verrez une flèche qui ralentit progressivement au fur et à mesure qu'elle avance en diagonale sur l'écran. Appuyez sur les quatre touches directionnelles pour déplacer la flèche. Ne vous inquiétez pas de perdre votre flèche. ça va rester dans votre vue.
Cet article devrait vous familiariser avec l’utilisation de vecteurs pour animer des mouvements. Une fois que vous avez compris la cinématique, continuez à lire mon article sur la dynamique. Faites-moi savoir comment ça se passe. Terima Kasih.