SuperColor : Gestion des effets de couleur en AS2
Par -Alexandre LEGOUT aka LAlex- le jeudi, juin 24 2004, 11:08 - AS2 - Lien permanent
Pour les besoins d'un développement, j'ai eu besoin de faire une transition de type "fondu vers le blanc", qui donne un effet des plus esthétiques. Je me suis servi pour cela d'une classe qui hérite de color, et implémente des méthodes permettant de manipuler la luminosité, et d'autres paramètres liés à la couleur d'un clip. J'ai utilisé pour cela l'ensemble de fonctions développées par Robert PENNER, qu'il expose dans son livre, mais en AS1.
J'ai donc repris ses fonctions pour les intégrer dans une classe AS2, qui contient également des propriétés "virtuelles" créées avec des getter/setter. Cela permet d'utiliser facilement les Tween dessus, et donc de créer des interpolations de luminosité trés facilement. Cliquez sur l'image pour voir un petit exemple. ![]()
Le code de l'animation que vous voyez est on ne peux plus simple :// Importation des classes
import com.lalex.movieclip.SuperColor;
import mx.transitions.Tween;
import mx.transitions.easing.Regular;
// Objet SuperColor
var myCol:SuperColor = new SuperColor(image);
// Objet Tween
var myTw:Tween = new Tween(myCol, "_brightOffset", Regular.easeInOut, 0, 255, 2, true);
myTw.stop();
// Evenements du Tween
var twEvent:Object = new Object();
myTw.addListener(twEvent);
var onMF = function(tw:Tween) {
tw.yoyo();
this.onMotionFinished = function(tw:Tween) {
tw.yoyo();
tw.stop();
this.onMotionFinished = onMF;
}
}
twEvent.onMotionFinished = onMF;
// Evenements sur l'image
image.onRelease = function() {
myTw.start();
}
image.onRollOver = function() {
click._visible = false;
}
Commentaires
tiens cela me dit quelquechose
eka > Ah bon ?
Pour ma part (sur la mienne) j'ai ajouté 2 méthodes tweenProperty et tweenRGB qui me servent bien à l'usage :
/* -------------
Exemple d'utilisation :ColorTool v1.0 AS2
Juin 18, 2004
Auteur : ekameleon
(c) 2003 Robert Penner - Use freely, giving credit where possible.
Color methods :
reset()
invert()
setRGB2()
getRGB2()
setTint()
getTint()
setTint2()
getTint2()
setTintOffset()
getTintOffset()
setRedOffset()
getRedOffset()
setGreenOffset()
getGreenOffset()
setBlueOffset()
getBlueOffset()
tweenProperty (prop, begin, end, duree, equation)
tweenRGB ( __r, __g, __b, duree, equation)
Color Event
onMotionChanged
invoqué pendant un changement de couleur avec les méthodes tweenProperty et tweenRGB
onMotionFinished
invoqué à la fin d'un changement de couleur avec les méthodes tweenProperty et tweenRGB
Color Getter/Setter Properties :
_RGBStr
red
green
bue
brightness
brightOffset
contrast
negative
redPercent
greenPercent
bluePercent
Classe basée sur le livre : Robert Penner's Programming Macromedia Flash MX
<a href="http://www.robertpenner.com/profmx" rel="nofollow">http://www.robertpenner.com/profmx</a>
<a href="http://www.amazon.com/exec/obidos/ASIN/0072223561/robertpennerc-20" rel="nofollow">http://www.amazon.com/exec/obidos/ASIN/0072223561/robertpennerc-20</a>
------------- */
import mx.transitions.BroadcasterMX ;
import mx.transitions.Tween ;
import mx.transitions.easing.* ;
class com.eka.color.ColorTool extends Color {
static private var __initBroadcaster = BroadcasterMX.initialize (Color.prototype);
// -----o Public Properties
public var addListener:Function ;
public var removeListener:Function ;
public var broadcastMessage:Function ;
public var onColorChanged:Function ;
public var onColorTweened:Function ;
public var onMotionChanged:Function ;
public var onMotionFinished:Function ;
// -----o Private Properties
private var _listeners:Array;
// -----o Constructor
public function ColorTool (mc:MovieClip) {
super (mc) ;
this._listeners = [];
this.addListener (this);
}
// -----o Private Methods
private function limit (value:Number, min, max) : Number {
if (value>max) return max ;
if (value<-100) return min ;
return value ;
}
// ----- solid color - Color methods
public function set _RGBStr (hexStr:String) : Void {
// prend en compte les 6 derniers caractères de la chaine
hexStr = hexStr.substr (-6, 6);
this.setRGB (parseInt (hexStr, 16));
}
public function get _RGBStr () : String {
var hexStr = this.getRGB().toString(16);
// fill in zeroes as needed
var toFill = 6 - hexStr.length;
while (toFill--) hexStr = "0" + hexStr;
return hexStr.toUpperCase();
}
// ----- set red, green, and blue with normal numbers - r, g, b between 0 and 255
public function setRGB2 (r, g, b) : Void {
this.setRGB (r << 16 | g << 8 | b);
} // Branden Hall - <a href="http://www.figleaf.com" rel="nofollow">www.figleaf.com</a>
// ----- returns an object with r, g, and b properties
public function getRGB2 () : Object {
var t = this.getTransform();
return {r:t.rb, g:t.gb, b:t.bb} ;
}
// ----- reset the color object to normal
public function reset () : Void {
this.setTransform ({ra:100, ga:100, ba:100, rb:0, gb:0, bb:0}) ;
}
// ----- tint - Color methods
// tint with a color just like Property Inspector
// r, g, b between 0 and 255; percent between 0 and 100
public function setTint (r, g, b, percent) : Void {
var ratio = percent / 100;
var trans = {rb:r*ratio, gb:g*ratio, bb:b*ratio};
trans.ra = trans.ga = trans.ba = 100 - percent;
this.setTransform (trans);
}
// returns a tint object containing r, g, b, and percent properties
public function getTint () : Object {
var trans = this.getTransform();
var tint = {percent: 100 - trans.ra};
var ratio = 100 / tint.percent;
tint.r = trans.rb * ratio;
tint.g = trans.gb * ratio;
tint.b = trans.bb * ratio;
return tint;
}
// tint with a color - alternate approach
// rgb a color number between 0 and 0xFFFFFF; percent between 0 and 100
public function setTint2 (rgb, percent) : Void {
var r = (rgb >> 16) ;
var g = (rgb >> <img src="http://common.lalex.com/themes/devblog/smilies/icon_cool.gif" alt="8)" class="smiley" /> & 0xFF;
var b = rgb & 0xFF;
var ratio = percent / 100;
var trans = {rb:r*ratio, gb:g*ratio, bb:b*ratio};
trans.ra = trans.ga = trans.ba = 100 - percent;
this.setTransform (trans);
}
// returns a tint object containing rgb (a 0xFFFFFF number) and percent properties
public function getTint2 () : Object {
var trans = this.getTransform();
var tint = {percent: 100 - trans.ra};
var ratio = 100 / tint.percent;
tint.rgb = (trans.rb*ratio)<<16 | (trans.gb*ratio)<<8 | trans.bb*ratio;
return tint;
}
// ----- tint offset - Color methods
// r, g, b between -255 and 255
public function setTintOffset (r, g, b) : Void {
var trans = this.getTransform();
with (trans) { rb = r; gb = g; bb = b; }
this.setTransform (trans);
}
public function getTintOffset () : Object {
var t = this.getTransform();
return {r:t.rb, g:t.gb, b:t.bb};
}
// ----- color inversion - Color methods
// inverse les couleurs
public function invert () : Void {
var trans = this.getTransform();
with (trans) {
ra = -ra;
ga = -ga;
ba = -ba;
rb = 255 - rb;
gb = 255 - gb;
bb = 255 - bb;
}
this.setTransform (trans);
}
// ----o Getter/Setter Properties
// ----- brightness
// luminosité, même effet que l'inspecteur de propriété
// pourcentage entre -100 and 100
public function set brightness (bright:Number) {
bright = limit (bright, -100, 100) ;
var trans = this.getTransform();
with (trans) {
ra = ga = ba = 100 - Math.abs (bright); // color percent
rb = gb = bb = (bright > 0) ? bright * (256/100) : 0; // color offset
}
this.setTransform (trans);
}
public function get brightness () {
var trans = this.getTransform();
with (trans) return rb ? 100 - ra : ra - 100;
}
// ----- contrast
// ajuste le contraste
// pourcentage entre -100 and 100
public function set contrast (percent) {
percent = limit (percent, -100, 100) ;
var t = {};
t.ra = t.ga = t.ba = percent;
t.rb = t.gb = t.bb = 128 - (128/100 * percent);
this.setTransform(t);
}
public function get contrast () { return this.getTransform().ra }
// ----- brightOffset - Color methods
// offset between -255 and 255
public function set brightOffset (offset) {
offset = limit (offset, -255, 255) ;
var trans = this.getTransform()
with (trans) rb = gb = bb = offset;
this.setTransform (trans);
}
public function get brightOffset () { return this.getTransform().rb }
// produit une image négative.
public function set negative (percent:Number) : Void{
percent = limit (percent, -100, 100) ;
var t = {};
t.ra = t.ga = t.ba = 100 - 2 * percent;
t.rb = t.gb = t.bb = percent * (255/100);
this.setTransform (t);
}
public function get negative () {
return this.getTransform().rb * (100 / 255);
}
// ----- solid color - Color methods
public function set red (amount) {
var t = this.getTransform();
this.setRGB (amount << 16 | t.gb << 8 | t.bb);
}
public function get red () {
return this.getTransform().rb;
}
public function set green (amount) {
var t = this.getTransform();
this.setRGB (t.rb << 16 | amount << 8 | t.bb);
}
public function get green () {
return this.getTransform().gb;
}
public function set blue (amount) {
var t = this.getTransform();
this.setRGB (t.rb << 16 | t.gb << 8 | amount);
}
public function get blue () {
return this.getTransform().bb;
}
// ----- color percent - Color methods ======
public function set redPercent (percent) {
percent = limit (percent, -100, 100) ;
var trans = this.getTransform();
trans.ra = percent;
this.setTransform (trans);
}
public function get redPercent () {
return this.getTransform().ra;
}
public function set greenPercent (percent) {
percent = limit (percent, -100, 100) ;
var trans = this.getTransform();
trans.ga = percent;
this.setTransform (trans);
}
public function get greenPercent () {
return this.getTransform().ga;
}
public function set bluePercent (percent) {
percent = limit (percent, -100, 100) ;
var trans = this.getTransform();
trans.ba = percent;
this.setTransform (trans);
}
public function get bluePercent () {
return this.getTransform().ba;
}
// ----- color offset - Color methods
public function set redOffset (offset) {
var trans = this.getTransform();
trans.rb = offset;
this.setTransform (trans);
}
public function get redOffset () {
return this.getTransform().rb;
}
public function set greenOffset (offset) {
var trans = this.getTransform();
trans.gb = offset;
this.setTransform (trans);
}
public function get greenOffset () {
return this.getTransform().gb;
}
public function set blueOffset (offset) {
var trans = this.getTransform();
trans.bb = offset;
this.setTransform (trans);
}
public function get blueOffset () {
return this.getTransform().bb;
}
// ----- Tween FX : tweenProperty() , twenRGB()
public function tweenProperty (prop:String, begin:Number, end:Number, duree:Number, equation:Function) {
begin = Math.round (begin) ;
end = Math.round (end) ;
var m = new Tween ( this ,prop , equation || Regular.easeOut , begin , end, duree) ;
m.addListener (this) ;
this.onMotionChanged = function () {
this.broadcastMessage ("onColorChanged")
}
this.onMotionFinished = function () {
m.removeListener (this) ;
this.broadcastMessage ("onColorTweened") ;
}
}
public function tweenRGB ( __r, __g, __b, duree, equation) {
var m:Tween ;
m = new Tween ( this , "red" , equation || Regular.easeOut , red , __r, duree || 18) ;
m = new Tween ( this , "green" , equation || Regular.easeOut , green , __g, duree || 18) ;
m = new Tween ( this , "blue" , equation || Regular.easeOut , blue , __b, duree || 18) ;
m.addListener (this) ;
this.onMotionChanged = function () {
this.broadcastMessage ("onColorChanged") ;
}
this.onMotionFinished = function () {
m.removeListener (this) ;
this.broadcastMessage ("onColorTweened") ;
}
}
}
import com.eka.color.* ;import mx.transitions.easing.* ;
var c:ColorTool = new ColorTool (mc) ;
c.tweenProperty ("brightness", 100, 0, 24, Bounce.easeOut ) ;
c.onColorTweened = function () {
trace ("fin de l'effet") ;
}
// pour changer une couleur unie sur un clip
mc.onPress = function () {
var c:ColorTool = new ColorTool(mc) ;
c.red = 24 ;
c.blue = 48 ;
c.green = 242 ;
c.tweenRGB ( 220, 120, 50, 24, Bounce.easeOut ) ;
c.onColorChanged = function () {
trace (mc + " change de couleur") ;
}
c.onColorTweened = function () {
c.tweenRGB ( 125, 125, 30, 24, Bounce.easeOut ) ;
}
}
bye
oups.. j'ai oublié de bien fermer ma balise
xcuse 
salut,
pas vraiment propre en OO mais bon, c'etait un premier pas 
en voyant vos deux implementations d'outils Color , je me demander si d'un point de vue design OO il etait bien d'integrer des méthodes de Tween ? et si cela est propre (toujours d'un point de vue OO ).
en tout cas c'est marrant moi quand j'avais du faire ca... j'avais etendu color pour les methodes *RGBStr et puis apres pour le lien avec les clip j'avais utilisés les bon vieux prototypes
en tout merci de faire partager ca... je vais pouvior me remettre le nez dedans et essayer de faire un petit menage dans mes classes...
bye
Hehe, pas mal :)! Et pour ceux qui sont encore sous MX, il y a le bon vieux dynColorTween de Tatsuo Kato:
http://www.tatsuokato.com/flash/dynColorTweenMX.html
yoy > Tu as raison sur le fait d'intégrer le Tween à la classe, je ne pense pas non plus que ce soit l'idéal ! C'est pour ça que je ne l'ai pas fait ...
++ ^^
moi je l'ai fait pour aller vite dans certaines situation sinon en effet vaut mieux soit faire une méthode qui hérite de la première, soit une autre méthode qui utilise la première qui hérite de MovieClip par exemple

bye
Sympa LAlex, merci de partager ce portage
Pour ma part, en as1, j'avais fait cela avec les tween proto de zeh http://www.fatorcaos.com.br/ :
demo : http://niko.informatif.org/flash/colorfx2.swf
article : http://niko.informatif.org/index.php/2003/12/05/25-EffetsDeCouleurs
Moi aussi me dit qq chose

Hihi, et voila la façon dont vous l'avez programmé alors....
ouai super ça sert à quoi??
200 ligne de code , pour faire le meme effet qu une interpolation de mouvement avec une luminosité qui augmente sur un clip ?
:S
Oui, en effet, rien de plus facile que de faire une interpolation avec une équation exponentielle pour l'interpolation directement dans Flash en dynamique sur des images chargées depuis l'estérieur !
Merci pour ta brillante contribution dd !
Autre grosse différence c'est le poid de ton animation ... lol

On peut bien entendu imaginer tout faire image par image aussi ... en faisant toutes les images dans imageReady et photoshop .. et ensuite on les importe toutes dans flash .... chacun ses gouts
Pas mal
eka >> tu aurais une exemple de différence de poids ... est ce que c'est réellement significatif ?
parce qu'une interpo sur un symbole(image), c'est pas vas vachement lourd, non ?
et le code... ca pese aussi sont poid...
a+
toutes les images clés sur ta scène pendant une interpolations sont transformées en une image intermédiaire avec une nouvelle position etc... donc tu as autant d'image que tu as d'images clé dans ton swf....

Pour une interpolation qui utilise une penner par exemple, tu gères seulement des calculs sur des valeurs numériques et ensuite tu appliques la valeur numérique sur une propriété du clip .... donc il y a qu'un seul clip et donc une seule image clé.
De toute façon il y a pas photo, suffit de faire de la POO et du développement un peu avancé en flash pour voir la différence, mais il ne faut surtout pas parler sans avoir essayé
bye
pour faire cette effet en "animation", tu n'as besoin que deux images clés.
Et tu utilises l'interpolation de mouvement avec une teinte sur la deuxième image et une accélératon à 100.
Donc le poids de ton swf n'est lié qu'à une seule image (jpg) et deux images clés (keyframe)
Je penses ce que yoy voulait dire à ekameleon.
A+
ui, c'est tout a fait ca.... apres bien sur c'est pas forcement très dynamique (meme sans parler de POO) mais c'est faisable je pense
mais sans avoir l'effet paramétrable ...
@Lalex : je comprends pas ta gestion d'evenement pour le onMotionFinished ... pourquoi il y est deux fois ... pour finir le yoyo ?
La réponse est dans la question !
A ca te fait rire... po moi! en faite, je trouve pas ca forcement logique puisque un yoyo c'est aller-retour... m'enfin!!!
yoy > Eh oh, va pas le prendre comme ca ... :\ Je précise quand-même que ce blog n'est pas une espace de support ... Il suffit de lire le code qui est suffisamment simple pour être compréhensible ! :o
Explication :
La méthode yoyo() se contente d'inverser le début et la fin du tween, et de relancer le Tween. Donc pour le 1er onMotionFinished : à la fin du tween (aller), je lance le yoyo, et j'initialise le onMotionFinished pour qu'à la fin du 2eme Tween (retour), il ré-inverse le sens du tween, et l'arrête, puis ré-initialise le onMotionFinished comme il était au début (pour l'aller suivant)...
Pas de quoi !
euh désolé de t'avoir froissé ... mais c'était sur le ton de la rigolade...
apres le fait que ce soit pas un espace de support, t'inquietes pas, je suis au courant... ya deja eu des commentaires à ce sujet... et puis ta premiere réponse etait suffisament claire. je donné juste mon avis sur le nom de la méthode yoyo...
pas de quoi >> MERCI
Fil des commentaires de ce billet