mercredi, janvier 28 2004

Optimisation des conditions booléennes avec opérateurs logiques

Pour ceux qui ne le savent pas encore, lorsque vous utiliser des opérateur booléens dans une condtion (&& ou ||), toutes les conditions ne sont pas forcément testées. En effet, une expression booléenne composée uniquement de && est forcément false si un seul de ses éléments est à false. L'évaluation de l'expression d'arrête donc dés qu'un élément false est trouvé. De la même manière, une expression composée de || est true si un seul de ses élements est à true ... :)

L'optimisation de conditions booléennes dans des instructions telles que if(...) ou while(...) passe donc par une estimation des probabilités de chaque expression booléenne unitaire d'être true ou false ... Ainsi, dans une expression &&, nous mettrons en premier les expressions qui ont le plus de chance d'être false, arrêtant ainsi l'évaluation des booléens suivants. 8)

// Retourne true
function getTrue() {
        trace("getTrue");
        return true;
}
// Retourne false
function getFalse() {
        trace("getFalse");
        return false;
}
/* Condition "et" non optimisée
   Les deux fonctions sont appelées */

if (getFalse() && getTrue()) {
        trace("OK");
}
// - Sortie -
// getTrue
// getFalse
/* Condition "et"
   La condition qui a le plus de chances de
   retourner false est mise en premier
   Ainsi, les condtions suivantes ont moins de
   chances d'être executées */

if (getFalse() && getTrue()) {
        trace("OK");
}
// - Sortie -
// getFalse
/* Condition "ou" non optimisée
   Les deux fonctions sont appelées */

if (getTrue() || getFalse()) {
        trace("OK");
}
// - Sortie -
// getFalse
// getTrue
// OK
/* Condition "ou"
   La condition qui a le plus de chances de
   retourner true est mise en premier
   Ainsi, les condtions suivantes ont moins de
   chances d'être executées */

if (getTrue() || getFalse()) {
        trace("OK");
}
// - Sortie -
// getTrue
// OK
Dans le cas donné ici, on sait exactement quel booléen va être retourné, mais de manière générale, il s'agit de faire preuve de bon sens. Il s'agit lors de la conception de ces conditions de faire la part entre la charge induite par l'évaluation d'une expression unitaire, et sa probabilité de mettre fin à l'évaluation de l'expression booléenne entière. Parfois, une condition a plus de chances de mettre fin à l'évaluation, mais provoque beaucoup de calculs, alors qu'une autre partie de l'expression est bien plus rapide à calculer, mais moins de chances d'arrêter l'évaluation. Il faut à ce moment la faire a part des choses entre probabilité et temps d'éxecution. 8| La négation "!" peut parfois servir à intervertir l'ordre de calcul, et ainsi inverser les probabilités. L'ordre sera à redéterminer en fonction de ca. :) if (getTrue() && getFalse()) {
        trace("OK");
}
// est équivalent à
if (!getTrue() || !getFalse()) {
        trace("OK");
}

Ce type d'optimisation est souvent négligé, alors que l'utilisation des conditions est trés fréquente en programmation ... Elle s'applique également à la plupart des langages, bien que certains commencent à évaluer les condtions par la fin ...^^

vendredi, janvier 23 2004

Saisie des commentaires en Flash

Comme suggéré dans le blog de Stéfane Funaro, créer un formulaire de saisie en Flash pour les commentaires d'un blog permet de se mettre à l'abris de manière quasi-complète des "blogspams" ... J'ai mis en place ici ce type d'outil. :) Pour ceux qui avaient choisis de garder un cookie du blog pour mémoriser leurs noms, email, et site web, vous pouvez l'effacer, étant donné que c'est un ShardeObject qui est maintenant utilisé ! 8)

En ce qui me concerne, ayant un blog "fait maison", je n'ai pas encore eu à faire face a des spammeurs, mais c'est surtout pour des raisons pratiques de formatage du texte par les BBCode que j'ai fait ce formulaire en Flash. Je n'ai pas pris la peine de faire un preload pour les 2,26Ko occupés par l'animation ... 8|

Le problème qui s'est posé à moi est que la classe Selection est assez capricieuse : en effet, elle ne permet de connaitre la zone sélectionnée que pour un élément ayant le focus. Or, lorsque l'on clique sur un bouton, ce bouton prend le focus, et on perd donc les informations concernant le texte qui est selectionné. J'ai donc créé une mini-classe qui permet de garder en permanence la sélection faite sur une zone de texte donnée, et de lui appliquyer des "tags" : dans le cas de ce blog, ces tags sont bien évidemment des BBCodes ... ;)

Je vous la livre telle quelle, vite faite et vite commentée ! :oops:/**
* TextFormater
* Premier brouillon, v0.0 alpha
*
* Surveille la sélection dans un champ texte
* et fournit les outils pour le formater
*/

class TextFormater {
        // TextField à formater
        private var _textfield:TextField;
        // Position de début et de fin de la sélection
        private var _begin:Number;
        private var _end:Number;
        // Constructeur
        // Prend en paramètre le champ texte à formater
        function TextFormater ($tf:TextField) {
                this._textfield = $tf;
                // On crée une propriété dans le TextField
                // qui pointe vers l'objet TextFormater
                this._textfield._formater = this;
                // Quand le champ texte prend le focus
                // on surveille la selection
                this._textfield.onSetFocus = function() {
                        this._formatInterval = setInterval(this._formater,"checkSelection",50);
                }
                // Quand le champ texte perd le focus
                // on arrête de le surveiller
                this._textfield.onKillFocus = function() {
                        clearInterval(this._formatInterval);
                }
        }
        // Surveille la sélection faite dans le champ texte
        function checkSelection() {
                // Si le champ texte a bien le focus
                if (eval(Selection.getFocus()) == this._textfield) {
                        // On renseigne le début et la fin de la selection
                        this._begin = Selection.getBeginIndex();
                        this._end = Selection.getEndIndex();
                }
        }
        // Ajoute un "tag" (BBCode ou autre) au début
        // et à la fin de la sélection
        function addTag($begin:String, $end:String) {
                var txt:String = this._textfield.text;
                // Encadre la sélection avec les tags
                this._textfield.text = txt.slice(0,this._begin) + $begin + txt.slice(this._begin,this._end) + $end + txt.slice(this._end);
                // Donne le focus au champ texte et sélectionne
                // le texte encadré par les tags
                Selection.setFocus(this._textfield);
                Selection.setSelection(this._begin,this._end + $begin.length + $end.length);
        }
}

J'espère que ce formulaire vous rendra la vie plus facile pour égayer vos commentaires, en attendant la version W3C du blog, et les versions Flash du blog et de mon site perso. ^^

vendredi, janvier 9 2004

Courbe de Bezier : petit effet

Actuellement, j'essaie de mettre en code toutes les petites idées qui me passent par la tête pour réaliser mon site perso. L'une d'elle est un effet elastique sur une courbe de Bezier, que j'ai réalisé vite fait histoire de voir ce que ca donne.





Du coup, je me suis replongé dans les mathématiques de ces courbes, notamment grâce à l'article de Timothée Groleau sur les courbes de Bezier dans Flash dont j'ai déjà parlé, et aussi grâce aux liens qu'il y donne. La difficulté réside dans le fait qu'il faut calculer les cooronnées du point de contrôle (ici juste _y) en fonction de l'endroit où l'on veut que la courbe passe ... rien de bien nouveau, et nombreux sont ceux qui on deja fait ce type d'utilisation des courbes dans Flash, mais voila ma petite contribution ! :)

J'en ai également profité pour me réconcilier un peu avec l'effet elastique des easing de Penner. En effet, bien que fan de ses interpolations, je trouvais l'effet elastique assez peu convaincant ... mais la il passe assez bien ! 8)

Le code en lui-même n'est pas ce qu'il y a de plus rigoureux et générique. En effet, j'ai par exemple profité du fait d'avoir un trait horizontal pour m'éviter un certain nombre de calculs ... :oops: De plus, quelque bugs subsistent encore, notamment lorsque l'on commence à "pousser" la courbe sans aller plus loin et que l'on revient la où on était, elle reste courbée ... ou alors au moment ou la souris rentre au dessus de l'animation. Mais comme je l'ai dit, ce n'est qu'un test assez vite fait ! ;)

::Télécharger xp_curve.zip::

mercredi, janvier 7 2004

Astuce sur la chaîne de portées et with

Je me suis aperçu d'une utilisation assez singulière de la chaine de portées avec l'instruction with, qui permet de limiter la répétition à outrance de l'endroit ou sont situées des propriétés ou méthodes.

var square = {x:10, y:10, w:100, h:100};<br />
with( square ) {<br />
 with( drawClip = this.createEmptyMovieClip("sq",10) ) {<br />
           _x = x;<br />
           _y = y;<br />
           lineStyle(0,0);<br />
           moveTo(0, 0);<br />
             lineTo(w, 0);<br />
             lineTo(w, h);<br />
             lineTo(0, h);<br />
             lineTo(0,0);<br />
      }<br />
}

Ces deux with imbriqués rajoutent à la chaîne de portées (dans l'ordre de recherche) : le clip crée (sq) et l'objet square. Donc, les instructions vont chercher d'abord dans le clip, et y trouver les méthodes et propriétés _x, _y, lineStyle, moveTo, etc... puis dans l'objet, pour y trouver les propriétés x, y, etc... Et voila, aucune portée n'est répétée à chaque ligne ! 8)

Par contre, cette imbrication est à utiliser avec précaution, étant donné que si le clip possède une propriété ayant le même nom qu'une propriété de l'objet square, c'est celle du clip qui sera utilisée en priorité ... 8|

jeudi, décembre 11 2003

Parseur ActionScript2 en PHP : premier essai

Pour continuer sur le projet d'un site communautaire autour de classes ActionScript 2, j'ai commencé à développer un parseur AS2 en PHP et ses fantastiques expressions régulières PERL, auxquelles j'ai eu du mal à me mettre, étant habitué aux expressions régulières POSIX. Depuis, les trouvant beaucoup plus puissante, je ne rate pas une occasion de les utiliser ! :D

En effet, lors de la publication de classes sur un site tel que celui que j'imagine, il faut pouvoir connaitre pour une classe la signature de son constructeur et de ses méthodes, afin de s'assurer que d'autres classes les utilisant ne vont pas être perturbées par une modification. Ca peut permettre aussi une génération automatique de commentaires ! 8)

Pour l'instant, il manque encore les import au niveau des dépendances, et la détection des getter/setter ... :°

Le problème est que étant donné que je code un peu toujours de la même manière en terme d'organisation du code, mes tests ne sont pas forcément des plus objectifs ! :=) Donc, si vous avez développé des classes AS2 et que vous voulez les tester dans ce prémice de parseur, ce serait super sympa de me signaler les quelques bugs qui peuvent apparaître sur vos propres classes. Je l'ai essayé sur les classes GPathfinder et GDispatcher de Grant Skinner, et il a l'air de fonctionner ...

Pour les inquiets, je ne sauvegarde absolument rien des codes qui peuvent être saisis dans ce parseur. ;)

lundi, décembre 1 2003

Tips : initialiser pluseurs propriétés en même temps

Du temps de mon premier pathfinder, j'avais crée une petit classe Point2, qui contenait des coordonnées. Je voulais également qu'elle soit dynamique, afin d'y mettre les propriétés que je voulait. Le problème était de taper 15 lignes de codes s'il y avait un nombre important de propriétés, et j'ai donc crée cette petite méthode setter pour me faciliter la vie.

dynamic class Dummy {
        function Dummy() {
                // ....
        }
        function set props(o:Object) {
                for (var curProp in o) {
                        this[curProp] = o[curProp];
                }
        }
        function get props():String {
                var prStr:String = "{ ";
                var writeComma:Boolean = false;
                for (var curProp in this) {
                        prStr += writeComma ? "," : "";
                        prStr += curProp+":"+this[curProp]+" ";
                        writeComma = true;
                }
                prStr += "}";
                return prStr;
        }
}
Rien de bien fantastique dans ces quelques lignes, mais c'est son utilisation qui est bien pratique :var myObj = new MyClass();
myObj.props = {name:"LAlex", x:10, y:20};
trace(myObj.name); // LAlex
trace(myObj.x); // 10
trace(myObj.props); // {y:20 ,x:10 ,name:LAlex }

Evidemment, ce n'est pas ce qu'il y a de plus "propre", mais ca peut aider a faire des raccourcis dans le code assez pratiques. :) Ca ne peut également pas être utilisé pour des initialisation multiples comme a=b=c. Pour pouvoir faire cela, il aurait fallu pouvoir retourner une valeur dans le setter, mais ce n'est pas possible comme je l'ai déjà dit dans ce blog ... :( Alors tant qu'à faire, autant que ca serve pour faire un affichage "pratique" ! 8)

mardi, novembre 25 2003

[PHP] Nouveau BBCode et protection des adresses e-mail

Aprés avoir reçu un bon paquet de mails "viagra-grospenis-sitedecul" à une adresse que je ne communique jamais, je me suis posé la question des adresses mails qui sont visibles sur certains sites, comme les blogs (y compris le mien) et les sites communautaires. :?

J'ai donc développé un petit script PHP qui va "encoder" les adresses e-mails, puis les envoyer a une fonction javascript qui va s'occuper de les décoder. Ainsi, l'adresse email n'apparaît jamais en clair dans le code source de la page, qui est utilisé par les "aspirateurs d'emails". 8|

L'avantage de ce script est que l'encodage est différent à chaque affichage de la page, ce qui fait qu'il est plus difficile de la récupérer en créant un fonction "en dur". Vous pouvez choisir vous même une liste de valeurs qui vont pouvoir remplacer le symbole '@', et une de ces valeurs sera prise au hasard pour chaque page. 8) En plus, le fait de les décoder pour les afficher avec javascript permet à l'internaute de ne pas être géné, puisqu'il voit exactement la même chose que d'habitude.

Cryptmail fonctionne sur Internet Explorer 6 et sur Firebird (donc sur Mozilla). N'ayant pas de Mac, je ne sais pas s'il fonctionne sur Safari ? 8O Etant du Javascript 1.2, je pense que ca devrait passer. Si certains visiteurs ont un navigateur "exotique" (moins fréquent on va dire :)) ce serait sympa de me dire si les adresses sont visibles correctement (le script tourne deja sur ce blog)! ;)

J'ai intégré ce script à mon parseur BBCode, et j'en ai profité ajouter des fonctionnalités comme la gestion des smileys intégrée au moteur, ce qui me permet également de ne pas afficher de smileys dans les tags de type "norender" (code et autres...). Et tant qu'à faire, j'ai supprimé quelques bugs (affichage des chaines "ressemblant" à une variable PHP comme $var, affichage des antislashs : \ , etc...) 8)

::Télécharger bbcode02.zip (avec cryptmail)::


::Télécharger cryptmail.zip seul::

lundi, novembre 24 2003

StringUtils 0.2 : plus optimisée !

J'ai mis en pratique les optimisations qui m'ont été suggérées par Timothee Groleau, et voici donc une version plus optimisée de la classe StringUtils. J'ai également mis en place mon autre implémentation de la méthode reverse, qui se révèle plus performante (MM a bien travaillé sur les tableaux apparemment 8)) ...

Je n'ai finalement pas intégré l'encodage MD5, pour une raison tout bête, qui est que c'est long ! :D En fait, c'est un surcroit de poids (quelques Ko), pour une utilisation moins fréquente que les fonctionnalités actuelles de la classe. Il me paraît mieux de faire une classe dédiée à l'encodage par exemple. Vous pourrez trouver son implémentation par neo-lao dans le commentaire de ce post.

En passant, neo-lao est un de mes partenaires de Flash Forum et il a ouvert un petit site de ressources, ou il mets à disposition ses réalisations Flash et autres : neo-lao ressources. :)

Code de la classe StringUtils/*************************
* StringUtils.as v0.2
* Fonction "utilitaires" de traitement
* des chaînes de caractères
*
*-------------------
* LAlex
* <a href="http://www.lalex.com/">http://www.lalex.com/</a>
*
* ------------------
* Aide à l'optimisation lTrim, rTrim et trim
* Thimothee Groleau
* <a href="http://www.timotheegroleau.com/">http://www.timotheegroleau.com/</a>
*
**************************/

class com.lalex.utils.StringUtils {
        // Caractères considérés comme caractères d'espacement
        private static var DEFAULT_SPACECHARS:String = "

\t"
;
        // StringUtils.replace
        // Cherche une suite de caractères dans une chaine
        // pour la remplacer par une autre
        // ----------
        // $str : Chaine de caractêres à traiter
        // $search : Chaine de caractère à chercher
        // $replace : Chaine de caractère de remplacement
        public static function replace($str:String, $search:String, $replace:String):String {
                return $str.split($search).join($replace);
        }
        private static function spaceStringToObject($space:Object):Object {
                var spObj:Object = new Object();
                // Si aucun caractères n'est spécifié, utilise
                // les caractères par défaut.
                if ($space == undefined) {
                        $space = DEFAULT_SPACECHARS;
                }
                if (typeof $space == "string") {
                        // Remplit l'objet
                        var spLen:Number = $space.length;
                        while(--spLen >= 0) {
                                spObj[$space.charAt(spLen)] = true;
                        }
                } else {
                        spObj = $space;
                }
                return spObj;
        }
        // >> private <<
        //
        // StringUtils._lTrim
        // On supprime tous les caractères d'espacement
        // au début de la chaine de caractères. Un objet
        // dont les propriétés sont les caractères d'espacement
        // lui est transmis.
        private static function _lTrim($str:String,$space:Object):String {
                // Longueur de la chaine restante
                var strLen:Number = $str.length;
                // Position actuelle
                var strPos:Number = 0;
                // Tant que la chaine n'est pas vide
                while (strLen > 0) {
                        // Si on ne trouve pas un espace, on arrete la boucle
                        if (!$space[$str.charAt(strPos)]) {
                                break;
                        }
                        // On avance d'une position
                        strPos++;
                        // On raccourcit "virtuellement" la chaine
                        strLen--;
                }
                // On retourne la chaine sans les caractères trouvés.
                return $str.slice(strPos);
        }
        // >> private <<
        //
        // StringUtils._rTrim
        // On supprime tous les caractères d'espacement
        // à la fin de la chaine de caractères. Un objet
        // dont les propriétés sont les caractères d'espacement
        // lui est transmis
        private static function _rTrim($str:String,$space:Object):String {
                // Longueur de la chaine restante
                var strLen:Number = $str.length;
                // Position actuelle
                var strPos:Number = strLen-1;
                // Tant que la chaine n'est pas vide
                while (strLen > 0) {
                        // Si on ne trouve pas un espace, on arrete la boucle
                        if (!$space[$str.charAt(strPos)]) {
                                break;
                        }
                        // On avance d'une position
                        strPos--;
                        // On raccourcit "virtuellement" la chaine
                        strLen--;
                }
                // On retourne la chaine sans les caractères trouvés.
                return $str.slice(0,strPos+1);
        }
        // StringUtils.lTrim
        // On supprime tous les caractères d'espacement
        // au début de la chaine de caractères. Une chaine
        // dont dont chaque caractère est un caractère d'espacement
        // lui est transmise.
        public static function lTrim($str:String,$space:String):String {
                return _lTrim($str, spaceStringToObject($space));
        }
        // StringUtils.rTrim
        // On supprime tous les caractères d'espacement
        // à la fin de la chaine de caractères. Une chaine
        // dont dont chaque caractère est un caractère d'espacement
        // lui est transmise.
        public static function rTrim($str:String,$space:String):String {
                return _rTrim($str, spaceStringToObject($space));
        }
        // StringUtils.trim
        // On supprime tous les caractères d'espacement
        // au début et à la fin de la chaine de caractères. Une chaine
        // dont dont chaque caractère est un caractère d'espacement
        // lui est transmise.
        public static function trim($str:String, $space:String):String {
                var sp:Object = spaceStringToObject($space);
                return _rTrim(_lTrim($str, sp), sp);
        }
        // StringUtils.stringToArray
        // Convertit une chaine de caractères en tableau
        // contenant un caractère par index.
        public static function stringToArray($str:String):Array {
                return $str.split("");
        }
        // StringUtils.arrayToString
        // Transforme un tableau en chaine de caractère
        // constituée de la concatenation de ses éléments.
        public static function arrayToString($ar:Array):String {
                return "" + $ar.join("");
        }
        // StringUtils.reverse
        // Inverse l'ordre des caractères d'une chaine
        public static function reverse($str:String):String {
                // Transforme la chaine en tableau.
                var ar:Array = $str.split("");
                // Inverse le tableau
                ar.reverse();
                // Transforme le tableau inversé en chaine.
                return ar.join("");
        }
}

::Télécharger StringUtils.zip::

mercredi, novembre 19 2003

Classe utilitaire pour le traitement des chaînes de caractères

Voici une petit classe que j'ai développé pour y regrouper mes traitements sur les chaînes de caractères. Vous y trouverez les méthodes statiques replace, lTrim, rTrim, trim, stringToArray, arrayToString et reverse ...

Si vous avez des idées de méthodes (ou même des implémentations) à me suggérer, je suis preneur !!! :D

/*************************
* StringUtils.as v0.1
* Fonction "utilitaires" de traitement
* des chaînes de caractères
*-------------------
* LAlex
* <a href="http://www.lalex.com/">http://www.lalex.com/</a>
**************************/

class com.lalex.utils.StringUtils {
        // Caractères considérés comme caractères d'espacement
        private static var SPACE_CHARS:Array = [" ","
"
,"
"
,"\t"];
        // StringUtils.replace
        // Cherche une suite de caractères dans une chaine
        // pour la remplacer par une autre
        // ----------
        // $str : Chaine de caractêres à traiter
        // $search : Chaine de caractère à chercher
        // $replace : Chaine de caractère de remplacement
        public static function replace($str:String, $search:String, $replace:String):String {
                // Debut de la recherche courante
                var stsearch:Number = 0;
                // Position trouvée
                var fnd:Number = -1;
                // Retour
                var ret:String = "";
                // Tant qu'on trouve la chaine recherchée
                while ((fnd = $str.indexOf($search,stsearch)) != -1) {
                        // On rajoute du début de la recherche à la position
                        // trouvée, puis on rajoute la chaine de remplacement
                        ret += $str.slice(stsearch,fnd) + $replace;
                        // On déplace le début de la recherche suivante
                        stsearch = fnd+$search.length;
                }
                // On rajoute la fin de la chaine
                ret += $str.slice(stsearch,$str.length);
                // On retourne le résultat
                return ret;
        }
        // StringUtils.lTrim
        // On supprime tous les caractères d'espacement
        // au début de la chaine de caractères.
        public static function lTrim($str:String):String {
                // Boucle infinie (arretée par les return)
                while (true) {
                        // Si la chaine est vide, on la retourne
                        if ($str == "") {
                                return $str;
                        }
                        // On boucle sur les espaces
                        var numSpace:Number = SPACE_CHARS.length;
                        while (--numSpace >= 0) {
                                // Si un espace est trouvé, on l'enlève de la chaîne
                                // et on arrête la boucle.
                                if ($str.charAt(0) == SPACE_CHARS[numSpace]) {
                                        $str = $str.slice(1);
                                        break;
                                }
                        }
                        // Si numSpace est négatif, la boucle entière a étée
                        // faite, donc aucun espace n'est trouvé.
                        // On retourne donc la chaine.
                        if (numSpace < 0) {
                                return $str;
                        }
                }
        }
        // StringUtils.rTrim
        // On supprime tous les caractères d'espacement
        // à la fin de la chaine de caractères.
        public static function rTrim($str:String):String {
                // On stocke la longueur de la chaine
                // pour éviter d'y accéder plusieurs fois
                var len:Number = $str.length-1;
                // Boucle infinie (arretée par les return)
                while(true) {
                        if ($str == "") {
                                return $str;
                        }
                        // Si la chaine est vide, on la retourne
                        var numSpace:Number = SPACE_CHARS.length;
                        while (--numSpace >= 0) {
                                // Si un espace est trouvé, on l'enlève de la chaîne
                                // et on arrête la boucle. On retire 1 à la longueur
                                // de la chaîne.
                                if ($str.charAt(len) == SPACE_CHARS[numSpace]) {
                                        $str = $str.slice(0,-1);
                                        len--;
                                        break;
                                }
                        }
                        // Si numSpace est négatif, la boucle entière a étée
                        // faite, donc aucun espace n'est trouvé.
                        // On retourne donc la chaine.
                        if (numSpace < 0) {
                                return $str;
                        }
                }
        }
        // StringUtils.trim
        // On supprime tous les caractères d'espacement
        // au début et à la fin de la chaine de caractères.
        public static function trim($str:String):String {
                return rTrim(lTrim($str));
        }
        // StringUtils.stringToArray
        // Convertit une chaine de caractères en tableau
        // contenant un caractère par index.
        public static function stringToArray($str:String):Array {
                return $str.split("");
        }
        // StringUtils.arrayToString
        // Transforme un tableau en chaine de caractère
        // constituée de la concatenation de ses éléments.
        public static function arrayToString($ar:Array):String {
                return "" + $ar.join("");
        }
        // StringUtils.reverse
        // Inverse l'ordre des caractères d'une chaine
        public static function reverse($str:String):String {
                var rev:String = "";
                var i:Number = $str.length;
                while (--i >= 0) {
                        rev += $str.charAt(i);
                }
                return rev;
                /*
                --- Autre implémentation
                --- sans doute moins rapide
                var ar:Array = $str.split("");
                ar.reverse();
                return ar.join(""); */

        }
}

::Télécharger StringUtils.zip::

mardi, novembre 18 2003

Hériter de BroadcasterMX : il manque pas quelque chose ?

Toujours sur mon moteur de tilegame en MVC (d'abord en 2D, puis en 3D iso), j'utilise pour la diffusion de mes évenements la classe BroadcasterMX au moyen de l'héritage. Ca permet de ne pas passer par la méthode initialize(), et également d'initialiser le prototype au lieu de l'instance. :)

Or, il se trouve que cette classe ne possede pas de constructeur !!! 8O Ce qui oblige a initialiser le tableau _listeners dans le constructeur de la classe fille. Une petite modification simple consiste donc à rajouter trois ligne dans le code de la classe :function BroadcasterMX() {
   this._listeners = new Array();
}
Il suffit ensuite de faire un simple super() dans la classe fille ...

Oulala, et l'EULA ? Je vais me faire taper sur les doigts moi !!! :D 8)

lundi, novembre 17 2003

La classe XML manque de dynamisme

Il semble que la classe XML de Flash ne soit pas déclarée comme étant dynamic. Voila qui pose pas mal de problème pour tout ce qui est callback, souvent utilisé dans l'évenement onLoad ... :? Si on veut accéder à un objet via une propriété de l'objet XML, on se voit obligé de ne pas effectuer de typage strict ... 8|

class Dummy {
        var node:String;
        function Dummy() {
                // ...
        }
        function loadFromXml($file:String) {
                var ldXml:XML = new XML();
                ldXml.callback = this;
                ldXml.load($file);
                ldXml.onLoad = function(suc) {
                        if (suc) {
                                this.callback.node = this.firstChild.nodeName;
                        } else {
                                trace("XML File error");
                        }
                }
        }
}
Il n'existe aucune propriété nommée 'callback'. ldXml.callback = this; Si on enlève le typage fort à la déclaration, ca fonctionne trés bien 8| var ldXml = new XML();

vendredi, novembre 14 2003

Typage fort et downcast : j'enrage !!!

Je n'arrive pas à trouver un moyen de faire du cast, tout en continuant à utiliser le typage fort de MX 2004 ... :? En fait, une simple utilisation du constructeur permet de ne pas provoquer d'erreur de compilation, mais au lieu de faire un downcast, cela me renvoie null ... :(

Pour ceux qui ne connaissent pas le terme "downcast", ca correspond à changer le type d'un instance vers une classe qui hérite de sa classe actuelle. Cette classe est en fait située "plus bas" dans la chaîne d'héritage, et le cast est la conversion d'un type à un autre, d'où le terme de downcast ... :) Par exemple, une voiture est un véhicule, mais un véhicule n'est pas forcément une voiture. Si on a une instance d'un véhicule et qu'on la caste vers la classe voiture, on va downcaster cette instance ... Un cast dans l'autre sens (de voiture vers véhicule) est un upcast, et il est le plus souvent effectué de manière implicite ...

Revenons à ce que je disais :// classe Parent
class Parent {
        function Parent() {
        }
        function doIt() {
                trace("doIt");
        }
        function toString():String {
                return "Parent instance";
        }
}
// classe Child
class Child extends Parent {
        function Child() {
                super();
        }
        function doItChild(test:Child) {
                trace(">> doItChild");
                trace(test);
        }
        function toString():String {
                return "Child instance";
        }
}
/********** Utilisation **********/
var par : Parent = new Parent();
trace(par); // Parent instance
var chi : Child = new Child();
chi.doItChild(Child(par));
// >> doItChild
// null

Je ne vois pas dans ce cas la ce qui pourrait empêcher le downcast, mais apparemment ca lui pose un problème ... 8| Décidemment, ce typage fort pose plus de problèmes qu'il n'en résout ... :? D'ailleurs, vous devez commencer à me trouver lourd avec ca car je n'ose pas compter combien de posts j'ai fait sur ce sujet !!! :D Mais la je me retrouve encore une fois à buter la dessus, et ca me fais enrager une fois de plus !!! :?

mardi, novembre 4 2003

Gestion des Movieclips par Flash

Ted Patrick vient de donner sur la liste Flashcoders une explication de la manière dont flash gère ses données, et plus particulièrement les movieclips sur ce thread. En effet, les quatre types de données gérées par le Flash Player sont

  • Les types simples (nombre, chaines, booléens), accédés par valeur
  • Les objets, accédés par référence
  • Les fonctions, accédées par référence
  • les movieclips, accédés par profondeur.
En fait, c'est la dernière catégorie que je trouve trés interessante. En fait, on peut avoir plusieurs clips qui ont le même nom d'instance, c'est celui qui a la plus petite profondeur qui va avoir la priorité ://add 2 movieclips of the same name
a = _level0.createEmptyMovieClip("ted",1);
b = _level0.createEmptyMovieClip("ted",2);
//which one is named ted? >> Lowest Depth Wins!
trace(_level0.ted.getDepth()) // 1
//trace the references a & b
trace(a.getDepth()) // 1
trace(b.getDepth()) // 2
//add some data
_level0.ted =23
//Data, Objects,Functions, Primitves can overshadow, movieclip path
trace(_level0.ted) // 23

Sur ce, il conseille de travailler les movieclips toujours par référence (valeurs de retour de createEmptyMovieClip par exemple), pour éviter ce type de problèmes.

Voila pourquoi dans Flash MX 2004 il a du être plutôt facile d'implémenter la méthode MovieClip.getInstanceAtDepth .... ;)

mardi, octobre 28 2003

Interaction Flash-Javascript avec fscommand et les Flash Methods

J'ai voulu essayer les interactions possibles entre Flash et javascript, que ce soit dans une sens (appel d'une fonction javascript avec Flash), ou dans l'autre (interaction sur l'animation Flash avec Javascript) ... Eh bien je suis assez déçu des performances ... :( Je pense que ce sont les performances du javascript qui sont un peu légères ... 8|

Ce test consiste en fait à regarder en permanence la position d'une popup, et de déplacer un movieclip dans l'animation Flash pour donner l'impression que la popup est un masque que l'on peut déplacer par drag&drop .... Vous pouvez aussi télécharger l'archive qui en contient le code ... Voir le test (testé sur IE, je ne sais pas si ca marche sur les navigateurs de type mozilla ou opera)

::Télécharger js-flash.zip::

lundi, octobre 20 2003

Comportement de instanceof avec les types simples

Timothée Groleau propose dans ce post une implémentation en ActionScript de l'instruction native instanceof. Il se trouve que cette implémentation a un comportement que je qualifierai de logique, mais qui n'est pas exactement le même que celui de l'instruction n