Ces trois tutoriels font suite à un séminaire donné chez Adobe France le 23 novembre 2009, par Nicolas Gans, responsable pédagogique plate-forme Flash au centre de formation Regart.net.
Ils reprennent les slides et les exemples montrés lors de cette journée.
Le séminaire est divisé en trois parties :
- Séparation du design et du code dans Flash – part 1 : séparation .fla et .as
- Séparation du design et du code dans Flash – part 2 : compiler des .fla différents
- Séparation du design et du code dans Flash – part 3 : coder et compiler avec Flex Builder
Problématiques abordées :
Comment développer un projet en Flash et fluidifier les échanges au sein d’une équipe composée de designer Flash et de développeurs AS3 .
Quelles sont les bonnes pratiques (séparation et communication entre éléments du design et code), les techniques (librairies partagées, SWC), outils (FlashDevelop, Flex Builder) ?
Première partie : séparation .fla et .as
Permettre à chacun de travailler avec ses propres outils.
Historique
ActionScript 1
- Code sur la timeline ou sur les objets (MC et BTN)
- Code disséminé un peu partout dans l’appli : difficile à maintenir et à comprendre.
- Le codeur et le designer étaient souvent une seule et même personne.
- Avec le temps : spécialisation des tâches, codeur et designer sont devenues deux personnes différentes.
- Mise au point de bonnes pratiques : centralisation du code sur le scénario principal, utilisation de la directive #include pour placer le code dans des fichiers .as externes.
ActionScript 2
- Apparition de la POO : une meilleure structuration du code en classes est alors permise
- L’éditeur de code de Flash montre ses limites pour les codeurs
- Utilisation de SEPY, Flashdevelop par les codeurs
ActionScript 3
- Langage clairement POO
- Prérequis en programmation sont importants
- Outils des codeurs : Flashdevelop, Flex Builder, FDT (plugin Eclipse)
Classe du document
- Représente le root (la scène principale) de l’application.
- Point d’entrée de l’application, permet d’externaliser tout le code.
- Hérite d’un displayObjectContainer (MovieClip, Sprite)
Associer un symbole et une classe
- Bonne séparation logique et vue.
- Transparent pour le designer qui peut créer des occurrences sur la scène avec une logique implémentée.
- Instanciation se fait par new MaClasse()
- Liaison avec Clip, Boutons, Bitmap, Police, Sons
Communication TimeLine <> fichier .as
- Occurrences posées sur la scène deviennent des propriétés publiques de la classe.
- Paramètres AS3 : « déclarer automatiquement les occurrences de la scène »
- Appel de méthodes de la classe depuis le scénario.
- Ciblage d’occurrences depuis la classe.
Déclencher des instructions en fonction de la position de la tête de lecture
3 méthodes :
- Appel de méthodes de la classe depuis le scénario
- Diffusion d’événement depuis le scénario
- Utilisation d’addFrameScript (combinée avec étiquettes via la propriété currentLabels)
Exemple : 01_balle_rebond [Télécharger l'exemple]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | package { import flash.display.FrameLabel; import flash.display.MovieClip; import flash.events.Event; /** * ... * @author Nicolas Gans */ public class Animation extends MovieClip { public function Animation():void { trace("Animation instanciée"); // méthode 2 addEventListener(Event.COMPLETE, ecouteurAnimationTerminee); // méthode 3 // utilisation de la fonction non-documentée addFrameScript // ATTENTION : les numéros d'image commencent à 0 // donc 89 = 90ème image // ATTENTION 2 : tout le code présent sur la frame est écrasé ! addFrameScript(89, frameAnimationTerminee); // méthode 3bis // on peut combiner tout cela avec des étiquettes // currentLabels renvoie un tableau d'objets FrameLabel var etiquettes:Array = currentLabels; for each (var label:FrameLabel in etiquettes) { trace(label.frame, " : ", label.name); } // ATTENTION : le numéro de frame d'un FrameLabel commence à 1 et non à 0 !! addFrameScript(etiquettes[0].frame - 1, frameAnimationMilieu); } // METHODE 1 // méthode appellée depuis le scénario de l'animation // plus performant et moins gourmand en mémoire private function animationTerminee():void { trace("Animation terminée"); } // METHODE 2 // diffusion d'un événement depuis le scénario private function ecouteurAnimationTerminee(e:Event):void { trace("Evénement COMPLETE diffusé depuis le scénario"); } // METHODE 3 // addFrameScript : une fonction se déclenche automatiquement quand la tête de lecture // parvient à telle image private function frameAnimationTerminee():void { trace("Animation terminéee avec addFrameScript"); stop(); } // METHODE 3bis // addFrameScript avec étiquette private function frameAnimationMilieu():void { trace("Animation milieu"); } } } |
Piloter la timeLine depuis la classe
Il est courant d’utiliser le scénario pour créer des écrans ou des états d’un clip et de déplacer la tête de lecture en fonction des actions de l’utilisateur pour afficher tel ou tel écran/état.
Problème de l’asynchronie code/tête de lecture
Player 9 : gros soucis de synchronisation code/tête de lecture. Le code s’exécute avant le déplacement effectif de la tête de lecture, d’où impossibilité de cibler des occurrences placées sur la scène :
1 2 3 4 | gotoAndStop(10); // occurrence placée à l’image 10 monClip.play(); Error #1009: Il est impossible d'accéder à la propriété ou à la méthode d'une référence d'objet nul. |
Exemple : 02_piloter_timeLine_depuis_classe [Télécharger l'exemple]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package { import flash.display.MovieClip; import flash.events.MouseEvent; import flash.system.*; /** * ... * @author Nicolas Gans */ public class Main extends MovieClip { public function Main():void { stop(); etape1_btn.addEventListener(MouseEvent.CLICK, etape1); etape2_btn.addEventListener(MouseEvent.CLICK, etape2); etape3_btn.addEventListener(MouseEvent.CLICK, etape3); } private function etape1(e:MouseEvent):void { // Fonctionne avec le Flash Player 10 // mais pas avec le Flash Player 9 gotoAndStop("etape1"); etape_txt.text = "Etape 1"; perso_mc.alpha = Math.random(); } private function etape2(e:MouseEvent):void { gotoAndStop("etape2"); etape_txt.text = "Etape 2"; tete_mc.alpha = Math.random(); } private function etape3(e:MouseEvent):void { gotoAndStop("etape3"); etape_txt.text = "Etape 3"; couronne_mc.alpha = Math.random(); } } } |
Solution 1 :
1 2 3 4 5 6 7 8 9 10 11 12 | // écouter l’événement RENDER addEventListener(Event.RENDER, onRender); // déplacer la tête de lecture gotoAndStop(10); // invalidation du Stage stage.invalidate(); // ciblage du clip dans l’écouteur private function onRender(e:Event):void { monClip.play(); } |
Rend très complexes les allers-retours sur la timeline.
Solution 2 :
Utiliser un addFrameScript.
1 2 3 4 5 6 7 | addFrameScript(9, imageDix); gotoAndStop(10); private function imageDix() :void { monClip.play(); } |
Beaucoup plus souple, surtout si on a plein d’étapes avec beaucoup d’allers-retours.
ATTENTION : pas nécessaire avec le player 10 lorsqu’on travaille dans une Classe, mais le problème persiste si on code sur la TimeLine.
Player 10 : si on code sur la TimeLine, il faut appeler la méthode de déplacement de tête de lecture sur un enfant du scénario dans lequel on code pour que ça fonctionne.
1 2 3 4 5 6 7 | // ne fonctionne pas gotoAndStop(10); monClip.alpha = Math.random(); // fonctionne monConteneur.gotoAndStop(10); monConteneur.monClip.alpha = Math.random(); |
Gestion des états d’un MovieClip : horizontalité vs verticalité
- Une alternative au travail avec la timeline (horizontalité) est de travailler avec la displayList (verticalité).
- Chaque état est un DisplayObject, on gère alors les changements d’état en les ajoutant/retirant de la liste d’affichage.
- Intérêt : on peut se passer du gotoAndStop() asynchrone et eviter les bugs liés au player en mode horizontal. On travaille de manière plus « naturelle » pour le player.
Exemple : 03_gestion_etats_MC_avec_displayList_Mario [Télécharger l'exemple]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | package { import flash.display.DisplayObject; import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.ui.Keyboard; /** * ... * @author Nicolas Gans */ public class Mario extends Sprite { private var touches:Object = new Object(); private var sens:Number; private var vitesse:Number = 8; public var isJumping:Boolean; private var _displayed:DisplayObject; public static const JUMP_FINISHED:String = "jumpFinished"; public function Mario():void { sens = scaleX; // on nettoie la displayList while (numChildren > 0) removeChildAt(0); // clip affiché par défaut displayed = repos_mc; addEventListener(Event.ADDED_TO_STAGE, activation); } private function activation(e:Event):void { stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown); stage.addEventListener(KeyboardEvent.KEY_UP, keyUp); addEventListener(Event.ENTER_FRAME, loop); // événement diffusé sur la dernière frame du clip saute_mc saute_mc.addEventListener(JUMP_FINISHED, onJumpFinished); } // gestion affichage / retrait des états private function set displayed(value:DisplayObject):void { // on supprime l'état en cours if (_displayed != null && contains(_displayed)) removeChild(_displayed); // on le remplace par le nouvel état _displayed = addChild(value); } // gestion des actions en fonction des touches enfoncées private function loop(e:Event):void { if (touches[Keyboard.SPACE] && !isJumping) { saute(); } if (touches[Keyboard.LEFT]) { deplace(Keyboard.LEFT); } else if (touches[Keyboard.RIGHT]) { deplace(Keyboard.RIGHT); } if (touches[Keyboard.DOWN] && !isJumping) { displayed = assis_mc; } } private function keyDown(e:KeyboardEvent):void { touches[e.keyCode] = true; } private function keyUp(e:KeyboardEvent):void { touches[e.keyCode] = false; if (!isJumping) displayed = repos_mc; } private function saute():void { isJumping = true; saute_mc.gotoAndPlay(2); displayed = saute_mc; } private function onJumpFinished(e:Event):void { isJumping = false; displayed = repos_mc; } private function deplace(pSens:int):void { if (_displayed == assis_mc) return; if (!isJumping) displayed = marche_mc; if (pSens == Keyboard.LEFT) { scaleX = -sens; x -= vitesse; } else { scaleX = sens; x += vitesse; } } } } } |



Bravo et merci pour le tuto
27 nov 2009 @ 17:17
Merci*1000 !!
02 juin 2010 @ 11:45