Preload en pure AS3

Preload Ca fait un moment que je voulais faire ce billet. Comme je me remets à faire du Flash et que mon nouveau collègue me menace de retirer mon blog de sa liste de flux, je me décide enfin à écrire quelque chose.

Pour le projet neoplayer, je cherchais un moyen de faire un preload de l’application. Quand on utilise le Flash IDE, on fait simplement une frame avec le chargement et on met tout le reste en frame 2. Mais comment on fait uniquement en code, sans passer par l’éditeur ?

Reproduire les frames

Quand on compile du Flash juste avec un fichier as, on a une class qui représente le conteneur principal, par exemple :

package
{
   import flash.display.Sprite;

   [SWF(width="200", height="200", backgroundColor="#ffffff", frameRate="48")]
   public class Main extends Sprite
   {
      public function Main()
      {
      }
   }
}

Le problème, c’est qu’ici, on va commencer à instancier des objets, initialiser des choses etc. Ca prend de la place et ce sont des prérequis pour la classe.

Il existe cependant un metadata qui permet de rajouter une frame qui sera exécutée avant. Voilà ce que ça donne :

package
{
   import flash.display.Sprite;

   [SWF(width="200", height="200", backgroundColor="#ffffff", frameRate="48")]
   [Frame(factoryClass="com.neolao.preload.DefaultPreload")]
   public class Main extends Sprite
   {
      public function Main()
      {
      }
   }
}

Cette frame est représentée par une class com.neolao.preload.DefaultPreload :

package com.neolao.preload
{
   import flash.display.MovieClip;
   import flash.display.DisplayObject;
   import flash.events.Event;
   import flash.utils.*;
    
   public class DefaultPreload extends MovieClip
   {
       public function DefaultPreload()
       {
            this.stop();
            this.addEventListener(Event.ENTER_FRAME, this._onEnterFrame);
       }
       
       private function _onEnterFrame(event:Event):void
       {
           if (this.framesLoaded == this.totalFrames) {
               this.removeEventListener(Event.ENTER_FRAME, this._onEnterFrame);
               this.nextFrame();
               
               var mainClass:Class = getDefinitionByName("Main") as Class;
               var app:DisplayObject = new mainClass() as DisplayObject;
               this.addChild(app);
           }
       }
    
   }
}

Il faut que cette class étende MovieClip, ensuite on fait un stop(). C’est donc dans cette fameuse class qu’on va pouvoir faire un preload et instancier la class Main après un nextFrame().

Pour vérifier que tout est chargé, il y a les propriétés framesLoaded et totalFrames qu’on peut tester.

J’ai remarqué que si on ne fait pas le nextFrame(), ça ne marche pas. Il faut aussi instancier la class principale puis l’ajouter avec addChild, donc ce n’est pas vraiment une deuxième frame qu’on crée avec l’instance Main, mais plutôt une frame vide avec comme enfant, une instance de Main.

Conclusion

A l’époque, toutes mes recherches pointaient sur le même exemple, un blog anglais. Je me suis dit que ça serait intéressant d’expliquer un peu en français la technique.

L’inconvénient, c’est qu’il faut connaitre le nom de la class principale dans la class Preload. C’est embêtant si on veut rendre ça facilement interchangable.

Commentaires