Pantalla completa y escala del escenario

Antes que nada, disculpen mi version en ingles de Flash por lo cual no puedo traducir todo como en la version al castellano. Por otra parte, no sabia sobre que escribir pero una amiga hizo la pregunta “Como hago que mis archivos flash utilicen toda la pantalla?”. Después de eso recordé que difícil me fue encontrar esa información detallada y tuve que agarrar información de varios tutoríales, artículos y capítulos para entender como funcionaba todo este asunto del posicionamiento en pantalla.
Primero que nada, mencionemos la diferencia entre posicionamiento y escala de nuestro documento y utilizar pantalla completa. Cuando hablamos de pantalla completa, le estamos diciendo a Flash que nuestro documento va a utilizar toda la pantalla y no todo nuestro navegador, esto quiere decir que todo incluyendo el menú inicio (en Windows) o el Finder (en Mac) desaparecen, mostrándonos solo nuestra película, así como sucede en YouTube cuando se ve una película en pantalla completa. Hablaremos de el modo pantalla completa mas adelante.
Bien, entonces si el modo pantalla completa no me sirve para hacer que mi documento Flash utilice todo mi navegador, que hay que hacer? Hay que utilizar un poco de HTML y reescalar nuestro documento con ActionScript.
Para empezar puedes descargarte los archivos necesarios para empezar el tutoríal aquí.
Además de nuestro documento Escenario.fla y Escenario.as esta nuestra clase Fondo que dibuja y posiciona el fondo, y es algo parecido a esto:

 
package {
	import flash.display.Sprite;
	public class Fondo extends Sprite {
 
		//Sprite en el cual se guardara la informacion
		//sobre el fondo
		private var fondo:Sprite = new Sprite();
 
		//Colores y sprites relacionados al fondo
		private var color:uint = 0x181B1C;
		private var gota:Gota = new Gota();
 
		public function Fondo():void {
		}
		public function init():void {
			//Agregamos nuestros Sprites
			addChild(fondo);
			addChild(gota);
			dibujarFondo();
		}
		private function dibujarFondo():void {
			dibujarColor(color);
			//Posicionamos la gota en el centro del escenario
			gota.x = stage.stage.stageWidth/2;
			gota.y = stage.stageHeight/2;
		}
		private function dibujarColor(_color:uint):void {
			//Utilizando la API de dibujo de Flash creamos
			//un relleno del tamano del escenario
			fondo.graphics.clear();
			fondo.graphics.beginFill(_color,1);
			fondo.graphics.moveTo(0,0);
			fondo.graphics.lineTo(stage.stageWidth,0);
			fondo.graphics.lineTo(stage.stageWidth,
                        stage.stageHeight);
			fondo.graphics.lineTo(0,stage.stageHeight);
			fondo.graphics.lineTo(0,0);
			fondo.graphics.endFill();
 
			// Al principio con la funcion clear() limpiamos
			// el contenido grafico de neustro sprite para
			// poder reutilizar este metodo mas adelante
		}
	}
}
 


La clase documento Escenario.as solo contiene estas líneas de código:

 
package {
	import flash.display.Sprite;
	public class Escenario extends Sprite {
		private var fondo:Fondo
		public function Escenario():void {
			init();
		}
		private function init():void {
			fondo = new Fondo()
			addChild(fondo)
			fondo.init()
		}
	}
}
 


Y Escenario.fla solo tiene el llamamiento a la clase de documento. Dentro de este archivo vayamos a la ventana de configuración de publicación (publish settings) que se encuentra dentro del menú archivo. En la pestaña de formatos asegurémonos que esta marcada la opción de HTML y Flash y publiquemos el archivo.

Con esto se crea un archivo .swf y un .html en la misma carpeta que contiene el .fla. Abramos ese archivo, el cual nos muestra el comportamiento en navegador por defecto que tienen las películas Flash, que obviamente no es el que queremos.

Si revisamos las líneas de código anteriores podemos ver que a través de código posicione la gota en el centro del escenario. Por lo cual si el tamaño del escenario es 550 por 400 sus coordenadas serán 275 en x y 200 en y, y si el escenario midiera lo mismo que el navegador? Si te sientes cómodo en javascript puedes decirle al navegador cuanto mide el documento flash y posicionarlo, etc.

Por otro lado esta la ventana configuración de publicación, pero esta vez en la pestaña HTML.

La primer opción son las opciones de publicación por defecto, de las cuales la mas interesante es Solamente Flash (Flash Only) y Solamente Flash – Permitir pantalla completa (Flash Only – Allow Fullscreen). Por el momento nos quedaremos con la opción de solamente Flash.

La segunda opción es para ajustar el tamaño de nuestro documento Flash, La opción que viene por defecto ajusta el tamaño del escenario al tamaño que nosotros tenemos de manera determinada, por lo cual lo cambiaremos a porcentaje, que se refiere al porcentaje en el navegador, por lo cual si ponemos 100 en ancho y 100 en alto tendremos un documento que utiliza el cien por cien de nuestro navegador.

Lo siguiente será ajustar la calidad a máxima (highest), la siguiente opción la dejamos como ventana, alineado HTML por defecto y la opción de escala es la opción mas importante del proceso, hay que seleccionar en No escalar (No scale).
Se que suena raro que le pongamos que no escale cuando lo que queremos es que escale, bueno la respuesta es sencilla, cuando se le ordena que no escale se le esta diciendo que no escale el contenido de nuestra película (MovieClips, Sprites, BitmapData, etc.) sin embargo el escenario si se escala por que arriba le dijimos que el escenario es proporcional al cien por cien de nuestro navegador.
La alineación de nuestra película la necesitamos a la izquierda (Left) y arriba (Top).

Nuestra configuración debió de quedar así:

Después de verificar que esta igual que el pantallaza anterior (o su homologo en castellano) publicamos la película.
Al reescalar nuestro navegador vemos que la película flash no se escala correctamente, esto se soluciona indicándole a Flash donde se posicionara la película, que para funcionar correctamente necesita estar en la esquina superior izquierda. Parece que ya habíamos hecho esto, pero las modificaciones de la publicación eran para el HTML, necesitamos decirle a Flash por otra parte done tiene que posicionar el escenario. Para eso necesitamos importar la clase StageAlign (alinear escenario), para ello añadimos estas líneas de código:

 
//Después de importar la clase Stage
 
	//La clase StageAlign le dirá a flash donde tiene que
	//posicionar el escenario
	import flash.display.StageAlign;
 
//Dentro del metodo init()
 
//Indicamos la posicion que tomara el escenario
		//en nuestro navegador
		stage.align = StageAlign.TOP_LEFT;
 


Agregamos el código y re-publicamos la película Flash.
Si abrimos el HTML veremos que neustro documento utiliza todo el browser y la gota esta en el centro, pero si la reescalamos la gota se queda en su sitio, además hay un borde muy molesto cubriendo nuestro documento.
El primer problema lo podemos resolviendo agregando estas líneas de código:

 
//Antes de declarar el nombre de nuestra clase
 
	//Importamos la clase evento para acceder al evento
	//RESIZE y la clase Stage para trabajar con el escenario
	import flash.events.Event;
	import flash.display.Stage;
 
//Dentro de la funcion init()
 
	//Añadimos un Listener para que ejecute la function
	//dibujarFondo cuando reescalemos la pantalla
	stage.addEventListener(Event.RESIZE, onDibujarFondo);
 
//Dentro de la clase
 
	//Metodo al que llamara el evento re-escalar que a su vez
	//llamara al metodo dibujarFondo()
	private function onDibujarFondo(event:Event):void {
		dibujarFondo();
	}
 


La razón por que dentro de la funcion dibujarFondo hiciera un llamamiento a la funcion graphics.clear() al inicio es por que en este caso el fondo es un color y cada que se reescale el navegador ese relleno de color tiene que desaparecer y ser sustituido por un relleno nuevo. En caso de que no tengas un color como fondo, puedes crear tu metodo con el cual reposiciones los elementos que a ti te interesan.

Ahora para solucionar el problema del borde blanco ingresamos en nuestro documento HTML y agregamos las siguientes líneas dentro de <head>:

 
<style type="text/css">
body {margin:0px;padding:0px;}
</style>
 


Con esto ya tenemos un documento que utiliza todo el navegador y que reposiciona el contenido. Solo nos falta hablar sobre el modo pantalla completa que mencionamos anteriormente. Para ello necesitamos regresar a la configuración de publicación y cambiar el témplate por Flash Only – Allow fullscreen ( Flash solamente – Permitir pantalla completa). Y agregar estas líneas de código en nuestra clase de documento:

 
//Importamos las clases necesarias para activar el modo pantalla
	//completa
	import flash.display.Stage;
	import flash.display.StageScaleMode;
	import flash.display.StageDisplayState;
	import flash.events.MouseEvent;
 
//Dentro de el metodo init:
 
	//Anadimos un listener para que al momento de pinchar sobr
        //el escenario entre en el modo pantalla completa
	addEventListener(MouseEvent.MOUSE_UP,onPantallaCompleta);
 
        //Creamos un metodo que reescale el escenario
		public function onPantallaCompleta(event:MouseEvent):void {
			if (stage.displayState == StageDisplayState.NORMAL) {
				stage.displayState=
                                StageDisplayState.FULL_SCREEN;
			} else {
				stage.displayState=StageDisplayState.NORMAL;
			}
		}
 


Ya terminamos, con esto tenemos una película que utiliza toda todo el navegador y es capaz de entrar al modo pantalla completa. Pero se le puede sacar mas partido a este tema y puedes hacer que una imagen cree un patron y se distribuya por la pantalla, o puedes hacer una imagen como fondo.
Solamente hay que mencionar unos pequeños detalles sobre el modo pantalla completa, cuando nuestra película entra en modo pantalla completa los campos de introducción de texto se deshabilitan y sale un aviso anunciándole al usuario que esta entrando en pantalla completa y como salir.
Puedes descargarte el archivo terminado del ejercicio aquí .

Gizmo

Gizmo

No he tenido tiempo de postear nada nuevo, pero justo hoy termine de ajustar unas cosas que no me gustaban de un proyecto pasado y lo acabo de montar. El proyecto se llama Gizmo y es un sistema de visualización de datos realizado entre vier0n y yo. Gizmo mapea la base de datos de Last.FM y devuelve los artistas similares al artista que se indique.

Aunque Gizmo sea un proyecto pasado, pensamos seguir actualizandolo para que ofrezca mas funciones asi que esperen sorpresas.

Interpolación de color utilizando la clase ColorTransform

Aquí de regreso con otro pequeño tutorial sobre color, esta ocasión explicare como se realiza una interpolación de color utilizando la clase ColorTransform. En caso de que no entiendas alguno de los conceptos utilizados aquí te recomiendo que leas mi post anterior “Conceptos básicos sobre el color en Flash”.

Antes de empezar descárgate los archivos necesarios para realizar el tutorial aquí.

Bueno, revisemos el contenido de los archivos que descargamos, por un lado tenemos la clase Fondo, la cual extiende la clase Sprite y su método dibujar, dibuja un cuadrado del tamaño del escenario con un color al azar como se muestra en seguida:

package {
 
	import flash.display.Sprite;
 
	public class Fondo extends Sprite {
		//Escogemos un color al azar para nuestro fondo
		// y se lo asignamos a la propiedad_color
		private var _color:uint = Math.random()*0xFFFFFF;
 
		public function Fondo():void {
		}
 
		//Dibujamos nuestro fondo
		public function dibujar():void {
			//Empezamos el relleno con el color elegido
			//anteriormente
			graphics.beginFill(_color,1);
			graphics.drawRect(0,0,stage.stageWidth,
                        stage.stageHeight);
			graphics.endFill();
		}
 
		//Creamos un metodo que nos devuelva el valor de _color
		public function get color():uint {
			return _color;
		}
 
		//Creamos un metodo para modificar la proiedad _color
		public function set color(colorVar:uint):void {
			this._color = colorVar;
		}
	}
}


El siguiente es nuestra clase de documento, que añade un objeto de tipo Fondo.

package {
 
	import flash.display.Sprite;
 
	public class InterpolacionEjemplo extends Sprite {
		//Creamos la propiedad _fondo que almacenara
		//nuestro fondo y la inicializamos
		private var _fondo:Fondo = new Fondo()
		public function InterpolacionEjemplo():void {
			ini();
		}
		private function ini():void {
		//Añadimos el fondo a nuestro documento y utilizamos
                //el metodo dibujar de nuestra clase Fondo
                        addChild(_fondo);
			_fondo.dibujar()
 
		}
	}
}


Por otro lado esta InterpolacionEjemplo.fla, que es nuestro documento en el cual se ejecutara el código de nuestra clase de documento.

Y por ultimo se encuentra el archivo “InterpolacionColor.as” el cual se encargara de realizar la interpolación. Dentro del archivo esta el código para poder empezar a trabajar. Antes de mostrar el código, repasemos lo que necesitamos para hacer cualquier interpolación. Al igual que las interpolaciones de movimiento, escala, etc. para realizar una interpolación solamente necesitamos 4 elementos, el primero es el objeto al que se le aplicara la interpolación, lo segundo es el valor inicial de la propiedad a interpolar, el tercero el valor final de dicha propiedad y por ultimo la velocidad (o duración) de la interpolación.

Una vez conociendo estos datos podemos empezar a escribir las primeras líneas de código de nuestra clase, empezamos importando las clases que utilizaremos, después de nombrar nuestra clase definimos las propiedades del objeto (la cual yo llamare _sprite), color inicial ( _colorUno ), color destino ( _colorDos ) y velocidad ( _vel ).

Y por ultimo creamos nuestro constructor, el cual poblara nuestras propiedades.

package {
 
	//Importamos las clases que necesitaremos
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
 
	public class InterpolacionColor {
 
		//Objeto que se interpola
		private var _sprite:Sprite;
 
		//Color actual del objeto
		private var _colorUno:uint;
 
		//Color al que se interpola
		private var _colorDos:uint;
 
		//Velocidad de la interpolación cuyos valores
		//tienen que ser numeros positivos menores a uno
		private var _vel:Number
 
		//Clase constructora donde asignamos los valores
		//iniciales
		public function InterpolacionColor(spriteVar:*,colorUnoVar:uint,
                colorDosVar:uint,velVar:Number) {
			this._sprite = spriteVar as Sprite
			this._colorUno = colorUnoVar
			this._colorDos = colorDosVar
			this._vel = velVar
		}
	}
}


Como podemos ver al principio de nuestro paquete, importamos la clase Sprite ( que funcionara como nuestro DisplayObject ), la clase evento para acceder al evento ENTER_FRAME y por ultimo la clase ColorTransform que cargara el objeto encargado de asignarle el color a nuestro Sprite. En la clase constructora le asignamos el valor a _sprite , _colorUno, _colorDos y _vel.

Antes de seguir adelante hablemos un poco de la clase ColorTransform. Esta clase permite ajustar los valores de color (RGB) y alpha de un DisplayObject (como puede ser un Sprite o Movieclip).
Lo siguiente que hay que saber es como funciona el constructor de esta clase, el cual es algo similar a esto:

 
ColorTransform(redMultiplier:Number = 1.0, greenMultiplier:Number = 1.0,
blueMultiplier:Number = 1.0, alphaMultiplier:Number = 1.0,
redOffset:Number = 0, greenOffset:Number = 0, blueOffset:Number = 0,
alphaOffset:Number = 0)
 


Repasemos los argumentos que pide uno por uno. Empezamos con los primeros cuatro valores (redMultiplier, greenMultiplier, blueMultiplier y alphaMultiplier) los cuales como su nombre indica “multiplican”. Los valores que multiplican es el valor actual del canal de color del objeto. Y los siguientes 4 (redOffset, greenOffset, blueOffset y alphaOffset) es el valor que se le agrega al resultado de la multiplicación entre el valor del canal por su multiplicador. Por lo cual el valor de la transformación de color se calcula de la siguiente manera:

  • nuevo_rojo = ( valor actual del canal rojo * redMultiplier) + redOffset
  • nuevo_azul = ( valor actual del canal azul * blueMultiplier) + blueOffset
  • nuevo_verde = ( valor actual del canal verde * greenMultiplier) + greenOffset
  • nuevo_alpha = ( valor actual del canal alpha * alphaMultiplier) + alphaOffset

Si alguno de los valores calculados es mayor a 255 el valor pasa a ser 255 y si es menor a 0 pasa a ser 0.

Una vez visto el constructor, echémosle un vistazo a la propiedad publica “color”. La propiedad color nos devuelve el valor actual en RGB del objeto ColorTransform , por lo cual aquí es donde almacenaremos nuestros colores intermedios cada vez que los calculemos, para después asignárselo al DisplayObject (en nuestro caso, un Sprite).

Esto cubre lo necesario para realizar la interpolación de color, ahora pasemos al calculo de los colores intermedios.
Antes de hacer cualquier calculo tenemos que descomponer los colores en sus canales RGB respectivamente, para esto utilizaremos los operadores bit >> ( de los cuales hable en mi post anterior). Una vez separados los colores hay que almacenarlos para después hacer nuestras operaciones con ellos. Para esto podríamos crear seis propiedades que nos almacenen lo siguiente:

  • El valor inicial de rojo
  • El valor inicial de verde
  • El valor inicial de azul
  • El valor final de rojo
  • El valor final de verde
  • El valor final de azul

Así podríamos trabajar individualmente con ellos, o podemos crear dos arrays que contengan los valores iniciales y finales. Yo prefiero trabajar con arrays ya que lo encuentro menos confuso.

Una vez creados los arrays hay que crear un método privado que nos descomponga y nos almacene los valores, llamaremos a este método “obtenerColores”, la cual llamaremos en nuestro constructor para que calcule los valores al principio. Por lo cual nuestro código debe verse algo parecido a esto:

 
package {
	//Importamos las clases que necesitaremos
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
 
	public class InterpolacionColor {
 
		//Objeto que se interpola
		private var _sprite:Sprite;
 
		//Color actual del objeto
		private var _colorUno:uint;
 
		//Color al que se interpola
		private var _colorDos:uint;
 
		//Velocidad de la interpolación cuyos valores
		//tienen que ser numeros positivos menores a uno
		private var _vel:Number;
 
		//Creamos dos arrays que guarden nuestros colores
		//descompuestos en sus canales RGB correspondientes
		private var _coloresIniciales:Array = new Array();
		private var _coloresFinales:Array = new Array();
 
		//Propiedad que almacenara una instancia de la clase
		//ColorTransform, que sera la enargada de cambiar el color
		//de nuestro objeto
		private var transformador:ColorTransform
 
		//Clase constructora donde asignamos los valores
		//iniciales
		public function InterpolacionColor(spriteVar:*,colorUnoVar:uint,
                colorDosVar:uint,velVar:Number) {
			this._sprite = spriteVar as Sprite;
			this._colorUno = colorUnoVar;
			this._colorDos = colorDosVar;
			this._vel = velVar;
			obtenerColores();
		}
 
		//método que se encargara de descomponer los colores e
		//inicializar nuestro transformador asignandole los valores
		//actuales de trasformacion de color de nuestro objeto
		private function obtenerColores():void {
			_coloresIniciales["R"] = _colorUno >> 16
		        _coloresIniciales["G"] = _colorUno >> 8 & 0xFF
			_coloresIniciales["B"] = _colorUno & 0xFF
			_coloresFinales["R"] = _colorDos >> 16
			_coloresFinales["G"] = _colorDos >> 8 & 0xFF
			_coloresFinales["B"] = _colorDos & 0xFF
		}
}
}
 


Como podemos observar además de agregar las propiedades “_coloresIniciales” y “_coloresFinales” he creado la propiedad transformador de tipo ColorTransform, el cual utilizaremos mas adelante.
Bueno ahora es hora de empezar a animar. Para ello crearemos el método “empezar” el cual como su nombre lo indica, empezara la animación agregándole un Listener a nuestro objeto InterpolacionColor con un evento ENTER_FRAME que haga referencia al método onEmpezar.
El método onEmpezar tendrá las operaciones necesarias para la animación. Recordemos la formula para hacer una interpolación básica:
a+=(a-b)*vel
Donde a es el valor actual de la propiedad, b el valor final y vel un numero menor a 1 (mientras mas pequeño el numero mas lenta la interpolación).
Esta operación hay que repetirla por cada canal RGB de la siguiente manera:

  • _coloresIniciales["R"]+= (_coloresFinales["R"]-_coloresIniciales["R"])*_vel;
  • _coloresIniciales["B"]+= (_coloresFinales["B"]-_coloresIniciales["B"])*_vel;
  • _coloresIniciales["G"]+= (_coloresFinales["G"]-_coloresIniciales["G"])*_vel;
  • _colorInterpolacion = _coloresIniciales["R"] << 16 | _coloresIniciales["G"] << 8 | _coloresIniciales["B"];

Lo que realiza el método onEmpezar es evaluar los colores de la siguiente manera, primero encuentra la diferencia entre el color actual y el color al que se desea llegar para después multiplicarlo por la velocidad. La velocidad siendo menor a uno hace que el valor cambie de manera proporcional cada vez que se evalúa.

El valor de _coloresIniciales[“R”,”G” o “B”] cambiara cada vez que se evalué esta función para después ser sumados en la propiedad “_colorInterpolacion” (la cual agregue previamente) para después ser asignada a la propiedad color de nuestro transformador. Y para terminar asignamos la transformación de color a _sprite gracias a la propiedad “ transform.colorTransform” que incluyen los DisplayObject
… Suena complicado pero si vemos el código es mas fácil de entender, por lo cual te invito a que mires el código actualizado:

 
package {
//Importamos las clases que necesitaremos
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.ColorTransform;
 
public class InterpolacionColor extends Sprite{
 
//Objeto que se interpola
private var _sprite:Sprite;
 
//Color actual del objeto
private var _colorUno:uint;
 
//Color al que se interpola
private var _colorDos:uint;
 
//Velocidad de la interpolación cuyos valores
//tienen que ser numeros positivos menores a uno
private var _vel:Number;
 
//Creamos dos arrays que guarden nuestros colores
//descompuestos en sus canales RGB correspondientes
private var _coloresIniciales:Array = new Array();
private var _coloresFinales:Array = new Array();
 
//Propiedad que almacenara una instancia de la clase
//ColorTransform, que sera la enargada de cambiar el color
//de nuestro objeto
private var transformador:ColorTransform
 
private var _colorInterpolacion:uint
//Clase constructora donde asignamos los valores
//iniciales
public function InterpolacionColor(spriteVar:*,colorUnoVar:uint,
colorDosVar:uint,velVar:Number) {
	this._sprite = spriteVar as Sprite;
	this._colorUno = colorUnoVar;
	this._colorDos = colorDosVar;
	this._vel = velVar;
	obtenerColores();
}
 
//método que se encargara de descomponer los colores e
//inicializar nuestro transformador asignandole los valores
//actuales de trasformacion de color de nuestro objeto
private function obtenerColores():void {
	_coloresIniciales["R"] = _colorUno >> 16
        _coloresIniciales["G"] = _colorUno >> 8 & 0xFF
	_coloresIniciales["B"] = _colorUno & 0xFF
	_coloresFinales["R"] = _colorDos >> 16
	_coloresFinales["G"] = _colorDos >> 8 & 0xFF
	_coloresFinales["B"] = _colorDos & 0xFF
}
 
	//método publico que inciara nuestra interpolación
	//agregando un Listener con el evento ENTER_FRAME
	public function empezar():void{
		addEventListener(Event.ENTER_FRAME,onEmpezar)
	}
 
	private function onEmpezar(event:Event):void{
	//Obtenemos el valor de transformacion de color del objeto cada
	//vez que entramos en la funcion
	transformador = _sprite.transform.colorTransform;
	//Obtenemos los valores de cada color segun la velocidad indicada
	//gracias a la formula a+=(b-a)*_vel, donde a es el valor de una
	//de las propiedades RGB de nuestro objeto, b el valor de esa
	//propiedad al que se desea llegar y vel la velocidad en la que se
        //llegara al color determinado
	_coloresIniciales["R"]+= (_coloresFinales["R"]-_coloresIniciales
        ["R"])*_vel;
	_coloresIniciales["B"]+= (_coloresFinales["B"]-_coloresIniciales
        ["B"])*_vel;
	_coloresIniciales["G"]+= (_coloresFinales["G"]-_coloresIniciales
        ["G"])*_vel;
	_colorInterpolacion = _coloresIniciales["R"] << 16 |
        _coloresIniciales["G"]
        << 8 | _coloresIniciales["B"];
	transformador.color = _colorInterpolacion;
	_sprite.transform.colorTransform = transformador;
 
	}
}
}
 


Con esto terminamos nuestra clase InterpolacionColor, obviamente podríamos añadir varios métodos mas (como por ejemplo, un método que detenga la interpolación) o incluso subclases con interpolaciones diferentes. Por el momento lo único que falta es aplicarla para ver como funciona. Nuestra clase se aplicaría de la siguiente manera:

 
package {
 
	// Importamos la clase Sprite
	import flash.display.Sprite;
	public class InterpolacionEjemplo extends Sprite {
		//Creamos la propiedad _fondo que almacenara
		//nuestro fondo y la inicializamos
		private var fondo:Fondo = new Fondo();
		//Declaramos la propiedad interpolación que se
		//encargara de contener una instancia de
		//nuestra clase InterpolacionColor
		private var interpolacion:InterpolacionColor;
		public function InterpolacionEjemplo():void {
			ini();
		}
		private function ini():void {
			//Añadimos el fondo a nuestro documento y utilizamos
			//el método dibujar de nuestra clase Fondo
			addChild(fondo);
			fondo.dibujar();
 
			//Construimos nuestra clase InterpolacionColor y
			//le pasamos los argumentos necesarios
			interpolación = new InterpolacionColor(fondo,
                        fondo.color,Math.random()*0xFFFFFF,0.05);
			interpolacion.empezar();
		}
	}
}
 


Como podemos ver lo único que hicimos fue crear nuestro Fondo (el cual tiene su propiedad color) y construir un objeto de clase InterpolacionColor para después ejecutarlo utilizando el método empezar() y ya tenemos nuestra interpolación!
Solo hay un problema, cuando la interpolación llega al color deseado que sucede? El evento ENTER_FRAME se sigue ejecutando, por lo cual es un desperdicio de memoria y hay que detener la función onEmpezar. Eso se puede realizar con un sencillo método “detener()” el cual remueva el Listener del evento ENTER_FRAME. Además hay que agregar la siguiente condicional al final de nuestro método onEmpezar que evalué si los canales de color han llegado a los valores deseados para después hacer un llamamiento a la función detener() y asignarle el valor de _colorDos a nuestro transformador.

 
//Metodo publico que detiene la interpolacion
public function detener():void {
	removeEventListener(Event.ENTER_FRAME,onEmpezar);
}
 
//Condicional dentro de la funcion onEmpezar
if((_coloresFinales["R"]-_coloresIniciales["R"]<1) &&
        (_coloresFinales["G"]-_coloresIniciales["G"]<1) &&
        (_coloresFinales["B"]-_coloresIniciales["B"]<1)){
	transformador.color = _colorDos
	_sprite.transform.colorTransform = transformador
	detener()
}
 


Ya con esto tendriamos una clase funcional para realizar nuestras interpolaciones de color. Sin embargo esta clase tiene mas posibilidades que ofrecer, como por ejemplo:

  • Trabajar con colores de 32 bit
  • Utilizar la clase en un mapa de bits (con algunas ligeras modificaciones)
  • El método yoyo ( método de la clase tween que repite la animación de inicio a fin en un ciclo.
  • Etc.

Por lo pronto aquí dejo para descargar la ultima version de la clase y una aplicación mas practica de la clase con ligeras modificaciones.

Conceptos básicos sobre el color en Flash

Bueno, me gustaría inaugurar el blog con un pequeño tutorial sobre color en Flash en donde cubrire los principios básicos del trabajo con color en Flash.

En este tutorial intentare cubrir de manera sencilla los siguientes temas:

* Numeración hexadecimal
* Diferencia entre la clase Number, int y uint
* Diferencia entre colores de 32-bit y de 24-bit
* Descomposición y ensamblaje de colores con los operadores bit
* Obtener colores al azar

Lo primero que hay que mencionar es que lo colores en Flash se representan en sistema hexadecimal. El sistema hexadecimal es el sistema de numeración posicional de base 16, por lo cual utiliza 16 símbolos. Símbolos de carácter numérico que van del 0 al 9 y seis de carácter alfabético que van de la A a la F. Las letras del alfabeto toman los valores del 10 al 15, empezando por la A, donde la A es 10, la B es 11, y así sucesivamente hasta la F que es el 15.
Para entender el sistema hexadecimal es conveniente repasar el sistema de numeración al que mas estamos acostumbrados, que es el decimal. En nuestro sistema de numeración habitual los números suelen leerse como múltiplos de 10, como por ejemplo el numero 2431 se leería de la siguiente manera: 2x10³ + 4x10² + 3x10¹ + 1 = 2000 + 400 + 30 + 1 = 2431. Este mismo numero en hexadecimal se leería de la siguiente manera: 2x16³ + 4x16² + 3x16¹ + 1 = 8192 + 1024 + 48 + 1 = 9265.

En realidad la importancia de eso recae en que los colores en Flash, al igual que los colores Web, se descomponen en 6 dígitos los cuales corresponden a dos para rojo(red), dos para verde(green) y dos para azul(blue), o puesto de otra manera RRGGBB, por sus siglas en ingles. Cada canal de color RGB puede tener un valor de entre 0 a 255, o lo que es lo mismo de 00 a FF((15x16¹)+15=255). Por lo cual no es muy importante saber leer todo el color, sino entender los distintos valores que tienen RRGGBB en cada color. Por ejemplo: El color FF0000 sabemos que es rojo si lo descomponemos en R:255 G:0 B:0.

Una de las novedades del AS3 son la clase uint y la clase int que seran las clases que utilizaremos para manipular el color. Las dos clases son números enteros (Integers), con la diferencia que uint es un entero absoluto, mientras int puede ser un entero positivo o negativo. Y la clase Number? Bueno la clase Number son nuestros números positivos y negativos con decimales de toda la vida jaja, así que no creo que haya problemas ahí. Hagamos una pequeña prueba con trace para terminar de aclarar el asunto. Para eso necesitaremos un documento Flash AS3 nuevo en el cual introduciremos este código en el primer fotograma

var numVar:Number = 3.5
 
var n:Number
var u:uint
var i:int
 
n = numVar
trace(n) // imprime 3.5
u = numVar
trace(u) // imprime 3
i = numVar
trace(i) // imprime 3
 
numVar = -1
 
n = numVar
trace(n) // imprime -1
u = numVar
trace(u) // imprime 4294967295
u = Math.abs(numVar)
trace(u) // imprime 1
i = numVar
trace(i) // imprime -1



4294967295? La primera vez que lo vi perdí al rededor de una hora buscando el problema, hasta que me di cuenta que era por el valor negativo que asignado a la variable u. Como es de tipo uint, no puede contener valores negativos. Entonces, de donde viene el 4294967295? Las clases uint, int y Number al igual que todas las demás clases tiene sus propios métodos: MAX_LENGTH(longitud máxima) y MIN_LENGTH(longitud mínima). Estos métodos nos devuelven el valor máximo (o mínimo) que un valor de tipo int, uint, o Number pueden llegar a tener. Por defecto al ingresar un numero negativo a una variable de tipo uint nos devuelve el valor máximo que una variable uint puede tener (4294967295), por lo tanto para evitar problemas con los números negativos utilizaremos Math.abs en situaciones donde puede darnos un numero negativo. Math.abs devuelve el valor absoluto del valor al que se le aplica. Para entender mejor la diferencia entre la clase uint, nt y Number agregaremos este código a nuestro código anterior:

trace(Number.MAX_VALUE) // imprime 1.79769313486231e+308
trace(Number.MIN_VALUE) // imprime 4.9406564584124654e-324
trace(int.MAX_VALUE) // imprime 2147483647
trace(int.MIN_VALUE) // imprime -2147483648
trace(uint.MAX_VALUE) // imprime 4294967295
trace(uint.MIN_VALUE) // imprime 0



Como vemos una variable de tipo uint puede almacenar números mas grandes que la clase int. Esto es gracias a que eliminando el signo de negativo queda espacio suficiente para el doble de valores. Con esto se concluye que gracias a sus cualidades concluimos que la clase uint es la clase mas apropiada para los colores de 24 y 32 bits (y ciclos for).
La sintaxis de los colores Web normalmente es #RRGGBB, sin embargo en Flash para los colores de 24 bits se utiliza la sintaxis 0xRRGGBB y para los de 32 bits 0xAARRGGBB. Los colores de 32 bits funcionan igual que los colores de 24 con la única diferencia de sus dos primeros componentes que son números referentes a la propiedad alpha de los colores. Con los colores de 24 bits hay que modificar la propiedad alpha del objeto al que se le aplica en caso de querer hacerlo transparente, y funcionan perfecto con Sprites y MovieClips. Sin embargo los colores de 32 bit están pensados para la clase BitmapData los cuales utilizan este tipo de colores. Al momento de realizar un cambio de color con la clase ColorTransform (de la cual hablare en otro post) sobre una imagen de mapa de bits es importante manejar el canal alpha, de lo contrario nos pondrá el color por encima de todo el mapa de bits, por lo cual el canal alpha hay que calcularlo con numeración hexadecimal al igual que los valores RGB. Por lo tanto 0xFFFF0000 dará un rojo completamente opaco, 0x00FF0000 dará un rojo completamente transparente y 0x80FF0000 dará un rojo medianamente transparente.

Bueno ahora pasemos al tema de los operadores bit >> y << . La función de estos operadores es la de convertir un numero a binario y desplazarlo tantos espacios como se le indique. Esto funciona muy bien para el trabajo con color. Por ejemplo, si tenemos los siguientes valores RGB R:0xFF G:0x66 B:0x00. Para ensamblar los colores podríamos utilizar concatenación de caracteres y algún otro método, pero el método correcto es con el operador << el cual desplaza uno de nuestros parámetros RGB a la izquierda dependiendo de cada uno y deja esos espacios vacíos como 0. Para entender mejor como funciona este operador agreguemos este código al final de todo:

var R:uint = 0xFF;
var G:uint = 0x66;
var B:uint = 0x00;
var color24Bit:uint;
 
color24Bit = R<<16;
trace(color24Bit);
// imprime 16711680 || esto a nivel binario es  1111 1111 0000 0000 0000 0000
 
color24Bit = G<<8;
trace(color24Bit);
// imprime 26112 || esto a nivel binario es 0000 0000 0110 0110 0000 0000
 
color24Bit = B;
trace(color24Bit);
// imprime 0 || esto a nivel binario es 0000 0000 0000 0000 0000 0000
 
color24Bit = R<<16 | G<<8 | B
trace(color24Bit)
// imprime 16737792 || esto a nivel binario es 1111 1111 0110 0110 0000 0000



Si notaste un patrón, bien. lo único que hizo la línea "color24Bit = R<<16 | G<<8 | B" fue sumar los números, esto lo hace gracias al operador lógico OR ("o" y se representa con el símbolo | ) que se encarga de hacer la suma binaria de este modo:

Lo que hace el operador OR es comparar los valores de ceros y unos y si un numero es igual a 1 entonces el resultado es 1 y si los tres valores son ceros el resultado será cero.

El otro operador bit del cual nos ayudaremos para trabajar con colores es el operador >> el cual como has de estar pensando hace lo mismo que << pero hacia la derecha, se entiende mas fácil si se piensa que este operador elimina el numero de caracteres de derecha a izquierda que se le indique. Siguiendo con nuestro archivo anterior, coloquemos este código debajo de todo:

// Recordemos que 0xFF6600 en binario es 1111 1111 0110 0110 0000 0000
 
R = color24Bit>>16
trace(R)
// imprime 255 || esto a nivel binario es 1111 1111
 
G = color24Bit>>8
trace(G)
//imprime 65382 || esto a nivel binario es 1111 1111 0110 0110
G = color24Bit>>8 &0xFF
trace(G)
//imprime 102 || esto a nivel binario es 0110 0110
 
B = color24Bit & 0xFF
trace(B)
// imprime 0 || esto a nivel binario es 0000 0000



Como podemos observar con el valor de R solamente hubo que descartar los dieciséis valores a su derecha, sin embargo con el valor de G y B hay que utilizar el operador lógico AND ("y",se representa &) que funciona de igual modo que OR con la diferencia de que AND al momento de comparar dos valores si uno de ellos es 0 el resultado será 0 y si los dos son 1 entonces el resultado será uno. Entonces si solo desplazamos el valor de color24Bit 8 casillas obtendremos 1111 1111 0110 0110 por lo cual hay que compararlo con 0000 0000 1111 1111 de la siguiente manera:

Y por ultimo tenemos el valor de B, para el cual solo hay que comparar color24Bit con 0xFF del siguiente modo:

Pues estos son los principios básicos del trabajo en color 24 bit en Flash, en caso de querer hacer estas operaciones con un color de 32 bit se sigue el mismo proceso pero con ligeras variaciones tomando en cuenta el valor de AA (alpha). Para ello se crea una variable mas con el nombre de A y yo le cambie el nombre a color32Bit para no confundirnos. El código para un color de 32 bit es el siguiente:

// Para ensamblar un color de 32 Bit
color32Bit = A<<24 | R<<16 | G<<8 | B
 
// Para descomponer un color de 32 bit
A = color32Bit>>24
R = color32Bit>>16 & 0xFF
G = color32Bit>>8 & 0xFF
B = color32Bit & 0xFF



Con estas herramientas podemos referirnos y manipular los colores en Flash, sin embargo antes de terminar quisiera abordar un tema muy sencillo pero de mucha utilidad. Obtener colores al azar. La manera mas sencilla es simplemente asignarle a una variable una valor al azar entre 0x000000 y 0xFFFFFF del siguiente modo:

var color24Bit:uint = Math.random()*0xFFFFFF



Con esto obtenemos un color al azar de entre toda la gama de colores que Flash ofrece.
Si después de leer el post no encuentres utilidad a toda la información que en el publique...es normal, por lo cual lo utilizare en un ejemplo practico. El siguiente ejemplo mostrara como obtener colores al azar de una manera mas controlada, para lo cual es necesario abrir un nuevo documento Flash y un nuevo documento Actionscript en el cual escribimos lo siguiente:

package {
	import flash.display.Sprite
	public class PruebaDeColor extends Sprite {
		private var numCirc:uint = 30;
		//private var colorBase:uint = 0xFF6600;
		public function PruebaDeColor():void {
			ini();
		}
		private function ini():void {
			dibujarCirculos();
		}
                private function dibujarCirculos() {
			for (var i:uint = 0; i<numCirc; i++) {
				var circulo:Sprite = new Sprite();
				var color:uint = obtenerColor();
				circulo.graphics.beginFill(color);
				circulo.graphics.drawCircle(0,0,((Math.random()
                                * (30 - 15 + 1)) + 15));
				circulo.graphics.endFill();
				circulo.x = Math.random()*stage.stageWidth;
				circulo.y = Math.random()*stage.stageHeight;
				circulosArray.push(circulo)
				addChild(circulo);
			}
		}
		private function obtenerColor():uint {
			var R:uint = Math.abs((Math.random() * (255 - 100
                        + 1)) + 100);
			var G:uint =  Math.abs((Math.random() * (50 - 20
                        + 1)) + 20);
			var B:uint =  Math.abs((Math.random() * (100 - 10
                        + 1)) + 10);
			var color24Bit:uint = R<<16 | G<<8 | B;
			return color24Bit;
		}
		private function onClickStage(event:MouseEvent):void {
			for each (var circulo in circulosArray){
				removeChild(circulo)
			}
			circulosArray = new Array()
			dibujarCirculos()
 
		}
	}
}



Guardamos el documento con el nombre PruebaDeColor.as en el mismo directorio donde vamos a poner nuestro archivo *.fla y se lo asignamos como Clase de Documento. Este código genera 30 círculos con posicion, tamaño y color al azar. Sin embargo como se restringieron los valores aleatorios que se podían obtener, solo obtenemos una gama de rojos y violetas.

Este es el ejercicio con algunas modificaciones, pincha en el para que vuelva a generar la imagen.

También podemos variar los valores de un color que escojamos, en este caso escogeremos el 0xFF6600 (de nuevo), para eso descomentamos la quinta línea de código e intercambiamos (o comentamos) nuestra función obtenerColor() por esta otra:

		private function obtenerColor():uint {
			var R:uint = Math.abs((Math.random() * (255 - 100 + 1))
                        + 50)
			var G:uint = colorBase >> 8 & 0xFF;
			var B:uint = colorBase & 0xFF;
			var color24Bit:uint = R<<16 | G<<8 | B;
			return color24Bit;
		}



Con esto solo variamos el valor del rojo. Estas no son las mejores maneras de manejar los colores, normalmente hubiera hecho una función genérica para poder reutilizarla con cualquier color. Sin embargo esto era solo para ilustrar como funciona de manera practica el color en Flash, en el siguiente post explicare como hacer una interpolación de color, sin embargo si se entiende el contenido de este post uno puede hacerlo por su cuenta y así terminar de aprender como funcionan los colores (bueno con esto e investigando sobre la clase ColorTransform).

Lab 01 : Particulas