Détruit une image avec un effet de vent personnalisé

Deux fois par mois, nous revoyons certains des articles préférés de nos lecteurs dans l’histoire d’Activetuts +. Ce tutoriel a été publié pour la première fois en mars 2010.

Dans ce didacticiel, nous allons créer une classe personnalisée qui décompose une image en mille morceaux et simule un vent qui les chasse. J'ai créé ce projet uniquement avec AS3 et FlashDevelop - Flash non requis!


Aperçu du résultat final

Jetons un coup d'œil au résultat final sur lequel nous allons travailler. Allez-y et cliquez n'importe où dans le fichier SWF:


Introduction rapide à FlashDevelop

FlashDevelop est un éditeur de code gratuit pour Flash et Flex. Vous pouvez l'utiliser pour modifier vos fichiers de classe lorsque vous travaillez avec le logiciel Flash ou créer un projet AS3 ne nécessitant pas du tout Flash - et c'est exactement ce que nous allons faire dans ce tutoriel..

Alors téléchargez FlashDevelop et installez-le. Malheureusement, FlashDevelop ne fonctionne que sous Windows. Les alternatives Mac incluent FDT et Flex Builder, bien qu’aucune d’elles ne soit gratuite. Vous pouvez utiliser Flash lui-même, et je vais vous expliquer comment procéder au fur et à mesure..


Étape 1: Créer un nouveau projet

Ouvrez FlashDevelop et cliquez sur Projet> Nouveau projet.?


Étape 2: Configuration

Choisissez Actionscript 3> Projet AS3. Pour le nom du projet, entrez "WindEffect". Pour l'emplacement, cliquez sur et naviguez jusqu'au dossier dans lequel vous souhaitez l'enregistrer. Laissez la case "Créer un répertoire pour le projet" cochée et cliquez sur OK.

Si vous souhaitez utiliser Flash CS3 / CS4, créez un nouveau fichier Flash et définissez la largeur et la hauteur de la scène sur 550x250px, définissez la couleur d'arrière-plan sur noir. Nommez-le "windEffect.fla" et enregistrez-le où vous voulez.


Étape 3: déplacer l'image source

Pour FlashDevelop, ouvrez le répertoire du projet et copiez ou faites glisser windEffect.jpg depuis le téléchargement source (lié en haut de la page) dans le dossier \ bin \..

Pour Flash, copiez ou faites glisser windEffect.jpg à partir du téléchargement source dans le même dossier que celui où vous avez windEffect.fla..


Étape 4: Installez TweenLite

Nous allons utiliser TweenLite de Greensock pour l’interpolation. Vous pouvez télécharger la dernière version du composant ici; Je l'ai aussi inclus dans le téléchargement source.

Pour FlashDevelop, copiez ou faites glisser greensock.swc du téléchargement source dans le dossier \ lib \ de ce projet..

Dans FlashDevelop, cliquez sur Afficher> Gestionnaire de projets.


Étape 5: Bibliothèque externe

Toujours dans FlashDevelop, cliquez sur le signe '+' situé à gauche du dossier lib pour le développer. Cliquez avec le bouton droit sur greensock.swc et sélectionnez Ajouter à la bibliothèque..

Pour Flash, copiez ou faites glisser le dossier \ com \ du téléchargement source dans le même dossier que votre fichier windEffect.fla..


Étape 6: La classe de document

Pour FlashDevelop, ouvrez à nouveau le gestionnaire de projet (voir l'étape 4), développez le dossier \ src \ et double-cliquez sur Main.as. Sous les importations et juste au-dessus de la définition de classe, ajoutez la balise de métadonnées suivante pour configurer les propriétés de l'étape:

[SWF (largeur = 550, hauteur = 250, frameRate = 30, backgroundColor = 0)]

Dans la méthode init () après le commentaire 'entry point', ajoutez le code suivant:

 stage.scaleMode = StageScaleMode.NO_SCALE; // ne pas étirer l'effet de scène var: WindEffect = new WindEffect ('windEffect.jpg'); // nous allons bientôt créer la classe WindEffect addChild (effect);

Voilà pour la classe de document Main.

Pour Flash, créez une nouvelle classe Main.as dans le même dossier que votre projet. Assurez-vous que la classe Main.as est dans le même dossier que le fla. & com dossier. Ajoutez les lignes suivantes:

package import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; classe publique Main étend Sprite fonction publique Main (): void if (stage) init (); sinon addEventListener (Event.ADDED_TO_STAGE, init);  fonction privée init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); stage.scaleMode = StageScaleMode.NO_SCALE; // ne pas étirer l'effet de scène var: WindEffect = new WindEffect ('windEffect.jpg'); // nous allons bientôt créer la classe WindEffect addChild (effect); 

Ouvrez Flash et affectez "Main" en tant que classe Document..

(Vous n’êtes pas sûr de quoi il s’agit? Lisez cette introduction rapide à l’utilisation d’une classe de document.)

Si vous essayez de l'exécuter maintenant, vous obtiendrez une erreur car nous n'avons pas encore créé la classe WindEffect. Assurez-vous simplement de sauvegarder le fichier et de le laisser pour le moment..


Étape 7: Créer la classe WindEffect

Pour FlashDevelop, cliquez sur Afficher> Gestionnaire de projets, cliquez avec le bouton droit sur le dossier \ src \ et choisissez Ajouter> Nouvelle classe..


Étape 8: Configuration de la classe

Nommez la classe WindEffect, cliquez sur le bouton de navigation de la classe de base et entrez flash.display.Sprite. Hit OK pour terminer.


Étape 9: Importer d'autres classes

Ajoutez toutes les importations nécessaires entre les crochets situés juste en dessous de 'import flash.display.Sprite;' et avant la définition de la classe. Cliquez sur Enregistrer.

import com.greensock.easing.Strong; importer com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest;

Pour Flash, créez un nouveau fichier ActionScript, nommez-le "WindEffect.as" et enregistrez-le dans le même répertoire que celui que vous avez utilisé. Il devrait être juste à côté de la fla. fichier, dossier com et Main.as.

Ajoutez le code suivant:

package import com.greensock.easing.Strong; importer com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest; Classe publique WindEffect étend Sprite fonction publique WindEffect () 

Étape 10: Ajouter une variable d'instance

Ajoutez une variable privée appelée "_pictureArray". C'est la seule variable que nous aurons dans cette classe. Son but principal est de faire référence à tous les petits sprites qui contiennent les petits morceaux de l'image une fois qu'elle a été décomposée..

Ajouter la ligne de code suivante entre crochets
de la classe:

Classe publique WindEffect: Sprite // ceci hébergera toutes les pièces de l'image que nous allons animer. private var _pictureArray: Array; 

Étape 11: Ajouter le constructeur

Ajoutez les lignes suivantes après la déclaration _pictureArray:

Classe publique WindEffect: Sprite // ceci hébergera toutes les pièces de l'image que nous allons animer. private var _pictureArray: Array; fonction publique WindEffect ($ url: String) // nous appelons simplement l'image de la charge dans le constructeur loadPicture ($ url); 

Étape 12: Accéder à l'image

Dans la méthode loadPicture () appelée par la méthode constructeur, nous instancions un chargeur pour charger le fichier windEffect.jpg. Nous ajoutons également un écouteur d'événement COMPLETE à écouter lorsque le chargement est terminé..

Ajoutez les lignes de code suivantes après la méthode WindEffect (). (Notez que le paramètre "$ url" est le chemin de l'image que nous chargeons, passée de Main.as.)

fonction privée loadPicture ($ url: String): void // nous créons un chargeur avec des écouteurs pour charger l'image source que nous utilisons. // et ensuite on charge l'image. var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); // lorsqu'il est chargé, appelez la fonction onLoadComplete () loader.load (new URLRequest ($ url)); 

Étape 13: Chargement

Une fois l'image correctement importée, cette méthode est appelée. Ajoutez les lignes de code suivantes après la méthode loadPicture () et enregistrez le fichier..

fonction privée onLoadComplete (e: Event): void // pour tester addChild (e.target.content); 

Étape 14: Testez un

Allez-y et appuyez sur CTRL + Entrée sur votre clavier. Cela devrait fonctionner et l'image devrait se trouver dans le coin supérieur gauche de la scène.

Maintenant que nous avons vérifié qu'il se charge correctement, supprimez la méthode addChild et remplacez-la par le code suivant:

createEffect (e.target.content);

Votre classe WindEffect devrait ressembler à ceci:

package import com.greensock.easing.Strong; importer com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest; [SWF (largeur = 550, hauteur = 250, frameRate = 30, backgroundColor = 0)] classe publique WindEffect étend Sprite private var _pictureArray: Array; fonction publique WindEffect ($ url: String) loadPicture ($ url); 
 fonction privée loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (nouvelle URLRequest ($ url));  fonction privée onLoadComplete (e: Event): void createEffect (e.target.content); 

Étape 15: Configurer les variables

La méthode createEffect () prend le paramètre image qui est essentiellement un bitmap et le décompose en 1250 pièces..

Nous calculons d’abord les positions x et y pour centrer l’image sur la scène. Nous les sauvegardons dans des variables locales appelées centerWidth et centerHeight.

La taille de l'image utilisée étant de 300x100, j'ai décidé de diviser l'image 50 fois horizontalement et 25 fois verticalement. Ces valeurs ont donné un résultat assez décent avec des performances optimales. Nous les sauvegardons dans des variables locales, que j'ai nommées "numberOfColumns" et "numberOfRows".

Nous enregistrons le résultat de la division de la largeur de l'image par numberOfColumns en "sizeWidth" et le résultat de la division de la hauteur de l'image par numberOfRows en "sizeHeight".

La variable "numberOfBoxes" contient numberOfColumns multiplié par numberOfRows.

Ensuite, nous instancions _pictureArray pour pouvoir y insérer de petits sprites. Ajoutez les lignes de code suivantes après la méthode onLoadComplete ():

fonction privée createEffect ($ bitmap: Bitmap): void // centre l'image horizontalement. var centerWidth: Number = (stage.stageWidth - $ bitmap.width) * .5; // centre l'image verticalement. var centerHeight: Number = (stage.stageHeight - $ bitmap.height) * .5; var numberOfColumns: uint = 50; var numberOfRows: uint = 25; var sizeWidth: uint = $ bitmap.width / numberOfColumns; var sizeHeight: uint = $ bitmap.height / numberOfRows; var numberOfBoxes: uint = numberOfColumns * numberOfRows; _pictureArray = []; 

Étape 16: boucles imbriquées

Après instanciation de _pictureArray, nous ajouterons deux boucles, l'une dans l'autre. La première boucle gère le déplacement sur la position x et parcourt toutes les colonnes, tandis que la seconde boucle se déplace sur la position y et parcourt toutes les lignes..

Ajoutez les lignes de code suivantes dans la méthode createEffect () juste après l'instanciation de _pictureArray, puis enregistrez le fichier:

pour (var i: uint = 0; i < numberOfColumns; i++)  //these loops are what splits the image into 1250 pieces. for (var j:uint = 0; j < numberOfRows; j++)  //let's see what it does. trace ('i:' + i, 'j:' + j);  

Étape 17: Testez deux

Testez le film en appuyant sur CTRL + Entrée.

Comme vous pouvez le voir, pour chaque je il y a une boucle complète de j. Ceci est appelé "boucles de nidification". Cela signifie que je qui représente l'axe des x reste sur une valeur alors que la seconde boucle itère pour l'axe des y.

En termes simples, nous commençons avec x = 0, y = 0; alors la prochaine itération est x = 0, y = 1; alors x = 0, y = 2, etc..

Lorsque y atteint la fin, la première boucle est incrémentée de 1, puis passe à nouveau à la 2ème boucle: x = 1, y = 0; x = 1, y = 1, x = 1, y = 2, etc. Cela continue jusqu'à la fin de la 1ère boucle.

Vous verrez ce que cela fait quand nous l'appliquerons à une manipulation de bitmap dans les prochaines lignes.


Étape 18: Division de l'image

Dans la deuxième boucle, supprimez la fonction de trace utilisée pour les tests. Chaque fois que nous bouclons, nous devons créer une petite image ayant la largeur de "sizeWidth" et la hauteur de "sizeHeight".

Cette petite image prend une photo d’une petite partie de l’image en partant du coin supérieur gauche vers la partie inférieure droite. Le "tempBitmapData" est où nous allons dessiner la petite partie de l'image. Le "sourceRect" est le rectangle que nous allons utiliser pour spécifier quelle partie de l'image sera copiée.

Ajoutez les lignes suivantes dans la deuxième boucle et enregistrez le fichier:

// 1 bitmapdata temporaire var tempBitmapData: BitmapData = new BitmapData (sizeWidth, sizeHeight); // 1 rectangle temporaire (x, y, largeur, hauteur) // nous passons i * sizeWidth pour le paramètre x & i * sizeHeight pour le paramètre y // et les dimensions sizeWidth & sizeHeight pour les paramètres width et height. var sourceRect: Rectangle = nouveau Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight); trace (sourceRect); // pour le test

Étape 19: Encore plus de tests

Testez le film. Ce qu’il fait maintenant est de créer un rectangle qui ajuste ses positions x et y à chaque itération..

Comme vous pouvez le constater, le premier exemple montre x = 0, y = 0 et le suivant est x = 0, y = 4. C'est ce que nous utilisons pour les limites de la capture instantanée prise à partir de l'image source. Supprimez la fonction de test lorsque vous êtes prêt à passer à autre chose.


Étape 20: BitmapData.copyPixels ()

Nous utilisons ensuite la méthode BitmapData.copyPixels () pour copier un petit morceau de l'image basé sur sourceRect. Les paramètres de cette méthode sont l'image bitmap à copier, la zone rectangle à copier et le point de destination où nous allons le copier..

Ajoutez la ligne de code suivante sous la déclaration sourceRect.

tempBitmapData.copyPixels ($ bitmap.bitmapData, sourceRect, nouveau point);

Nous créons ensuite un bitmap temporaire pour héberger le bitmapData que nous venons de copier et un sprite temporaire pour héberger ce bitmap.

Ensuite, nous poussons une référence de chaque Sprite sur _pictureArray pour un accès ultérieur. Après cela, nous ajoutons le Sprite à la scène avec les mêmes coordonnées que celles d'où nous l'avons copié, recréant ainsi l'image d'origine..

Nous décalons ensuite l'image de centerWidth et centerHeight pour la centrer correctement sur la scène.

Ajoutez les lignes de code suivantes et, encore une fois, enregistrez le fichier:

// nous créons ensuite 1 bitmap temporaire pour héberger les bitmapdata que nous venons de copier. var tempBitmap: Bitmap = new Bitmap (tempBitmapData); // et 1 sprite temporaire pour héberger le bitmap afin de permettre l'interactivité. var tempSprite: Sprite = new Sprite; // nous ajoutons simplement chaque boîte dans son propre sprite pour permettre l'interactivité, car les bitmaps ne sont pas interactifs. tempSprite.addChild (tempBitmap); // chaque image-objet est ajoutée dans le tableau _pictureArray pour un accès ultérieur. _pictureArray.push (tempSprite); // puis place chacun d'eux sur la scène. // Nous ajoutons la largeur et la hauteur du centre afin que l'image soit centrée sur la scène. tempSprite.x = i * sizeWidth + centerWidth; tempSprite.y = j * sizeHeight + centerHeight; addChild (tempSprite);

Étape 21: Testez trois

Allez-y et testez à nouveau. Vous devriez voir l'image correctement présentée sur la scène. On dirait même pas que ça a été séparé en 1250 pièces.

Juste après le crochet de fermeture de la deuxième boucle, avant de fermer la méthode, ajoutez la ligne de code suivante:

stage.addEventListener (MouseEvent.CLICK, blowWind);

Nous ajoutons un écouteur d'événement à la scène pour écouter un MouseEvent.CLICK. Cela déclenchera l'animation en exécutant la fonction blowWind (), que nous allons créer à l'étape suivante..

Votre classe WindEffect devrait ressembler à ceci:

package import com.greensock.easing.Strong; importer com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest; Classe publique WindEffect étend Sprite private var _pictureArray: Array; fonction publique WindEffect ($ url: String) loadPicture ($ url);  fonction privée loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (nouvelle URLRequest ($ url));  fonction privée onLoadComplete (e: Event): void createEffect (e.target.content);  fonction privée createEffect ($ bitmap: Bitmap): void var centerWidth: Number = (stage.stageWidth - $ bitmap.width) * .5; var centerHeight: Number = (stage.stageHeight - $ bitmap.height) * .5; var numberOfColumns: uint = 50; var numberOfRows: uint = 25; var sizeWidth: uint = $ bitmap.width / numberOfColumns; var sizeHeight: uint = $ bitmap.height / numberOfRows; var numberOfBoxes: uint = numberOfColumns * numberOfRows; _pictureArray = []; pour (var i: uint = 0; i < numberOfColumns; i++)  for (var j:uint = 0; j < numberOfRows; j++)  var tempBitmapData:BitmapData = new BitmapData (sizeWidth, sizeHeight); var sourceRect:Rectangle = new Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight); tempBitmapData.copyPixels ($bitmap.bitmapData, sourceRect, new Point); var tempBitmap:Bitmap = new Bitmap (tempBitmapData); var tempSprite:Sprite = new Sprite; tempSprite.addChild (tempBitmap); _pictureArray.push (tempSprite); tempSprite.x = i * sizeWidth + centerWidth; tempSprite.y = j * sizeHeight + centerHeight; addChild (tempSprite);   stage.addEventListener (MouseEvent.CLICK, blowWind);   

Étape 22: Création de l'effet de vent

Commencez par supprimer l’écouteur d’événements MouseEvent.CLICK car nous n’avons besoin que cela se produise une seule fois. Ajoutez les lignes de code suivantes après la méthode createEffect ():

fonction privée blowWind (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, blowWind); 

Nous devons passer en revue tous les sprites que nous avons assignés à _pictureArray et les animer individuellement..

TweenLite est appliqué pour animer toutes les pièces vers la droite comme si du vent les soufflait.

Les paramètres sont les suivants: la cible de l'interpolation, la durée de l'interpolation, un objet variable contenant toutes les propriétés, ainsi que les valeurs auxquelles vous souhaitez appliquer l'interpolation..

Par exemple: TweenLite.to (cible, durée, x: 100, y: 100, rotation: 30, facilité: Strong.easeIn, onComplete: trace, onCompleteParams: ['bonjour']).

Les deux derniers paramètres de l'exemple ci-dessus sont utilisés pour la fin de l'interpolation. Le paramètre onComplete appelle la fonction de trace et le paramètre onCompleteParams envoie un tableau contenant la chaîne "hello" dans la fonction de trace..

Ajoutez les lignes de code suivantes juste après l'écouteur d'événements à supprimer:

pour (var i: uint = 0; i < _pictureArray.length; i++)  TweenLite.to ( _pictureArray[i], getRandomInRange (.25, 2, false),  x: stage.stageWidth + 100, y:_pictureArray[i].y + getRandomInRange (-100, 100, false),// rotation: getRandomInRange (-90, 90), ease:Strong.easeIn, onComplete:removeSprite, onCompleteParams:[_pictureArray[i]]  ); 

Dans l'implémentation réelle, lorsque nous appelons TweenLite depuis la boucle, nous affectons la cible à _pictureArray [itération en cours]..

Pour la durée, nous attribuons une valeur pour la durée de l'interpolation à une durée aléatoire comprise entre 0,25 seconde et 2 secondes..

L'objet variable contient 5 propriétés:

  • x: stage.stageWidth + 100 qui animera la propriété x du sprite.
  • y: _pictureArray [i] .y + getRandomRange (-100,100, false) qui obtiendra la position y du sprite actuel et ajoutera un nombre aléatoire compris entre -100 et 100 pour donner à l'animation un effet d'expansion.
  • rotation: getRandomRange (-90,90) fait pivoter l'image-objet actuelle de -90 à 90 degrés.
  • facilité: Strong.easeIn ce qui fait que l'interpolation commence lentement et s'accélère soudainement.
  • onComplete: removeSprite qui appelle la méthode removeSprite une fois que l'interpolation est terminée et que le Sprite n'est plus à l'écran.
  • onCompleteParams qui envoie le tableau [_pictureArray [itération actuelle]] comme paramètre pour removeSprite.

Étape 23: Méthode removeSprite ()

Cette méthode est appelée à partir de TweenLite lorsque l'animation d'une interpolation particulière est terminée. Nous supprimons simplement le Sprite de la liste d’affichage pour éviter tout encombrement. Ajoutez les lignes de code suivantes après la méthode blowWind ():

fonction privée removeSprite ($ sprite: Sprite): void removeChild ($ sprite); 

Étape 24: Méthode getRandomInRange ()

Je suis sûr que vous connaissez bien celle-ci (sinon, Carlos Yanez a écrit un petit conseil sur le sujet.) Ma version offre la possibilité de renvoyer des nombres entiers (int, uint) ou flottants (fractions)..

Ajoutez les lignes de code suivantes. Si vous utilisez FlashDevelop, vous pouvez l'enregistrer en tant qu'extrait de code personnalisé afin de l'ajouter facilement à tout cours / projet. Je l'ai déclaré comme une méthode statique publique pour une accessibilité complète.

Fonction statique publique getRandomInRange ($ min: nombre, $ max: nombre, $ arrondi: booléen = vrai): nombre if ($ arrondi) retourne Math.round (Math.random () * ($ max - $ min) + $ min); else return Math.random () * ($ max - $ min) + $ min; 

C'est tout! Lancer le film. Si quelque chose ne va pas, vérifiez votre code avec la classe WindEffect que j'ai incluse dans le téléchargement source..


Conclusion

La clé pour créer des effets sympas consiste à apprendre et à maîtriser à la fois la manipulation d'images et les classes d'interpolation d'animation telles que TweenLite. S'il vous plaît n'hésitez pas à laisser une note pour tous les commentaires, préoccupations ou suggestions. Merci d'avoir lu!