Chargement de données avec des commandes

Il est très courant de charger des données externes (telles que des fichiers SWF) pendant l'exécution, mais nous ne pouvons en lire ou en manipuler le contenu que lorsque les données sont complètement chargées. Habituellement, nous devons écouter l’événement complet envoyé par un Chargeur ou URLLoader objet qui charge les données pour la gestion de l'achèvement. Souvent, nous écrivons du code qui charge les données dans une fonction et écrivons du code qui gère l'achèvement du chargement dans une autre fonction, mais cela peut être amélioré en regroupant l'ensemble du processus de chargement…

Ce tutoriel explique comment créer une extension de chargement dans la structure de commande de mon précédent tutoriel, Thinking in Commands part 1 of 2, afin de regrouper le traitement de l'achèvement dans un seul endroit. Cette extension de chargement peut également être combinée avec le cadre de gestion de scène décrit dans Penser dans les commandes, partie 2 sur 2. De nombreuses classes utilisées dans ce tutoriel sont couvertes dans le tutoriel précédent. Je vous recommande donc de lire les tutoriels précédents avant de continuer..

De plus, ce tutoriel introduit le concept de gestionnaire de données, une "banque" centrale qui stocke les références aux objets de données. Vous pouvez enregistrer des données dans le gestionnaire de données avec une chaîne de clé unique, puis accéder aux données en fournissant la chaîne de clé correspondante. Cela vous évite d'avoir à garder des références d'objets de données et quelques problèmes de portée variable.

En passant, vous aurez besoin de la plate-forme GreenSock Tweening pour compléter ces exemples..


Pourquoi charger des données avec des commandes?

Normalement, nous traitons les données chargées dans la fonction complète d’écouteur d’événements. Cela sépare deux morceaux de code qui sont connectés logiquement. Et en regardant le code, votre flux de pensée peut être interrompu lorsque votre vue passe de la fonction de chargement à l'écouteur complet..

Regardons le déroulement logique d'une approche naïve de chargement de fichiers SWF.

Le chargeur charge un fichier SWF à partir d’une URL et le onComplete () la fonction est appelée par le dispatchEvent () méthode qui distribue un événement complet, où le dispatchEvent () La méthode est invoquée en interne par le chargeur. Eh bien, en fait, il est invoqué par le LoaderInfo objet qui appartient à la Chargeur objet, mais pour plus de simplicité, disons simplement le dispatchEvent () méthode est appelée par le chargeur.

Ensuite, dans le onComplete () la fonction, la doMoreStuff () la fonction est appelée après la fin du chargement et, comme son nom l'indique, fait plus de choses.

La logique de haut niveau est très linéaire: invoquez le Loader.load () méthode première, onComplete () en second lieu doMoreStuff () troisième. Cependant, comme vous le remarquerez dans le diagramme, l'appel de chaque fonction est intégré au corps de la fonction de la précédente, ce qui donne un code "imbriqué". À mon avis, si le flux logique d'une fonctionnalité donnée est linéaire, le code associé doit être écrit de manière linéaire et non imbriquée. Sinon, le code pourrait parfois devenir confus si le niveau d'imbrication de l'appel est trop élevé.

C'est à ce moment-là que l'approche du commandement entre en jeu. Le diagramme ci-dessous montre que le code est assez linéaire à l’aide de commandes, en ce sens que toutes les commandes sont chaînées linéairement par une commande série. Bien que le programme "dévie" dans la setProperties (), addChildLoader (), et doMoreStuff () les fonctions; leur invocation est linéaire.


Gestionnaire de données

D'accord, avant de passer à autre chose à propos du chargement, jetons d'abord un coup d'oeil à la Gestionnaire de données classe. Un gestionnaire de données vous permet d'associer une chaîne de clé à un objet de données et vous pouvez obtenir une référence à cet objet de données partout dans votre code. Avec le gestionnaire de données, vous n'avez pas à vous soucier de la conservation des références de données et des portées variables. Tout ce que vous avez à faire est d’enregistrer une donnée au gestionnaire avec une chaîne de clé.

Le codage est assez simple, comme indiqué ci-dessous:

 données de package import flash.utils.Dictionary; public class DataManager // un dictionnaire qui gère les relations chaîne-données privé statique var _data: Dictionary = new Dictionary (); // retourne l'objet de données associé à une chaîne de clé public static function getData (key: String): * return _data [key];  // enregistre un objet de données avec une chaîne de clé public static function registerData (key: String, data: *): void _data [key] = data;  // annule l'enregistrement d'une chaîne de clé fonction statique publique unregisterData (key: String): void delete _data [key];  // annule l'enregistrement de toutes les chaînes de clés fonction statique publique clearData (): void pour (clé var: Chaîne dans _data) delete _data [clé]; 

Ainsi, lorsque nous souhaitons enregistrer une chaîne de clé "myData" avec un objet de données, par exemple un sprite, nous pourrions écrire le code de la manière suivante:

 var sprite: Sprite = new Sprite (); DataManager.registerData ("myData", sprite);

Plus tard, n'importe où dans le code, nous pourrions écrire le code suivant pour obtenir une référence de l'image-objet et l'ajouter à une liste d'affichage. C'est aussi simple que cela, plus de problèmes liés à la gestion des références d'objet et des portées variables.

 var sprite: Sprite = DataManager. getData ("myData") en tant que Sprite; container.addChild (sprite);

Méthode de chargement naïf

Voyons maintenant comment la méthode de chargement naïf charge une image externe. Le code de chargement réside dans une fonction et le code de traitement d'achèvement dans une autre. Nous allons charger trois images et les ajouter à la scène une fois le chargement terminé. De plus, nous surveillerons la progression du chargement en écoutant les événements de progression..


Étape 1: Créer un document Flash

Ouvrir Flash et créer un nouveau document Flash.

Étape 2: Créer une barre de progression

Tracez une barre de progression sur la scène. c'est pour représenter la progression du chargement. Convertissez toute la barre de progression en un symbole et nommez-y "progressBar_mc". Dans le symbole de la barre de progression, convertissez la barre de progression interne en un autre symbole et attribuez-lui le nom d'occurrence "innerBar_mc"..


Étape 3: préparez les images

Placez trois images dans le même dossier que le fichier FLA, nommées "image1.jpg", "image2.jpg" et "image3.jpg". Voici à quoi ressemblent les trois images.


Étape 4: Créer la classe de document

Créez un nouveau fichier AS pour la classe de document pour le fichier FLA. Le code est assez simple et tous les détails sont expliqués dans les commentaires. Tout d'abord, trois chargeurs sont créés et le chargement commence. À chaque événement de progression, la barre de progression est mise à jour. Lorsque le chargement est terminé, la barre de progression disparaît et les trois images s’affichent une par une..

 package import com.greensock.TweenMax; import flash.display.DisplayObject; import flash.display.Loader; import flash.display.MovieClip; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; public class NaiveLoading étend MovieClip private var loader1: Loader; private var loader2: Loader; private var loader3: chargeur; fonction publique NaiveLoading () // réduction de la barre de progression à l'échelle zéro progressBar_mc.innerBar_mc.scaleX = 0; // créer des chargeurs loader1 = new Loader (); loader2 = nouveau chargeur (); loader3 = nouveau chargeur (); // ajouter des écouteurs de progression loader1.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, onProgress); loader2.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, onProgress); loader3.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, onProgress); // ajouter des écouteurs d'achèvement loader1.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete); loader2.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete); loader3.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete); // commence le chargement de loader1.load (new URLRequest ("image1.jpg")); loader2.load (new URLRequest ("image2.jpg")); loader3.load (new URLRequest ("image3.jpg"));  fonction privée onProgress (e: ProgressEvent): void // calcule le nombre total de bits pour charger var bytesTotal: uint = 0; bytesTotal + = loader1.contentLoaderInfo.bytesTotal; bytesTotal + = loader2.contentLoaderInfo.bytesTotal; bytesTotal + = loader3.contentLoaderInfo.bytesTotal; // calcule le nombre total de bits chargés var bytesLoaded: uint = 0; bytesLoaded + = loader1.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader2.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader3.contentLoaderInfo.bytesLoaded; // met à jour l'échelle de la barre de progression progressBar_mc.innerBar_mc.scaleX = bytesLoaded / bytesTotal;  private var _completeCount: int = 0; fonction privée onComplete (e: Event): void _completeCount ++; if (_completeCount < 3) return; //remove progress listeners loader1.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress); loader2.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress); loader3.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress); //remove completion listeners loader1.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete); loader2.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete); loader3.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete); var image1:DisplayObject = loader1.content; var image2:DisplayObject = loader2.content; var image3:DisplayObject = loader3.content; //adjust loaded image positions image1.x = 30, image1.y = 30; image2.x = 230, image2.y = 30; image3.x = 430, image3.y = 30; //add loaded images to display list addChild(image1); addChild(image2); addChild(image3); //fade out progress bar TweenMax.to(progressBar_mc, 0.5, autoAlpha:0, blurFilter:blurX:20, blurY:20); //fade in loaded images TweenMax.from(image1, 0.5, delay:0.5, alpha:0, blurFilter:blurX:20, blurY:20); TweenMax.from(image2, 0.5, delay:0.7, alpha:0, blurFilter:blurX:20, blurY:20); TweenMax.from(image3, 0.5, delay:0.9, alpha:0, blurFilter:blurX:20, blurY:20);   

Étape 5: Testez le film

Appuyez sur CTRL + ENTRÉE pour tester le film. Vous verrez que la barre de progression disparaît immédiatement et que les trois images s’affichent. C’est parce que les images sont des fichiers locaux, ce qui signifie qu’elles peuvent être chargées presque immédiatement. Pour simuler la vitesse de téléchargement en ligne, sélectionnez d’abord le bouton Affichage> Paramètres de téléchargement> DSL en tant que vitesse de téléchargement simulée, puis appuyez à nouveau sur CTRL + ENTRÉE sans fermer la fenêtre de test pour commencer à simuler le téléchargement en ligne. Cette fois, vous verrez les progrès s’élargir progressivement avant de s’effacer..

Ok, il est temps de charger les images avec le framework de commandes.


Commandes utilitaires

Avant de poursuivre, créons des commandes utilitaires qui seront utilisées plus tard dans l'exemple. Encore une fois, ces classes de commandes sont basées sur le framework de commandes présenté dans mon précédent tutoriel (Partie 1), et je vous recommande vivement de les parcourir avant de continuer. Si vous avez déjà lu le didacticiel, vous pouvez toujours revenir en arrière si vous avez besoin de rafraîchir votre mémoire..

Commandes Data Managers

Ici, nous allons créer deux commandes pour l’enregistrement et le désenregistrement de données pour la classe de gestionnaire de données. le RegisterData commande enregistre les données dans le gestionnaire, tandis que la Annuler l'enregistrement commande désenregistre des données.

 package commands.data import commands.Command; importer data.DataManager; // cette commande enregistre les données dans la classe publique du gestionnaire de données RegisterData extend Command public var key: String; données var publiques: *; fonction publique RegisterData (key: String, data: *) this.key = key; this.data = data;  écraser la fonction protégée execute (): void DataManager.registerData (clé, données); Achevée(); 
 package commands.data import commands.Command; importer data.DataManager; // cette commande annule l'enregistrement des données de la classe publique du gestionnaire de données UnregisterData extend Commande public var key: String; fonction publique UnregisterData (key: String) this.key = key;  écraser la fonction protégée execute (): void DataManager.unregisterData (key); Achevée(); 

La commande LoaderLoad

Cette commande encapsule un Chargeur les instances charge() méthode. Vous pouvez fournir un onProgress commande qui est exécutée à chaque événement de progression et un onComplete exécuté lorsque le chargement est terminé. Notez que le Achevée() La méthode est invoquée à la fin du chargement. Cette ligne de code est extrêmement cruciale. Si vous n'invoquez pas la méthode, la commande ne sera jamais considérée comme complète, ce qui bloquera toute votre application dans le pire des cas..

 package commands.loading import commands.Command; import flash.display.Loader; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; import flash.system.LoaderContext; Classe publique LoaderLoad extend Command public var loader: Loader; public var url: URLRequest; public var context: LoaderContext; public var onProgress: Command; public var onComplete: Command; fonction publique LoaderLoad (loader: Loader, url: URLRequest, contexte: LoaderContext = null, onProgress: Command = null, onComplete: Command = null) this.loader = loader; this.url = url; this.context = context; this.onProgress = onProgress; this.onComplete = onComplete;  écraser la fonction protégée execute (): void // ajouter des écouteurs loader.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, progressListener); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, completeListener); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, loadingComplete); // commence à charger loader.load (url, contexte);  fonction privée loadingComplete (e: Event): void // supprime les écouteurs loader.contentLoaderInfo.removeEventListener (ProgressEvent.PROGRESS, progressListener); loader.contentLoaderInfo.removeEventListener (Event.COMPLETE, completeListener); loader.contentLoaderInfo.removeEventListener (Event.COMPLETE, loadingComplete); Achevée();  fonction privée progressListener (e: ProgressEvent): void // exécute la commande onProgress if (onProgress) onProgress.start ();  fonction privée completeListener (e: Event): void // exécute la commande onComplete if (onComplete) onComplete.start (); 

La commande InvokeFunction

Cette commande encapsule l'appel d'une autre fonction. Il est conçu pour vous permettre de fournir un tableau de paramètres supplémentaire pour la fonction à appeler..

 package commands.utils import commands.Command; // cette commande appelle une fonction public class InvokeFunction () s'étend de la commande public var func: Function; public var args: Array; fonction publique InvokeFunction (func: Function, arguments: Array = null) this.func = func; this.args = args;  écrase la fonction protégée execute (): void func.apply (null, args); Achevée(); 

C'est tout. Temps pour l'exemple.


Étape 1: Copiez le fichier de document Flash

Copiez le fichier FLA de l'exemple précédent dans un nouveau dossier et copiez-y les fichiers image..


Étape 2: créer la classe de document

Créez un nouveau fichier AS pour la classe de document du fichier FLA copié, nommé "LoadingDataWithCommands". N'oubliez pas de changer le nom de la classe de document dans le fichier FLA en ce nouveau.

Le code de la classe de document est assez propre. Il définit simplement la scène actuelle à un ChargementScene avec un régisseur. Nous utilisons le cadre de scène présenté dans mon précédent tutoriel (Partie 2). Vous pouvez le vérifier si vous avez oublié comment l'utiliser..

 package import flash.display.MovieClip; importer des scènes.SceneManager; Classe publique LoadingDataWithCommands étend MovieClip fonction publique LoadingDataWithCommands () var sceneManager: SceneManager = new SceneManager (); sceneManager.setScene (nouveau LoadingScene (this)); 

Il y a deux scènes au total. le ChargementScene charge les images et met à jour la barre de progression. Une fois le chargement terminé, la scène passe par le MainScene, qui s'estompe dans les images chargées.


Étape 3: La scène de chargement

Étendre la Scène classe pour créer une nouvelle classe nommée ChargementScene. le récipient La propriété contient une référence au sprite principal. Cela nous permet d'accéder à la barre de progression ultérieurement.

 package import scenes.Scene; Classe publique LoadingScene Etend Scene conteneur privé var: LoadingDataWithCommands; fonction publique LoadingScene (conteneur: LoadingDataWithCommands) this.container = conteneur; 

Créez maintenant la commande d’introduction pour la scène de chargement. L'intro créera trois chargeurs et commencera le processus de chargement. Ceci est fait en remplaçant le createIntroCommand () méthode. Le code suivant va dans le corps de la classe, de la même manière que le constructeur.

 // la commande d'introduction commence le chargement des trois images qui annulent la fonction publique createIntroCommand (): Commande var loader1: Loader = new Loader (); var loader2: Loader = new Loader (); var loader3: Loader = new Loader (); var commande: Command = new ParallelCommand (0, // réduit la barre de progression à zéro. New SetProperties (container.progressBar_mc.innerBar_mc, scaleX: 0), // commandes liées au chargement exécutées en série par le nouveau SerialCommand (0, / / enregistre les trois chargeurs dans le gestionnaire de données new ParallelCommand (0, new RegisterData ("loader1", loader1), new RegisterData ("loader2", loader2), nouveau RegisterData ("loader3", loader3)), // début du chargement commandes en parallèle nouvelles ParallelCommand (0, nouvelle LoaderLoad (loader1, nouvelle URLRequest ("image1.jpg"), null, nouvelle InvokeFunction (onProgress) // commande onProgress), nouvelle LoaderLoad (loader2, nouvelle URLRequest ("image2.jpg") , null, nouvel InvokeFunction (onProgress) // commande onProgress), nouveau LoaderLoad (loader3, nouveau URLRequest ("image3.jpg"), null, nouveau InvokeFunction (onProgress) // commande onProgress)))); renvoyer la commande; 

Ensuite, remplacez le onSceneSet () méthode. Cette méthode est appelée lorsque la commande d'introduction est terminée, indiquant que le chargement est terminé. Dans cette méthode, nous disons au responsable de la scène de se rendre sur la scène principale. Avant la transition de la scène, la commande outro est exécutée en premier.

 redéfinit la fonction publique onSceneSet (): void sceneManager.setScene (new MainScene (conteneur)); 

Et puis écrasez le createOutroCommand. Cette commande doit effacer la barre de progression.

 // la commande outro disparaît progressivement de la barre de progression de la fonction publique createOutroCommand (): Command var commande: Command = new SerialCommand (0, // fade out progress barre de progression new TweenMaxTo (conteneur.progressBar_mc, 0.5, autoAlpha: 0, blurFilter : blurX: 20, blurY: 20), // supprime la barre de progression de la liste d'affichage new RemoveChild (conteneur, conteneur.progressBar_mc)); renvoyer la commande; 

Enfin, créez le onProgress méthode invoquée par le InvokeFunction commandes.

 fonction privée onProgress (): void // récupère les références du chargeur à partir du gestionnaire de données var loader1: Loader = DataManager.getData ("loader1") en tant que Loader; var loader2: Loader = DataManager.getData ("loader2") en tant que chargeur; var loader3: Loader = DataManager.getData ("loader3") en tant que chargeur; // calcule le nombre total de bits pour charger var bytesTotal: uint = 0; bytesTotal + = loader1.contentLoaderInfo.bytesTotal; bytesTotal + = loader2.contentLoaderInfo.bytesTotal; bytesTotal + = loader3.contentLoaderInfo.bytesTotal; // calcule le nombre total de bits chargés var bytesLoaded: uint = 0; bytesLoaded + = loader1.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader2.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader3.contentLoaderInfo.bytesLoaded; // met à jour la barre de progression scale conteneur.progressBar_mc.innerBar_mc.scaleX = bytesLoaded / bytesTotal; 

Étape 4: La scène principale

Maintenant, créez une nouvelle classe pour la scène principale, en prolongeant le Scène classe.

 package import scenes.Scene; Classe publique MainScene étend Scene conteneur var privé: LoadingDataWithCommands; fonction publique MainScene (conteneur: LoadingDataWithCommands) this.container = conteneur; 

Remplacer le createIntroCommand () méthode. Cette méthode ajoutera les chargeurs à la liste d’affichage et les affichera un par un. De plus, les chaînes de clé de données ne sont pas enregistrées du gestionnaire de données..

 redéfinit la fonction publique createIntroCommand (): Command // récupère les références du chargeur à partir du gestionnaire de données var loader1: Loader = DataManager.getData ("loader1") en tant que Loader; var loader2: Loader = DataManager.getData ("loader2") en tant que chargeur; var loader3: Loader = DataManager.getData ("loader3") en tant que chargeur; var command: Command = new ParallelCommand (0, // commandes de traitement d'images chargées new SerialCommand (0, // ajuste les positions d'image chargées new par ParallelCommand (0, new SetProperties (loader1, x: 30, y: 30), par exemple)), new SetProperties (loader2, x: 230, y: 30), new SetProperties (loader3, x: 430, y: 30)), // ajout des images chargées pour afficher la liste nouveau ParallelCommand (0, nouvel AddChild (conteneur , loader1), nouvel AddChild (conteneur, loader2), nouvel AddChild (conteneur, loader3)), // ouverture en fondu des images chargées nouveau ParallelCommand (0, nouveau TweenMaxFrom (loader1, 0.5, flouFilter: blurX: 20, flou: 20 ), nouveau TweenMaxTo (loader1, 0.5, autoAlpha: 1), nouveau TweenMaxFrom (loader2, 0.5, retard: 0.2, alpha: 0, flouFiltre: blurX: 20, flou: 20), nouveau TweenMaxTo (loader2, 0.5, delay: 0.2, autoAlpha: 1), nouveau TweenMaxFrom (loader3, 0.5, delay: 0.4, alpha: 0, flouFilter: blurX: 20, flou: 20), nouveau TweenMaxTo (loader3) , 0.5, delay: 0.4, autoAlpha: 1))), // données de suppression de l'enregistrement dans le gestionnaire de données new ParallelCommand (0, new UnregisterData ("loader1"), new Unregi sterData ("loader2"), nouveau UnregisterData ("loader3"))); renvoyer la commande; 

Étape 5: Testez le film

Bien. Avaient fini! Testez le film et simulez le téléchargement en ligne. Vous verrez exactement le même résultat que dans l'exemple précédent, mais cette fois, tout est fait avec le framework de commandes et le framework de scènes.


Résumé

Dans ce tutoriel, je vous ai montré comment charger des images externes avec le framework de commandes. le LoaderLoad Cette commande peut également être utilisée pour charger des fichiers SWF externes. De plus, vous pouvez créer vos propres commandes pour charger des données externes autres que des images et des fichiers SWF, en encapsulant les URLLoader classe dans tes commandes.

Nous avons écrit plus de code dans le deuxième exemple que dans le premier. N'oubliez pas que le cadre de commande et le cadre de scène ne servent pas à obtenir le même résultat avec moins de code, mais à gérer le code de manière systématique et modulaire, afin de vous simplifier la vie pour la maintenance et les modifications futures.

Le premier exemple regroupe tout le code dans une seule classe, ce qui rend difficile toute maintenance future si la quantité de code devait devenir extrêmement importante. Le second exemple, en revanche, sépare le code logiquement indépendant en différentes scènes, ce qui facilite les modifications futures. De plus, en intégrant le cadre de commande et le cadre de scène, nous avons laissé la place à de futures extensions, où nous pouvons ajouter plus de scènes et de commandes intro / outro sans perturber le code non pertinent..

!