Construire un système efficace de décalcomanies Flash

J'ai eu l’idée de créer ce que j’appelle des décalques Flash à partir des autocollants fournis avec les modèles d’avion et qui utilisent des «décalcomanies» pour maquiller mes propres applications Flash depuis. Un DecalSheet est en gros une grande image (.JPG, .PNG ou .GIF) qui est découpée en images plus petites appelées 'Decals', qui sont des bitmaps et peuvent être utilisées n'importe où DisplayObjects serait utilisé..

Cette technique est l’un des moyens les plus efficaces d’apporter beaucoup d’actifs dans une application Flash sans faire appel à la bibliothèque (si vous utilisez Flash IDE) ou à la balise incorporée (si vous utilisez le compilateur Flex). Voyons comment créer un système DecalSheet simple.

Avec DecalSheets, vous pouvez réduire l'encombrement de la mémoire de votre application en consolidant des images plus petites en images plus grandes. Tout graphique que vous souhaitez intégrer à une classe ou à un lieu dans une bibliothèque FLA peut être stocké dans une seule feuille de décalcomanie ou réparti sur plusieurs feuilles de décalcomanie, selon vos besoins. Etant donné que DecalSheets peut être configuré pour ne charger que lorsque cela est demandé, vous pouvez charger les graphiques d'application exactement quand vous en avez besoin, ce qui réduit le temps de démarrage et de chargement initial. Enfin, vous pouvez modifier l’ensemble de votre application en modifiant simplement le BitmapData de vos DecalSheets au moment de l’exécution..

Ce diagramme illustre comment nous prenons une seule image DecalSheet et utilisons les coordonnées pour découper un nouveau décalque..

Dans ce tutoriel, nous allons créer 2 classes: le DecalSheet et le Decal. Vous définissez les coordonnées X, Y, Largeur et Hauteur pour découper les graphiques du DecalSheet et celui-ci renverra des Décalques. Les décalcomanies sont des bitmaps et peuvent être utilisées partout où DisplayObjects serait normalement utilisé. Ce qui rend les décalques spéciaux, c'est qu'ils conservent une référence à la feuille de décalcomanies à partir de laquelle ils ont été découpés. Lorsque vous mettez à jour le BitmapData de DecalSheet, tous les décalques découpés dans cette feuille seront également mis à jour. Cela vous permet de redéfinir l'apparence d'une application entière au moment de l'exécution en chargeant simplement dans de nouvelles images source..

L'exemple suivant montre notre source DecalSheet à gauche et un SimpleButton à droite à l'aide de Decals pour chaque état de bouton. Lorsque vous cliquez sur le bouton, une nouvelle image est chargée et ses données bitmap remplacent l'enveloppe d'origine dans la feuille de décalcomanie. Tous les décalques du bouton simple seront également mis à jour. Le re-skinning est presque instantané!

À la fin du tutoriel, vous aurez le fichier .SWF suivant:

Feuille de décalcomanie Source Images

Avant de commencer, assurez-vous que vous avez les deux images suivantes. Ce seront nos sources DecalSheet que nous utiliserons pour couper les états des boutons de.


button_skin_a.png
button_skin_b.png

Étape 1: Configuration de la classe de document

La première chose à faire est de créer notre classe de document principal. J'ai déjà mis en place une classe simple qui va charger une image et l'ajouter à la liste d'affichage.

 package import flash.display.Bitmap; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.net.URLRequest; Classe publique DeaclSheetTutorial étend Sprite private var loader: Loader; fonction publique DeaclSheetTutorial () configureStage (); loadDecalSheetSource ("images / button_skin_a.png");  fonction privée configureStage (): void stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE;  fonction publique loadDecalSheetSource (url: String): void loader = new Loader (); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onImageLoad); loader.load (nouvelle URLRequest (url));  fonction privée onImageLoad (événement: événement): void loader.removeEventListener (Event.COMPLETE, onImageLoad); var bitmap: Bitmap = Bitmap (loader.content); addChild (bitmap); 

Lorsque vous exécutez cette classe, vous devriez voir notre button_skin_a.png être affiché sur la scène. Maintenant nous sommes prêts à commencer à créer notre décalque.

Étape 2: Création de la classe DecalSheet

Le DecalSheet étend la classe Bitmap. J'ai configuré mes classes dans des packages "com.flashartofwar" mais vous êtes libre de les configurer comme vous le souhaitez. Créez une nouvelle classe appelée DecalSheet et collez-la dans le code suivant:

package com.flashartofwar import flash.display.BitmapData; import flash.display.Bitmap; Classe publique DecalSheet étend Bitmap fonction publique DecalSheet (bitmapData: BitmapData = null, pixelSnapping: String = "auto", smoothing: Boolean = false) super (bitmapData, pixelSnapping, smoothing); 

Étape 3: Test de la décalcomanie

Maintenant que nous avons créé notre DecalSheet, assurons-nous qu'il peut afficher des images. Pour ce faire, nous allons passer le BitmapData du fichier .png que nous avons chargé précédemment. Retournez dans la classe de document et remplacez la ligne 40, où nous appelons addChild, par ce qui suit:

decalSheet = new DecalSheet (bitmap.bitmapData); addChild (decalSheet);

Nous allons aussi devoir importer la classe DecalSheet à la ligne 3:

importer com.flashartofwar.DecalSheet;

En plus de configurer une variable pour enregistrer notre DecalSheet à la ligne 16:

private var decalSheet: DecalSheet;

Maintenant, lorsque vous compilez, vous devriez voir la même image, mais elle se trouve maintenant dans la feuille de décalcomanie. Parlons de la façon dont nous pouvons couper ces graphiques.

Étape 4: Stockage des décalques dans la feuille de décalques

À ce stade, nous avons une classe DecalSheet simple qui étend la classe Bitmap. Notre objectif est de pouvoir définir les zones de la décalcomanie pouvant être découpées et transformées en décalcomanies. Avant de pouvoir enregistrer des décalques, nous allons avoir besoin d’un endroit pour les stocker..

Ajoutez la propriété suivante à la ligne 8:

protected var decalRectangles: Dictionary = nouveau dictionnaire (true);

Et importez la classe Dictonary à la ligne 5:

import flash.utils.Dictionary;

Comme vous pouvez le constater, ce dictionnaire sera l’endroit où nous pourrons associer le nom d’un autocollant à ses coordonnées..

Étape 5: Enregistrement des décalques

À la base, un décalque est en réalité juste un nom et ses valeurs X, Y, Largeur et Hauteur que nous utilisons pour couper BitmapData à partir du DecalSheet. Nous allons enregistrer cette information avec la fonction suivante sur la ligne 16.

fonction publique registerDecal (name: String, rectangle: Rectangle): void decalRectangles [name] = rectangle; 

Maintenant, vous pouvez associer les coordonnées de découpe d'un décalque à un nom et à un rectangle.

Vous devrez également importer la classe Rectangle à la ligne 5:

import flash.geom.Rectangle;

Étape 6: Exemple de méthode de décalcomanie

Nous allons ajouter la fonction la plus importante de DeaclSheet, la méthode sample (). Cette fonction est ce que nous allons utiliser pour découper BitmapData à partir de DecalSheet afin de créer nos décalcomanies. Mettons la fonction suivante à la ligne 22 de la classe DecalSheet.

exemple de fonction publique (name: String): BitmapData var rect: Rectangle = decalRectangles [name]; // Applique le décalage correct lors de l'échantillonnage des données var m: Matrix = new Matrix (); m.translate (-rect.x, -rect.y); // Crée un nouveau BitmapData var bmd: BitmapData = new BitmapData (rect.width, rect.height, true, 0xffffff); bmd.draw (bitmapData, m); retourner bmd; 

Vous devrez également importer la classe de matrice à la ligne 5:

import flash.geom.Matrix;

Il y a beaucoup de choses dans cette fonction, alors allons-y ligne par ligne dans le processus.

var rect: Rectangle = decalRectangles [nom];

Ici, nous utilisons le nom passé dans l’autocollant pour rechercher le rectangle enregistré dans l’autocollantRectangles Dictonary.

Ensuite, nous allons créer une matrice pour décaler où nous échantillonnons le BitmapData de.

var m: Matrix = new Matrix (); m.translate (-rect.x, -rect.y);

Ici, nous utilisons les positions X et Y du rectangle pour créer le décalage d'échantillon approprié.

Nous devons maintenant créer un nouveau BitmapData pour stocker notre découpe..

var bmd: BitmapData = new BitmapData (rect.width, rect.height, true, 0xffffff);

Comme vous pouvez le constater, nous utilisons la largeur et la hauteur du rectangle comme nouvelles dimensions, définissons le paramètre transparent sur true et attribuons au nouveau BitmapData une couleur d'arrière-plan de 0xffffff. En définissant transparent sur true et en fournissant une couleur d'arrière-plan, nous pourrons échantillonner correctement les images .png transparentes telles que les exemples "button_skin" que nous chargeons..

Enfin, nous devons dessiner les BitmapData DecalSheets dans la nouvelle instance de la classe BitmapData et appliquer la matrice.

bmd.draw (bitmapData, m);

Nous avons maintenant notre bitmapData composé et nous renvoyons simplement la nouvelle instance BitmapData.

Étape 7: Test de la méthode exemple

Avant d'aller plus loin, nous allons vouloir faire quelques choses simples pour tester notre nouvelle méthode exemple DecalSheet. Retournons dans notre classe de document et ajoutons la fonction suivante à la ligne 49 après la méthode onImageLoad:

fonction publique registerDecals (): void decalSheet.registerDecal ("up", new Rectangle (0,0,99,31)); decalSheet.registerDecal ("down", nouveau rectangle (0,32,99,31)); decalSheet.registerDecal ("sur", nouveau rectangle (99,0,99,31)); 

Vous pouvez voir ici que nous enregistrons chacun des états de bouton dont nous aurons besoin ultérieurement lorsque nous créerons notre SimpleButton. Vous devrez importer la classe Rectangle à la ligne 11:

import flash.geom.Rectangle;

… Ainsi que l'ajout de l'appel à registerDecals à la ligne 46, à l'intérieur de la fonction onImageLoad après l'ajout de DecalSheet à la scène.

registerDecals ();

Nous allons maintenant créer une dernière fonction au bas de notre classe, autour de la ligne 54:

fonction publique decalSheetDemo (): void var sampleBitmap: Bitmap = new Bitmap (decalSheet.sample ("up")); sampleBitmap.x = 230; addChild (sampleBitmap); 

Cette fonction constituera notre principale zone de préparation pour le reste de la démo. En ce moment, nous créons un nouveau bitmap à partir des coordonnées "up" registeredDecal "du haut" de DecalSheet, en décalant sa position x et en l'ajoutant à la scène.

Nous appellerons cette fonction après l'appel de registerDecals que nous avons ajouté à onImageLoad autour de la ligne 46:

decalSheetDemo ();

Maintenant, si nous faisons une compilation, nous devrions voir notre image DecalSheet à gauche et notre image bitmap échantillonnée à partir de DecalSheet à droite. Vous pouvez tester tous les décalcomanies en remplaçant "up" par "up" ou "over". Maintenant, nous en avons assez pour commencer notre classe de décalcomanie.

Étape 8: Création de la classe d'autocollant

Tout comme le DecalSheet, le Decal étendra également la classe Bitmap. Toutefois, le décalque aura un objectif très spécialisé et reposera sur le DecalSheet pour fournir ses données BitmapData au lieu de les transmettre au constructeur. Créez une nouvelle classe appelée Decal and Coll dans le code suivant:

package com.flashartofwar import flash.display.Bitmap; public class Decal étend Bitmap protected var decalSheetSrc: DecalSheet; fonction publique Decal (name: String, src: DecalSheet, pixelSnapping: String = "auto", smoothing: Boolean = false) super (null, pixelSnapping, smoothing); // Enregistrer la source de la feuille d'autocollant. decalSheetSrc = src; // Enregistrer le nom du décalque afin que nous puissions l’échantillonner à partir de la décalcomanie. this.name = name; // Obtient des données bitmap de la src DecalSheet. rafraîchir();  fonction publique refresh (): void bitmapData = decalSheetSrc.sample (name); 

Alors, quoi de neuf? Comme vous pouvez le constater, nous modifions les arguments du constructeur à partir de ceux de BitmapClass d'origine. Notre décalque va avoir besoin de connaître son nom (nous l'utilisons pour demander BitmapData à DecalSheet via la méthode exemple) et nous devons connaître le décalque src avec lequel le décalque a été découpé..

En passant par le processus de construction, nous passons null à la propriété BitmapData du super avec toutes les valeurs passées pour pixelMapping et smoothing. Ensuite, nous sauvegardons une référence de la src DecalSheet dans la propriété deaclSheetSrc. Nous sauvegardons ensuite la valeur de nom passée dans la propriété de nom hérité de BitmapData. Nous utilisons "this" pour distinguer la différence entre le paramètre passé en et le paramètre name de l'instance de la classe. Enfin nous appelons la méthode refresh.

La méthode d'actualisation de l'autocollant effectue une tâche simple. Il demande un nouveau BitmapData à son DecalSheet parent et le définit. Cela crée l'affichage du décalque. Abandonner la logique pour demander BitmapData au DecalSheet parent jouera un rôle important ultérieurement lorsque nous commencerons à changer le BitampData du DecalSheet.

Étape 9: Renvoi des décalques de la décalcomanie

Avant de pouvoir vérifier que Decals fonctionne, nous voudrons ajouter la possibilité de demander des Decals par nom à DecalSheet et de lui renvoyer une instance Decal. Nous pouvons le faire en ajoutant la fonction suivante dans la feuille DecalSheet après la méthode registerDecal autour de la ligne 21:

fonction publique getDecal (name: String): Decal return decalRectangles [name]? nouvelle décalcomanie (nom, ceci): null; 

Maintenant, nous pouvons demander des décalcomanies à la décalcomanie en transmettant simplement le nom de toute décalcomanie enregistrée. Vous remarquerez ce raccourci conditionnel. Fondamentalement, le premier élément est ce que nous testons. Dans ce cas, nous voulons savoir si le nom fourni a été enregistré auprès de decalRectangles Dictonary. Le ? dénote ce qui se passe s'il existe. Ici, nous créons un nouveau décalque, donnons le même nom que celui qui a été transmis à la fonction getDecal et fournissons une référence de l'instance DecalSheet (this) au décalque. Le: indique ce qui se passe si le nom fourni n’a pas été trouvé sur le Dictonary deacalRectangles. Nous retournons simplement null. Testons cela pour nous assurer que tout fonctionne.

Étape 10: Test de la décalcomanie et de la décalcomanie

Nous sommes maintenant prêts à tester notre décalque. Pour ce faire, nous allons revenir à la classe de classe et remplacer la méthode decalSheetDemo par le code suivant:

fonction publique decalSheetDemo (): void var upDecal: Decal = decalSheet.getDecal ("up"); upDecal.x = 230; addChild (upDecal); 

Nous devrons également importer la classe de décalcomanies à la ligne 3:

importer com.flashartofwar.Decal;

Si vous compilez la classe, vous devriez voir le décalque à droite de l'instance DecalSheet à partir de laquelle il a été découpé. Alors, quel est le gros problème? Nous avions la même chose il y a 4 étapes avec moins de code. Eh bien, laissez-moi vous expliquer pourquoi il s’agit d’un moyen puissant d’apporter des ressources à votre application Flash..

Imaginez que vous avez une galerie de photos. Et si de nombreux sites utilisaient tous la même galerie de photos mais que vous deviez personnaliser chaque galerie de photos en fonction du site individuel sur lequel elle était hébergée. Selon la manière dont vous créez votre galerie de photos, vous pouvez décider de créer un fichier .SWF avec chaque bouton en tant qu'élément de la bibliothèque avec un ID de liaison. Ou vous pouvez charger chaque image individuelle une par une au moment de l'exécution. Pendant longtemps, j'ai utilisé les deux méthodes, mais je trouvais toujours trop contraignant d'attendre le chargement d'un fichier .SWF volumineux ou de plusieurs images plus petites jusqu'à la création du système DecalSheet..

Maintenant, je crée simplement une image DeaclSheet, je définit les coordonnées de chaque bouton et je n’ai plus qu’à gérer une image et certaines données découpées. Je mets généralement les coordonnées découpées dans un fichier .XML et je peux maintenant transmettre l'image à un concepteur qui ne connaît peut-être rien de Flash, mais qui peut créer facilement un nouveau thème à partir d'un modèle .PSD. Je sais que cela ressemble à un exemple unique, mais j'utilise ce système dans tous les sites Flash que je construis. Nous n'avons pas encore abordé la fonctionnalité la plus cool!

Que se passe-t-il si vous devez retoucher une application à la volée? Vous devez recharger toutes les images et créer de nouvelles instances de classe ou une logique dans vos composants pour pouvoir reconstituer les nouveaux actifs. Redéfinir l'apparence d'une application Flash construite avec Decals est aussi simple que de changer le BitmapData du DeaclSheet. Laisse moi te montrer comment.

Étape 11: Modification de DecalSheet BitmapData

Nous allons avoir besoin d'un moyen de dire à toutes les décalques découpées dans une feuille de décalcomanies que les données BitmapData ont été modifiées et qu'elles doivent être ré-échantillonnées. Nous pouvons le faire facilement en remplaçant la méthode set bitmapData de DecalSheet. Ajoutez la méthode suivante sous le constructeur DecalSheet à la ligne 17:

remplacer le jeu de fonctions public bitmapData (valeur: BitmapData): void super.bitmapData = valeur; dispatchEvent (nouvel événement (Event.CHANGE)); 

… Avec une déclaration d'importation pour Event à la ligne 5:

import flash.events.Event;

Maintenant qu'un nouvel événement est distribué chaque fois que le BitmapData de DecalSheet est modifié, nous devrons l'écouter dans la classe Decal..

Étape 12: Écoute d'événements de décalcomanie

Maintenant que le DecalSheet distribue un événement de changement lorsque son BitmapData est mis à jour, le Decal peut écouter ces événements et rééchantillonner son propre BitmapData à partir du DecalSheet. Ajoutons les 3 méthodes suivantes dans la classe Decal sous la fonction d'actualisation à la ligne 27:

fonction protégée addListeners (target: IEventDispatcher): void target.addEventListener (Event.CHANGE, onChange, false, 0, true);  function protégée removeListeners (target: IEventDispatcher): void target.removeEventListener (Event.CHANGE, onChange);  fonction protégée onChange (event: Event): void refresh (); 

Nous devons également importer les classes IEventDispatcher et Event à la ligne 4:

import flash.events.Event; import flash.events.IEventDispatcher;

Enfin, nous devrons appliquer l'écouteur à DecalSheet parent du décalque en ajoutant le code suivant à la fin du constructeur, à la ligne 23 du constructeur:

addListeners (src);

Avant de poursuivre, j'aimerais expliquer pourquoi je divise l'ajout et la suppression des écouteurs d'événement dans des fonctions distinctes. Chaque fois que je crée des classes, j'essaie de réfléchir à la manière dont je vais les étendre et aussi à la façon dont je peux casser la logique en parties les plus petites possibles. Ces 3 fonctions représentent une caractéristique essentielle du décalque et sont probablement les plus importantes que nous voudrions modifier lors de l’extension de cette classe. J'essaie également d'utiliser des interfaces autant que possible. Je l'explique plus en détail plus tard. Comme vous pouvez le constater, nous pouvons facilement ajouter et supprimer les écouteurs Change Event et nous appelons refresh lorsque l'instance Decal entend l'événement approprié. Dans la prochaine étape, nous allons construire notre SimpleButton et explorer cette nouvelle fonctionnalité..

Étape 13: Création d'un bouton simple

Revenons à la classe de document et créons un SimpleButton en utilisant tous les décalques que nous avons enregistrés dans le DecalSheet. Une fois encore, nous allons remplacer la fonction decalSheetDemo par le code suivant:

fonction publique decalSheetDemo (): void var up: Decal = decalSheet.getDecal ("up"); var over: Decal = decalSheet.getDecal ("over"); var down: Decal = decalSheet.getDecal ("down"); var myButton: SimpleButton = new SimpleButton (haut, haut, bas); myButton.useHandCursor = true; myButton.hitTestState = up; myButton.x = 230; this.addChild (myButton); 

Nous devons également importer SimpleButton à la ligne 8:

import flash.display.SimpleButton;

Nous allons donc maintenant configurer chacun des décalques, créer une nouvelle instance de SimpleButton et les transmettre au constructeur. Étant donné que SimpeButton utilise DisplayObjects pour chaque état et que nos décalques étend la classe Bitmap, nous pouvons les remplacer partout où les objets DisplayObjects sont utilisés. Compilez la classe de classe et vérifiez le bouton. Vous verrez que les décalques sont affichés lorsque le bouton change d'état..

Étape 14: Mise à jour des BitmapData de la décalcomanie

Nous allons maintenant charger notre deuxième peau de bouton "button_skin_b.png"et remplacez BitmapData du DecalSheet. Puisque les décalques écoutent l'événement Change de DecalSheet, nous serons en mesure de redéfinir le SimpleButton sans changer une seule propriété sur celui-ci..

Ce diagramme montre comment, en modifiant les valeurs BitmapData de DecalSheet, nous pouvons diffuser un événement à tous les enfants. Décalques à rééchantillonner..

Commençons par ajouter dans le programme d'écoute d'événement suivant le bouton de la ligne 72 de la classe de document après l'ajout du bouton à la liste d'affichage:

myButton.addEventListener (MouseEvent.CLICK, onClick);

Une fois que cela est en place, ajoutons les trois méthodes suivantes sous la fonction decalSheetDemo:

fonction privée onClick (event: MouseEvent): void loadBlueSkin ("images / button_skin_b.png") fonction privée loadBlueSkin (url: String): void loader = new Loader (); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onBlueSkinLoaded); loader.load (nouvelle URLRequest (url));  fonction privée onBlueSkinLoaded (événement: événement): void loader.removeEventListener (Event.COMPLETE, onImageLoad); var bitmap: Bitmap = Bitmap (loader.content); decalSheet.bitmapData = bitmap.bitmapData; 

Enfin, nous aurons besoin d’importer MouseEvent à la ligne 13:

import flash.events.MouseEvent;

Ce que nous avons fait ici est ajouté un écouteur Click Event au SimpleButton. Lorsque nous entendons ce déclic, nous commençons à charger la nouvelle skin. Une fois que le skin est chargé, nous tapons le contenu du chargeur sous forme de bitmap et passons son bitmapData dans le setter bitmapData du DecalSheet. Lorsque vous exécutez ceci maintenant et cliquez sur le bouton, vous verrez instantanément le skin de SimpleButton et DecalSheet seront mis à jour pour la nouvelle image. Le changement est instantané!

Vous avez maintenant vu comment nous créons un DecalSheet, enregistrons des Decals, obtenons des Decals et habillons un SimpleButton. Nous allons également redéfinir le bouton au moment de l'exécution en chargeant simplement dans un nouveau graphique. Cela couvre le pouvoir d'utiliser des décalcomanies pour habiller votre application Flash. Les étapes suivantes nettoient simplement le code que nous avons écrit et ajoutent des fonctionnalités supplémentaires pour aider à étoffer le système DecalSheet.

Étape 15: Supprimer l'autocollant

Nous ne pouvons pas simplement laisser notre DecalSheet sans la possibilité de supprimer les décalques que nous avons enregistrés, ajoutons donc une méthode deleteDecal après la méthode registerDecal:

fonction publique deleteDecal (name: String): Boolean return delete decalRectangles [name]; 

Étape 16: Obtenir les noms d'autocollants enregistrés

Il serait probablement utile d’obtenir une liste de tous les noms de décalques enregistrés à partir d’un DecalSheet, ajoutons-le dans Array pour ne stocker que les noms de décalques. Nous devrons ajouter la propriété suivante après le décalque autour de la ligne 13:

public var decalNames: Array = new Array ();

Et remplacez les méthodes registerDecal et deleteDecal par les fonctions suivantes:

fonction publique registerDecal (name: String, rectangle: Rectangle): void decalRectangles [name] = rectangle; decalNames.push (nom);  fonction publique deleteDecal (name: String): Boolean index: nombre = decalNames.indexOf (name); if (index! = -1) decalNames.splice (index, 1); retour supprime decalRectangles [nom]; 

Nous pouvons le tester en exécutant ce qui suit dans la classe de classe:

trace ("Decals", decalSheet.decalNames); decalSheet.deleteDecal ("down"); trace ("Décalques restants", decalSheet.decalNames);

Étape 17: Détachez un décalque de la décalcomanie

La connexion entre le décalque et son décalque parent est incroyablement puissante, mais nous souhaitons parfois que les décalcomanies soient un peu plus indépendantes. C'est pourquoi nous allons ajouter une méthode detach à la classe Decal après la méthode onChange:

fonction publique detach (): void removeListeners (decalSheetSrc); decalSheetSrc = null; 

Une fois la méthode detach appelée, nous supprimons les écouteurs d'événement et supprimons la référence à la référence DecalSheet. Ceci déconnecte complètement toute relation avec le parent DecalSheet.

Étape 18: Création d'une interface de décalcomanie

L'un des concepts fondamentaux de la création de modèles et de modèles de conception orientés objet (OO) consiste à "Programmer une interface; pas une implémentation". Malheureusement, expliquer complètement ce concept dépasse le cadre de ce didacticiel, mais cela ne signifie pas pour autant que nous ne pouvons pas essayer de mettre en pratique certaines des meilleures pratiques. Si vous n'avez jamais utilisé d'interfaces auparavant, elles sont très simples. Toute interface ne définit qu'un ensemble de fonctions publiques qu'une classe doit contenir. Donc, dans notre système DecalSheet, nous allons créer une interface IDecalSheet et y taper notre Decal. Ceci maintiendra nos décalques faiblement couplés à la décalcomanie et permettra une grande flexibilité lors de l'extension de notre système..

Pour commencer, nous devrons créer une nouvelle interface dans le même package que nos classes DecalSheet et Decal. Voici la structure de l'interface:

package com.flashartofwar import flash.display.BitmapData; import flash.display.IBitmapDrawable; import flash.events.IEventDispatcher; import flash.geom.Rectangle; interface publique IDecalSheet étend IBitmapDrawable, IEventDispatcher function registerDecal (nom: String, rectangle: Rectangle): void; function deleteDecal (name: String): Boolean; fonction getDecal (name: String): Décalque; exemple de fonction (nom: String): BitmapData; 

Ainsi, dans notre interface, nous définissons les fonctions publiques les plus couramment utilisées qui composent notre DecalSheet. Notez également que même notre interface peut étendre d'autres interfaces. Nous allons étendre IBitmapDrawable et IEventDispatcher. Cela permettra à notre feuille de décalcomanie de faire les mêmes tâches que la classe Bitmap et nous pourrons envoyer et écouter les événements de celle-ci..

Maintenant, nous devons dire au DecalSheet d'implémenter cette interface. Allez dans la classe DecalSheet et remplacez la définition de classe autour de la ligne 10 par ce qui suit:

Classe publique DecalSheet expand Bitmap implémente IDecalSheet

Si votre interface est dans le même package que votre DecalSheet, vous n'avez pas à vous soucier de l'importation de l'interface IDecalSheet..

Ensuite, nous devons implémenter l'interface dans notre classe de décalcomanies. Partout où nous utilisons le type DecalSheet, nous voudrons le remplacer par IDecalSheet:

Autour de la ligne 9:

protected var decalSheetSrc: IDecalSheet;

Autour de la ligne 11:

fonction publique Decal (name: String, src: IDecalSheet, pixelSnapping: String = "auto", smoothing: Boolean = false)

Autour de la ligne 32:

fonction protégée addListeners (target: IDecalSheet): void

Autour de la ligne 37:

fonction protégée removeListeners (target: IDecalSheet): void

Maintenant, notre décalcomanie est complètement saisie dans l'interface de la décalcomanie à la place de la classe réelle. Nous avons également imposé à toute classe qui souhaite utiliser la classe de décalcomanie de mettre en œuvre toutes les mêmes fonctions publiques que DeccalSheet.

Étape 19: Effacer les décalcomanies de la décalcomanie

La dernière fonctionnalité que nous ajouterons est la possibilité d'effacer une décalcomanie de décalcomanies et de déconnecter toute décalcomanie instanciée liée à la décalcomanie. Pour commencer, ajoutons la méthode suivante à DecalSheet:

fonction publique clear (): void dispatchEvent (nouvel événement (Event.DEACTIVATE, true, true)); decalRectangles = nouveau dictionnaire (true); decalNames = new Array (); 

Maintenant, lorsque nous appelons la méthode clear sur DecalSheet, nous envoyons un événement Deactivate et supprimons le Dictonary et le Array. Nous devons maintenant ajouter un écouteur d'événement à l'autocollant. Dans la classe Decal, remplacez les fonctions addListeners et removeListeners par les suivantes:

fonction protégée addListeners (target: IDecalSheet): void target.addEventListener (Event.CHANGE, onChange, false, 0, true); target.addEventListener (Event.DEACTIVATE, onDeactivate);  fonction protégée removeListeners (target: IDecalSheet): void target.removeEventListener (Event.CHANGE, onChange); target.removeEventListener (Event.DEACTIVATE, onDeactivate); 

Nous devrons également ajouter la méthode suivante après la fonction onChange:

fonction protégée onDeactivate (event: Event): void event.stopPropagation (); détacher(); 

Nous pouvons vérifier que tous les décalcomanies ont été déconnectés en appelant la méthode clear sur la feuille DecalSheet, puis en essayant de modifier la valeur BitmapData de la feuille DecalSheet. Vous verrez que les décalcomanies ne se mettent plus à jour..

Étape 20: Extension du système de décalcomanies

Il y a beaucoup de possibilités d'étendre le système DecalSheet. Une retombée intéressante est de faire TextField DecalSheet. Vous pouvez facilement créer une classe DecalSheet qui implémente l'interface IDecalSheet, mais au lieu d'utiliser BitmapData, elle prendrait plutôt un TextField et le diviserait en décalcomanies. En utilisant TextLineMetrics, des décalcomanies peuvent être créées en allant ligne par ligne sur un champ TextField ou caractère par caractère. C’est un excellent moyen de déplacer du texte sur l’écran et d’éviter les distorsions que vous rencontrez parfois lors du déplacement de TextField animés..

PaperVision est également un autre excellent endroit pour utiliser DecalSheets. Imaginez pouvoir mettre à jour un modèle 3D à la volée! En définissant les décalques comme textures, vous pouvez mettre à jour les BitmapData du DecalSheet pour changer l’image de vos modèles 3D..

La fin!