Dans cette leçon, nous allons créer une petite application de déplacement de réservoir. Le cœur de ce tutoriel consiste à faire en sorte que le tank vise le pointeur de la souris et se dirige vers un clic de souris..
Jetons un coup d'œil au résultat final sur lequel nous allons travailler:
Déplacez la souris pour faire viser la tourelle et cliquez n'importe où pour que le char se rende à cet endroit..
Eh bien, commençons… Pour ce tutoriel, nous aurons besoin de graphiques de chars et de tourelles. J'ai utilisé Google SketchUp 7 pour créer le mien.
J'ai d'abord créé un réservoir dans son ensemble. Ensuite, j'ai tourné le mode d'affichage du programme sur "projection parallèle", plaçant ma caméra à un angle de 45 ° par rapport au char afin de créer une illusion d'isométrie dans le jeu..
S'il vous plaît, ne me jugez pas pour des graphismes horribles, je peux vraiment faire beaucoup mieux mais c'est juste pour des raisons d'explication :)
Ensuite, j'ai caché la tourelle en ne laissant que le corps du réservoir visible et j'ai fait pivoter le corps de 45 ° huit fois, rendant chaque position séparément. J'ai donc réalisé 8 vues différentes du corps. J'ai fait la même chose à la tourelle pendant que le char était caché. J'ai sauvegardé les 16 images sous le format PNG 24 avec canal alpha. Vous pouvez voir le résultat final ci-dessous. (Cela ne suffit pas vraiment pour ce type de mouvement, il serait préférable d'avoir deux fois plus de vues du char mais c'est suffisant pour les besoins de ce tutoriel.)
.
Vous n'avez pas nécessairement besoin d'utiliser Google SketchUp bien sûr, vous pouvez utiliser 3ds max ou Maya ou ce que vous préférez, vous pouvez également utiliser mes graphiques pour vous entraîner si vous ne voulez pas ou ne pouvez pas créer vos propres graphiques..
Ouvrez maintenant Flash (j'utilise Adobe Flash CS4) et choisissez Créer un nouveau fichier Flash (Actionscript 3.0). Nous en aurons besoin uniquement pour créer un tank MovieClip et pour y connecter la classe Game ultérieurement..
.
Cliquez avec le bouton droit sur la scène et accédez à l'élément Propriétés du document. Faites-en 600 x 400 (ou ce que vous aimez) et 21 images par seconde (cette cadence me semble optimale alors je l'utilise presque toujours. Cela n'a pas vraiment d'importance, cependant)..
Cliquez sur OK. Aller à Fichier> Enregistrer sous et enregistrez ce fichier sous le nom tank.fla dans un dossier de votre ordinateur (je vous recommande de créer un dossier Tank et d'y placer le fichier).
Maintenant, allez à Fichier> Importer> Importer dans la bibliothèque. Recherchez le dossier dans lequel vous avez enregistré vos huit images de réservoir, sélectionnez-les tous et importez-les dans la bibliothèque..
.
Créez un nouveau symbole vide en cliquant sur cette petite icône dans la bibliothèque:
Choisissez le type de MovieClip et appelez le symbole "réservoir". Placez le point d’inscription au centre (le point d’inscription est ce petit carré noir dans cette grille de carrés blancs, pour ceux qui ne le savent pas).
Une fois le symbole créé, il apparaît dans la bibliothèque (son nom "tank" est simplement un nom cosmétique utilisé uniquement dans la bibliothèque, le nom de celui-ci importe peu). Ouvrez-le en double-cliquant sur son icône. Ensuite, prenez 1.png dans la bibliothèque et faites-le glisser sur la scène du symbole. Alignez l'image sur le point d'enregistrement du symbole comme dans cette capture d'écran:
Vous voulez que le point d'alignement soit au centre du cercle de braquage du char.
Aller à la chronologie du symbole. Renommez le "Couche 1" en "Réservoir". L'image du corps de votre réservoir (1.png) doit figurer sur la première image de ce calque. Cliquez sur la deuxième image et, sans relâcher le bouton de la souris, faites glisser le curseur sur la 8e image en sélectionnant les images 2 à 8. Cliquez ensuite avec le bouton droit de la souris sur la zone sélectionnée et choisissez "Convertir en images clés vierges"..
Lorsque 7 images clés vides sont créées, sélectionnez la deuxième image et faites-y glisser 2.png en alignant l'image sur le point d'alignement (comme vous l'avez fait avec 1.png); imaginant que le point d’enregistrement est un axe que le char utilisera pour tourner lorsqu’il tourne. Faites la même chose pour le reste des cadres. Vous n'avez pas besoin de l'aligner très précisément, mais plus vous l'alignez avec précision, plus le mouvement ressemblera à celui que le char essaiera de suivre le curseur pendant le jeu..
Une fois que vous avez fait glisser chaque image sur la scène du symbole et que vous l'avez alignée, sélectionnez la première image et appuyez sur F9 pour ouvrir le panneau Actions. Tapez une seule méthode "stop ();" dedans et fermez le panneau. C’est une étape importante car nous ne voulons pas que notre tank commence automatiquement à tourner dès qu’il est ajouté à la scène..
Accédez à la bibliothèque et créez un nouveau symbole MovieClip. Appeler tourelle. Double-cliquez sur l'icône du symbole et faites de même avec le tank MovieClip (étapes 4. à 8.) sur la tourelle mais en utilisant des images de tourelle. Alignez-le sur le point d’enregistrement de cette façon, au point autour duquel la tourelle tournerait naturellement:
Notez que j'ai nommé les images de la tourelle comme suit: 1-.png, 2-.png, etc., afin qu'elles ne remplacent pas les images de char lors de leur importation dans la bibliothèque. Vous voudrez peut-être utiliser des dossiers pour y placer vos images. Dans ce cas, vos images de tourelle et de char peuvent porter les mêmes noms..
Une fois que vous avez terminé avec le symbole de la tourelle, rouvrez-le, créez un nouveau calque au-dessus du calque "Réservoir" et faites glisser le clip de la tourelle de la bibliothèque sur ce calque. Alignez la tourelle avec le corps du char. Le résultat devrait ressembler à ceci:
Cliquez une fois sur la tourelle pour la sélectionner (un rectangle bleu l’indiquera):
… Puis allez dans les propriétés et donnez-lui le nom d'occurrence mTurret (pour la tourelle MovieClip):
Cliquez sur le lien "Scène 1" pour quitter le mode d'édition de symbole..
Cliquez avec le bouton droit sur le symbole de réservoir dans la bibliothèque, choisissez Propriétés (ou Liaison si vous utilisez Flash CS3) dans le menu déroulant (assurez-vous que vous êtes en mode Avancé), cochez la case "Exporter pour Actionscript" et pour la classe. 'nom, tapez "Tank" (avec T majuscule). Cette étape nous permettra de connecter notre Tank MovieClip aux instances créées à l’aide de notre classe Tank à l’avenir..
La partie graphique est terminée pour le moment. vous pouvez supprimer le réservoir de la scène. Nous l'ajouterons par programme plus tard.
Dans votre outil de création Flash, accédez à Fichier> Nouveau et créer un nouveau fichier ActionScript.
Allez dans le dossier où vous avez sauvegardé votre fichier tank.fla et créez un nouveau dossier appelé "principal" à l'intérieur. Enregistrez votre fichier ActionScript dans ce dossier en tant que TankMaker.as. L’emplacement de ce fichier doit donc être: tank / main / TankMaker.as
Tout d’abord, créez un package et importez-y les classes nécessaires:
package main import flash.display. *; importer flash.events. *;
Le mot "principal" signifie ici l'emplacement de ce fichier par rapport à notre tank.fla
Nous aurons besoin de classes "display" pour afficher nos ressources à l'écran et "events" pour suivre les événements de souris..
Nous devons maintenant déclarer une classe publique TankMaker (en fonction du nom du fichier Actionscript) et les variables nécessaires:
package main import flash.display. *; importer flash.events. *; public class TankMaker étend Sprite // l'instance de notre classe Tank (que nous avons déjà exportée pour actionscript auparavant) private var tank: Tank; // les vars pour garder les coordonnées du point où nous voulons que notre tank se déplace privé var moveTankToX: Number; var privé moveTankToY: Number; // coordonnées du point où le char vise sa tourelle private var turnTurretToX: Number; private var turnTurretToY: Nombre; // position actuelle du réservoir privé var currentTankPositionX: Number; private var currentTankPositionY: Number; private var tankSpeed: Nombre = 2; // le point où le réservoir se déplace après un clic de souris private var var clickPoint: Object; // l'angle de rotation du char et de la tourelle en radians private var Atan2: Number; tourelle var privéeAtan2: Nombre;
J'ai déclaré toutes les variables comme "privées" parce que je ne veux pas qu'elles soient accessibles de l'extérieur de cette classe.
Directement sous la dernière variable, créez une fonction publique et appelez-la TankMaker. Ce sera le constructeur de la classe. Ajoutez ensuite un écouteur d'événement pour Event.ADDED_TO_STAGE afin que nous puissions créer notre objet réservoir uniquement après l'étape. Puis passez cet événement à la méthode appelée addStage..
fonction publique TankMaker () addEventListener (Event.ADDED_TO_STAGE, addStage);
Une fois que l'étape a été créée et que l'événement ADDED_TO_STAGE a déclenché la méthode addStage (), il est temps de créer une instance de réservoir..
Déclarez une fonction privée et appelez-la addStage. Le type de données de la fonction sera: Event. Et le type de retour sera "vide" car nous n'allons rien renvoyer.
fonction privée addStage (e: Event): void // crée une nouvelle instance de réservoir du clip // que vous avez exportée pour ActionScript tank = new Tank (); // maintenant un petit truc, j'ai réduit mon réservoir // à la taille d'environ un quart de sa taille d'origine // afin qu'il ne soit pas si énorme tank.scaleX = 0.25; tank.scaleY = 0,25; // définit la position initiale du réservoir à droite // au centre de la scène tank.x = stage.stageWidth / 2; tank.y = stage.stageHeight / 2; // et l'ajoute à la liste d'affichage addChild (tank); // ajoute maintenant des écouteurs d'événements pour la souris vers le bas et le déplacement de la souris // événements à la scène stage.addEventListener (MouseEvent.MOUSE_DOWN, mouseDownListener); stage.addEventListener (MouseEvent.MOUSE_MOVE, mouseMoveListener);
Créez une fonction privée mouseMoveListener () avec un type de données d'événement de souris pour gérer les mouvements de la souris sur la scène. L'écouteur d'événements pour déclencher cette fonction a été créé à la dernière étape..
fonction privée mouseMoveListener (e: MouseEvent): void // crée une variable pour conserver l'angle relatif // entre la position actuelle de la souris en degrés // et la position actuelle du réservoir var angle: Number; // les 2 variables suivantes vont être // égales à la position actuelle de la souris turnTurretToX = e.stageX; turnTurretToY = e.stageY; // calcule l'angle relatif en radians // entre la position actuelle de la souris // et la tourelle de la position actuelle du réservoirAtan2 = Math.atan2 (turnTurretToY - currentTankPositionY, turnTurretToX - currentTankPositionX); // calcule le même angle en degrés. // pour obtenir des degrés en radians, nous devons // multiplier par 180 le nombre de radians et diviser le résultat par PI // Mais voici quelques détails de Flash // il calcule l'angle non de 0 à 360 // mais de 0 à 180 et de - 180 à 0 // ajoutons donc certaines conditions pour résoudre ce problème si (Math.round (turretAtan2 * 180 / Math.PI) < 0) // if angle is between 0 and -180 add 360 to it angle = Math.round(turretAtan2 * 180 / Math.PI) + 360; else // if not, calculate it as usual angle = Math.round(turretAtan2 * 180 / Math.PI); // having our angle value stored in a variable // let's rotate our turret towards the mouse pointer // I've done a lot of calculations trying to // figure it all out, so you may try to undestand my logic // I'm just picking the right frame of the turret MC depending // on the angle of the mouse from the turret if (angle > 240 && angle < 300) // go inside the tank MovieClip then inside mTurret // go to the frame 1 and stop tank.mTurret.gotoAndStop(1); if (angle > 300 && angle < 340) tank.mTurret.gotoAndStop(2); if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) tank.mTurret.gotoAndStop(3); if (angle > 20 && angle < 60) tank.mTurret.gotoAndStop(4); if (angle > 60 && angle < 120) tank.mTurret.gotoAndStop(5); if (angle > 120 && angle < 160) tank.mTurret.gotoAndStop(6); if (angle > 160 && angle < 200) tank.mTurret.gotoAndStop(7);; if (angle > 200 && angle < 240) tank.mTurret.gotoAndStop(8); // end
Sous la fin de notre fonction mouseMoveListener (), créez une fonction privée appelée mouseDownListener () avec le type de données MouseEvent et transmettez-la à la méthode moveTankOnEnterFrame:
fonction privée mouseDownListener (e: MouseEvent): void // quand un clic survient, affecte la variable suivante // les coordonnées de la position actuelle du pointeur de la souris moveTankToX = e.stageX; moveTankToY = e.stageY; // et ajoute un écouteur d'événement pour déplacer le réservoir image par image addEventListener (Event.ENTER_FRAME, moveTankOnEnterFrame);
Créez une nouvelle fonction privée appelée moveTankOnEnterFrame () et appelez-y une méthode moveToCoordinates () avec 3 paramètres:
fonction privée moveTankOnEnterFrame (e: Event) moveToCoordinates (réservoir, moveTankToX, moveTankToY);
Cela entraînera éventuellement le char de conduire vers le point cliqué, chaque image.
Nous avons maintenant appelé la méthode moveToCoordinates () mais nous ne l’avons pas encore créée. Faisons-le maintenant.
Les tX et tY ne seront pas utilisés, mais nous devons créer autant de paramètres que nous avons appelés. Voici à quoi ça ressemble:
fonction privée moveToCoordinates (tank_mc: Tank, tX: Number, tY: Number) // crée une variable pour conserver l'angle relatif // entre la position actuelle de la souris en degrés // et la position actuelle du réservoir // cette variable existe uniquement à l'intérieur de celle-ci fonction donc // vous pouvez utiliser le même nom que nous utilisions avant var angle: Number; // calcule l'angle (rappelez-vous moveMouseListener? // on fait la même chose ici mais avec le char lui-même) if (Math.round (Atan2 * 180 / Math.PI) < 0) angle = Math.round(Atan2 * 180 / Math.PI) + 360; else angle = Math.round(Atan2 * 180 / Math.PI); if (angle > 240 && angle < 300) tank.gotoAndStop(1); if (angle > 300 && angle < 340) tank.gotoAndStop(2); if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) tank.gotoAndStop(3); if (angle > 20 && angle < 60) tank.gotoAndStop(4); if (angle > 60 && angle < 120) tank.gotoAndStop(5); if (angle > 120 && angle < 160) tank.gotoAndStop(6); if (angle > 160 && angle < 200) tank.gotoAndStop(7); if (angle > 200 && angle < 240) tank.gotoAndStop(8); // give the clickPoint a value of a current mouse position // when a click occurs clickPoint = x:moveTankToX, y:moveTankToY; // calculate the angle in radians between the pointer's // current position and tank Atan2 = Math.atan2(clickPoint.y - tank_mc.y, clickPoint.x - tank_mc.x); // now add a value of Atan2 cosine to the tank's X position // and sine to its Y position every frame tank_mc.x += Math.cos(Atan2) * tankSpeed; tank_mc.y += Math.sin(Atan2) * tankSpeed; // now give the values to currentTankPositionX and // currentTankPositionY which we used in our mouseMoveListener currentTankPositionX = tank_mc.x; currentTankPositionY = tank_mc.y; // and finally a little trick. Since we don't want our tank to // start chaotically vibrating when it reaches its destination // we must calculate the distance between the tank's position and // the click point, and if it's less than 15, remove the ENTER_FRAME listener if (Math.abs(tank_mc.x - clickPoint.x) < 15 && Math.abs(tank_mc.y - clickPoint.y) < 15) removeEventListener(Event.ENTER_FRAME,moveTankOnEnterFrame);
Pourquoi utiliser une distance de 15? Eh bien, j'ai découvert que cela ne dépasse jamais 15 en le traçant simplement comme ceci:
trace (Math.abs (tank_mc.x - clickPoint.x));
… Tu peux faire la même chose si tu veux;)
Notre classe étant prête, examinons-la dans son ensemble:
package main import flash.display. *; importer flash.events. *; classe publique TankMaker étend Sprite private var tank: Tank; var privé moveTankToX: Number; var privé moveTankToY: Number; private var turnTurretToX: Nombre; private var turnTurretToY: Nombre; private var currentTankPositionX: Number; private var currentTankPositionY: Number; private var tankSpeed: Nombre = 2; private var clickPoint: Object; var privée Atan2: Number; tourelle var privéeAtan2: Nombre; fonction publique TankMaker () addEventListener (Event.ADDED_TO_STAGE, addStage); fonction privée addStage (e: Event): void tank = new Tank (); tank.scaleX = 0,25; tank.scaleY = 0,25; tank.x = stage.stageWidth / 2; tank.y = stage.stageHeight / 2; addChild (réservoir); stage.addEventListener (MouseEvent.MOUSE_DOWN, mouseDownListener); stage.addEventListener (MouseEvent.MOUSE_MOVE, mouseMoveListener); fonction privée mouseMoveListener (e: MouseEvent): void angle var: nombre; turnTurretToX = e.stageX; turnTurretToY = e.stageY; tourelleAtan2 = Math.atan2 (turnTurretToY - currentTankPositionY, turnTurretToX - currentTankPositionX); if (Math.round (tourelleAtan2 * 180 / Math.PI) < 0) angle = Math.round(turretAtan2 * 180 / Math.PI) + 360; else angle = Math.round(turretAtan2 * 180 / Math.PI); if (angle > 240 && angle < 300) tank.mTurret.gotoAndStop(1); if (angle > 300 && angle < 340) tank.mTurret.gotoAndStop(2); if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) tank.mTurret.gotoAndStop(3); if (angle > 20 && angle < 60) tank.mTurret.gotoAndStop(4); if (angle > 60 && angle < 120) tank.mTurret.gotoAndStop(5); if (angle > 120 && angle < 160) tank.mTurret.gotoAndStop(6); if (angle > 160 && angle < 200) tank.mTurret.gotoAndStop(7);; if (angle > 200 && angle < 240) tank.mTurret.gotoAndStop(8); private function mouseDownListener(e:MouseEvent):void moveTankToX = e.stageX; moveTankToY = e.stageY; addEventListener(Event.ENTER_FRAME,moveTankOnEnterFrame); private function moveTankOnEnterFrame(e:Event) moveToCoordinates(tank, moveTankToX, moveTankToY); private function moveToCoordinates(tank_mc:Tank, tX:Number, tY:Number) var angle:Number; if (Math.round(Atan2 * 180 / Math.PI) < 0) angle = Math.round(Atan2 * 180 / Math.PI) + 360; else angle = Math.round(Atan2 * 180 / Math.PI); if (angle > 240 && angle < 300) tank.gotoAndStop(1); if (angle > 300 && angle < 340) tank.gotoAndStop(2); if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) tank.gotoAndStop(3); if (angle > 20 && angle < 60) tank.gotoAndStop(4); if (angle > 60 && angle < 120) tank.gotoAndStop(5); if (angle > 120 && angle < 160) tank.gotoAndStop(6); if (angle > 160 && angle < 200) tank.gotoAndStop(7); if (angle > 200 && angle < 240) tank.gotoAndStop(8); clickPoint = x:moveTankToX, y:moveTankToY; Atan2 = Math.atan2(clickPoint.y - tank_mc.y, clickPoint.x - tank_mc.x); tank_mc.x += Math.cos(Atan2) * tankSpeed; tank_mc.y += Math.sin(Atan2) * tankSpeed; currentTankPositionX = tank_mc.x; currentTankPositionY = tank_mc.y; if (Math.abs(tank_mc.x - clickPoint.x) < 15 && Math.abs(tank_mc.y - clickPoint.y) < 15) removeEventListener(Event.ENTER_FRAME,moveTankOnEnterFrame);
Aller à Fichier> Nouveau, et créez un nouveau fichier ActionScript. Enregistrez-le sous "Game.as" dans le même dossier que votre fichier tank.fla. Ce sera notre classe de document.
Voici le code pour la classe Game.as:
package import flash.display. *; // importer le contenu de notre dossier principal import main. *; public class Game s'étend sur MovieClip private var newTank: TankMaker; fonction publique Game () // crée une nouvelle instance de notre classe de construction de réservoirs newTank = new TankMaker (); // et l'ajouter à l'étape du cours addChild (newTank);
Enregistrez le fichier. Tout ce qu’il fait est de créer un char et de l’ajouter à la scène principale, prêt à être contrôlé.
Ouvrez tank.fla et accédez au panneau Propriétés. Pour le type de classe dans "Jeu" et enregistrez le fichier.
Aha! Nous y voilà. Vous pouvez maintenant appuyer sur CTRL + ENTRÉE sur PC (CMD + RETURN sur Mac) et tester le jeu..
J'espère que vous avez apprécié ce tutoriel, merci d'avoir lu :)