Preload en pure AS3

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

1. Le samedi, avril 4 2009, 09:24 par ekameleon

Hello :)

Pour ma part je préfère créer un module SWF à part qui va charger le premier avec un Loader en ApplicationDomain.currentDomain :) Et comme cela mon SWF est très modulaire et peut être utiliser pour toutes mes applications.

EKA+ :)

3. Le lundi, avril 6 2009, 11:21 par kiroukou

Salut,

Moi je procède ainsi, sauf que la classe que j'utilise pour le preload de mon appli n'est pas ta DefaultPreload mais une classe spécifique au projet héritant de DefaultPreload et sur laquelle je surcharge la partie problématique selon le projet :
var mainClass:Class = getDefinitionByName("Main") as Class;


@Eka: en effet j'ai tendance à préférer cette approche aussi, seulement lorsque mon Loader utilise une classe en commun avec le reste de mon appli, ça devient un peu plus gênant d'avoir le currentDomain... (pour la maintenance entre autre).

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.