Comunidad de diseño web y desarrollo en internet online

Crear movieclips complejos en tiempo de ejecución

Citar            
MensajeEscrito el 26 Ago 2011 06:21 pm
Hola gente. Cada vez me siento más inútil, ya que a cada paso que doy, me encuentro con una tarea para mí sencilla en AS2, pero insalvable (para mí también) en AS3.

Os voy a poner en antecedentes.

Estoy haciendo una aplicación en la que se podrán crear instancias de imágenes en la pantalla al pulsar un botón. Cada una de estas imágenes debe ser arrastrable, escalable y rotable.

Gracias a NESTORRENTE, pude hacer la función de escalado en un movieclip puesto a mano en la pantalla (funciona perfectamente, por cierto); lo de moverlo y rotarlo iba a dejarlo para más adelante. Ahora quería probar el escalado en un movieclip creado dinámicamente, pero como soy UN ZOTE DE CUIDADO, no lo consigo.

Os explico cómo creo que debía hacerse y si después de leer esto tenéis tiempo y ganas de explicarme cómo se hace de verdad, os lo agradeceré. Empezamos.

Cada movieclip debe llevar una imagen y unos "tiradores" de transformación similares a los que puede llevar un bitmap cuando lo importas en word. De esta forma, si hacemos "drag" sobre la imagen, el movieclip se desplaza, si hacemos "drag" sobre el tirador de abajo a la derecha, se escala y si hacemos "drag" sobre el superior central, gira.

En estos momentos lo único que me importa es conseguir hacer un movieclip que me carge la imagen especificada, que contenga los tiradores y que se escale. Una vez conseguido esto, creo que agregar lo demás será más de lo mismo.

El movieclip (al que llamaré elMc) creo que debe estar compuesto por la imagen en sí y otro movieclip que representa los tiradores de transformación. Por lo tanto, elMc tiene dentro de sí el loader de la imagen y el movieclip de transformación. Si llamamos a los tiradores de transformación "transform_mc" y el loader de la imagen "img_ldr", debería encontrarme con una serie de movieclips que, a su vez, contendrían instancias de estos últimos que os he comentado.

Para generar el "transform_mc" he dibujado un rectángulo del tamaño de la imagen mediante "graphics.lineTo" y los cuadritos de las esquinas están insertados de la biblioteca. En la biblioteca tengo dos símbolos:"tirador" y "tiradorN". Están vinculados a actionscript con estos nombres desde su panel de propiedades. Esto es porque sólo quiero que se escale desde la esquina inferior derecha, por lo que he creado unos tiradores negros pequeñitos (tiradorN) de 6X6 píxels y un cuadrito balnco más grande (tirador) que es el que hará las veces de "escalador" de 10X10 píxels.

Teniendo esto, dentro elMc, deberían estar img_ldr y transform_mc. Por lo tanto, y desde mi antigua visión de AS2, debería poder acceder a los elementos de esta forma:
elMc.transform_mc - para acceder al transform_mc de cada movieclip que tenga creado.

Obviamente, no funciona. Consigo crear el movieclip principal con su imagen y con sus tiradores, pero no consigo controlar cada parte y, por lo tanto, no consigo asignarles acciones de arrastrar o pulsar o lo que sea.

Os voy a poner el engendro de código que he perpetrado y, por favor, si podéis y tenéis tiempo y ganas, me ilumináis un poco.

Al pulsar el botón de crear mc, se llama a la función cargaIMG que llama a la función posicionaIMG, la cual finaliza la creación:

Código :

//con esta función cargo la imagen
function cargaIMG () {
   var img:URLRequest = new URLRequest("imagenes/chamarra1.png");
   root["img_ldr"] = new Loader();
   this.img_ldr.contentLoaderInfo.addEventListener (Event.COMPLETE,posicionaIMG);
   this.img_ldr.load (img);
}

como véis, he creado el img_ldr en root porque si no, desde la función "posicionaIMG" no podía cargarla en el movieclip contenedor. Sigo con la función "posicionaIMG":

Código :

function posicionaIMG (e:Event) {
   var elMc = new MovieClip(); //El moviuclip contenedor tendrá el nombre "elMc"
   
   //Lo que sigue es para saber el ancho y largo de la imagen cargada. Después, como tiene que llevar
   //el margen necesario para colocar el mc de transformación, le sumo 10 píxels. Después, coloco la
   //imagen cargada dentro de "elMc", en las coordenadas deseadas.
   var anchura = this.img_ldr.width + 10;//el margen de 10 es para dar 5 px por cada lado de la imagen
   var altura = this.img_ldr.height + 10;
   this.img_ldr.x = 5;
   this.img_ldr.y = 5;
   elMc.addChild (this.imgLDR);
   
   //creo un mc de transformación para poder ocultarlo y mostrarlo y manipularlo de forma independiente 
   var transform_mc = new MovieClip();
   //Hago el dibujo del marco en función de las medidas de anchura y altura que he calculado en el paso anterior
   transform_mc.graphics.lineStyle (0, 0x555555, 1, true, LineScaleMode.NONE, CapsStyle.SQUARE);
   transform_mc.graphics.moveTo (2,2);
   transform_mc.graphics.lineTo ((anchura-5),2);
   transform_mc.graphics.lineTo ((anchura-5),(altura-5));
   transform_mc.graphics.lineTo (2,(altura-5));
   transform_mc.graphics.lineTo (2,2);
   
   //creo los cuadraditos de control en base a instancias de los símbolos que tengo creados en la biblioteca
   //y los coloco en las 4 esquinas de "transform_mc"
   var tirador1:MovieClip = new tiradorN();
   tirador1.x = 0;
   tirador1.y = 0;
   transform_mc.addChild (tirador1);
   var tirador2:MovieClip = new tiradorN();
   tirador2.x = anchura - 8;
   tirador2.y = 0;
   transform_mc.addChild (tirador2);
   var tirador3:MovieClip = new tiradorN();
   tirador3.x = 0;
   tirador3.y = altura - 8;
   transform_mc.addChild (tirador3);
   var tiradorB:MovieClip = new tirador();
   tiradorB.x = anchura - 10;
   tiradorB.y = altura - 10;
   transform_mc.addChild (tiradorB);
   
   //Ahora que ya está completo el "transform_mc", lo coloco dentro de "elMc"
   elMc.addChild(transform_mc);
   addChild (elMc);
}

Tras ejecutar esto, me aparece en pantalla un hermoso movieclip con un cuadro de transformación y una preciosa chamarra en el medio.

Mi problema viene ahora. He creado unas funciones de escalado que funcionan muy bien en un movieclui creado "a mano". Ahora, necesito asignar esas funciones al "tiradorB" que se encuentra dentro del "transform_mc", dentro de "elMc". Obviamente no existe elMc.transform_mc.tiradorB (que es como lo haría en AS2).

Si hago un numChildren de elMc, me devuelve 2 (lógico, porque están ahí y se ven en pantalla). Si pregunto por el 0, me dice que es un objeto loader y si le pregunto por el 1 me dice que es un movieclip. Bien, eso es lo que tenía que ser. La cuestión es que si le pregunto por el nombre del child[1], me dice que es instance5, por lo que deduzco que mi "transform_mc" no se llama así, sino "instance5".

Entonces, ¿cómo diantre hago para que los movieclips que creo tengan el nombre que deseo para poder controlarlos independientemente? y ¿cómo hago para asignarles los comportamientos que deben llevar?

Gracias por vuestra paciencia y ayuda.

Por CidDeMizar

81 de clabLevel



 

firefox
Citar            
MensajeEscrito el 26 Ago 2011 06:37 pm
Cuando lo creas le puedes asignar un puntero

var miClip:MovieClip = new MovieClip()

En ese scope (timeline, clase, o lo que uses) miClip es la referencia. Si quieres asignar nombre harías

miClip.name = "algunClip"
var elClip:MovieClip = getChildByName("algunClip")

Esto último no tiene mucho sentido si tienes el puntero, usar el nombre es útil si haz creado el elemento a mano, no por código.

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox
Citar            
MensajeEscrito el 27 Ago 2011 02:11 pm
Gracias Jorge. He conseguido entender a medias el por qué no hace falta lo de los nombres, ya que al crear el movieclip de transformación, le he asignado el listener del mouse click. De todas formas, ahora me funciona a medias. Lo que hace es que, cuando hago click en el tirador blanco, puedo escalar el movieclip, pero SÓLO HAL HACER CLICK, no al arrastrarlo. También, sólo se cancela la acción si vuelvo a hacer click sobre el tirador blanco.

Lo que deberia ocurrir es que al arrastrar el tirador blanco, el movieclip se debería escalar y al soltar el ratón, debería detenerse la escala.

He usado el mismo código que he utilizado en una prueba de escalado con un movieclip creado "a mano", no por programación. En este caso, las funciones de escalado y el reconocimiento de eventos del ratón funcionan perfectamente.

Si no te importa, te coloco el código y, si puedes, le echas un vistazo y me dices dónde la estoy "cagando".

Lo primero, hago declaraciones de varias variables generales, hago la carga de datos de un txt esxterno y resuelvo esos datos:

Código :

// DECLARACIONES

// de la peli
var dir:String;
var dataDir:String;
var laPeli:String;

// transformaciones
var seleccionado_mc:MovieClip;//para saber si hay alguno seleccionado. Defecto, null
var movLocZ:int;//locZ en el momento del arrastre. Sin selección, valor -1
var reposoLocZ:int;//locZ en reposo. Sin selección, valor-1
var trans_mc:MovieClip;//para saber qué tirador se está usando en la transformación
var trans_iniX:int;//locX de inicio de la transformación
var trans_iniY:int;//locY de inicio de transformación
var scale_iniX:Number;//escala X al iniciar transformación
var scale_iniY:Number;//escala Y al iniciar transformación

// de las imagenes en escena
var img_ldr:Loader;//loader de las imágenes

/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// CARGA DE TXT o BD
var dirPel:String = this.loaderInfo.url;
var sep:uint = dirPel.lastIndexOf("/");
dir = dirPel.substr(0,sep + 1);
laPeli = dirPel.substr(sep+1,dirPel.length-1);
dataDir = dir + "imagenes/";

var listaIMG:Array = new Array();
var datos:URLRequest = new URLRequest(dataDir + "data.txt");
var datosCarga:URLLoader = new URLLoader();
datosCarga.dataFormat = URLLoaderDataFormat.VARIABLES;
datosCarga.addEventListener (Event.COMPLETE, resuelveExtData);
datosCarga.load (datos);

function resuelveExtData (e:Event):void {
   listaIMG = datosCarga.data.imagenes.split(",");
   cargaIMG ();
}

Esto funciona bien, ya que me carga lo que necesito. Ahora vienen las funciones de creación de los movieclips:

Código :

//carga la imagen
function cargaIMG () {
   var img:URLRequest = new URLRequest(dataDir+listaIMG[7]);
   img_ldr = new Loader();
   img_ldr.contentLoaderInfo.addEventListener (Event.COMPLETE,insertaIMG);
   img_ldr.load (img);
}

//al finalizar la carga de imagen, se lanza esta función
function insertaIMG (e:Event) {
//creo el movieclip contenedor
   var elMc = new MovieClip();

//calculo alto y ancho de bitmap cargado. En función de estos valores, aplico el márgen
//necesario y coloco el bitmap en las coordenadas deseadas
   var anchura = img_ldr.width + 10;//el margen de 10 es para dar 5 px por cada lado de la imagen
   var altura = img_ldr.height + 10;
   img_ldr.x = 5;
   img_ldr.y = 5;
   elMc.addChild (img_ldr);

   //creo un mc de transformación para poder ocultarlo y mostrarlo
   var transformMC = new MovieClip();
   transformMC.graphics.lineStyle (0, 0x555555, 1, true, LineScaleMode.NONE, CapsStyle.SQUARE);
   transformMC.graphics.moveTo (2,2);
   transformMC.graphics.lineTo ((anchura-5),2);
   transformMC.graphics.lineTo ((anchura-5),(altura-5));
   transformMC.graphics.lineTo (2,(altura-5));
   transformMC.graphics.lineTo (2,2);
   var tirador1:MovieClip = new tiradorN();
   tirador1.x = 0;
   tirador1.y = 0;
   transformMC.addChild (tirador1);
   var tirador2:MovieClip = new tiradorN();
   tirador2.x = anchura - 8;
   tirador2.y = 0;
   transformMC.addChild (tirador2);
   var tirador3:MovieClip = new tiradorN();
   tirador3.x = 0;
   tirador3.y = altura - 8;
   transformMC.addChild (tirador3);

//este es el tirador importante. Lo creo, le activo el modo botón, le asigno el listener del
//mouse y lo agrego al movieclip de transformación.
   var tiradorB:MovieClip = new tirador();
   tiradorB.x = anchura - 10;
   tiradorB.y = altura - 10;
   tiradorB.buttonMode = true;
   tiradorB.addEventListener (MouseEvent.CLICK, iniEscala);
   transformMC.addChild (tiradorB);
   elMc.addChild (transformMC);

//añado el movieclip de transformación al contenedor
   addChild (elMc);
}


y, por fin, aquí están las funciones de escalado:

Código :

function escalar (e:MouseEvent):void {
   var distanciaX:int;//distancia entre cursor y click inicial
   var distanciaY:int;//distancia entre cursor y click inicial
   var porcentajeX:Number;//porcentaje a escalar
   var porcentajeY:Number;//porcentaje a escalar
   var ratio:uint = 5;//ratio de proporción píxels/escala

   distanciaX = stage.mouseX - trans_iniX;
   distanciaY = stage.mouseY - trans_iniY;

   porcentajeX = ((100*scale_iniX) + (distanciaX / ratio)) / 100;
   porcentajeY = ((100*scale_iniY) + (distanciaY / ratio)) / 100;
   if (porcentajeX <=0.1) {
      porcentajeX = 0.1;
   } else if (porcentajeX >= 5) {
      porcentajeX = 5;
   }
   if (porcentajeY <=0.1) {
      porcentajeY = 0.1;
   } else if (porcentajeY >= 5) {
      porcentajeY = 5;
   }
   seleccionado_mc.scaleX = porcentajeX;
   seleccionado_mc.scaleY = porcentajeY;
}

function iniEscala (e:MouseEvent):void {
   // Creamos el listener para redimensionar el MovieClip
   trace (e.currentTarget);
   trace (e.currentTarget.parent.parent);
   seleccionado_mc = MovieClip(e.currentTarget.parent.parent);
   trans_mc = MovieClip(e.currentTarget);
   trans_iniX = stage.mouseX;
   trans_iniY = stage.mouseY;
   scale_iniX = seleccionado_mc.scaleX;
   scale_iniY = seleccionado_mc.scaleY;
   stage.addEventListener (MouseEvent.MOUSE_UP, finEscala);
   stage.addEventListener (MouseEvent.MOUSE_MOVE, escalar);
}

function finEscala (e:MouseEvent):void {
   // Eliminamos el listener que redimensiona el MovieClip 
   stage.removeEventListener (MouseEvent.MOUSE_MOVE, escalar);
   stage.removeEventListener (MouseEvent.MOUSE_UP, finEscala);
}


Ya te he comentado arriba cómo se comporta esto y cómo debería comportarse en realidad. Agradecería tu ayuda.

Un saludo

Por CidDeMizar

81 de clabLevel



 

firefox
Citar            
MensajeEscrito el 27 Ago 2011 05:14 pm
no le pongas el escalar en el mouse_move, crea mejor un enterframe, va a ser mas preciso. cual es bien el resultado de esto? te tira una depuracion el codigo? o simplemente no se comporta como quisieras que se comporta? que es lo que no funciona, salu2.

Por D0M41N

56 de clabLevel



Genero:Masculino  

Argentina

chrome
Citar            
MensajeEscrito el 28 Ago 2011 05:03 pm
Te explico, D0M41N:
el movieclip aparece en la pantalla con la imagen de una chamarra y los tiradores de control (como podría aparecer una imagen que quieres escalar en el word o el photoshop). Lo que quiero hacer es que, al tirar del "tirador" que aparece abajo a la derecha de la chamarra, ésta se escale. Lo que ocurre es que sólo se escala al hacer click (no al hacer drag) y no sé por qué. Este mismo código lo tengo aplicado a un movieclip igual, pero creado a mano (no por programación como este) y funciona perfectamente.

En cuanto a lo de tu sugerencia de hacerlo en el enterFrame, no puede ser, porque si se trata de "arrastrar" un elemento de control, este arrastre se verifica con el mouse.move. si se hiciese con el enter frame, se escalaría independientemente del movimiento que tuviese el elemento de control.

De todas formas, muchísimas gracias por tu respuesta e interés.

Por CidDeMizar

81 de clabLevel



 

firefox
Citar            
MensajeEscrito el 29 Ago 2011 07:42 am
Ya lo he resuelto. Como gran inútil que soy, me había equivocado al escribir el código (ya no sé hacer ni siquiera "copy/paste". El problema estaba en el listener que le había puesto al "tiradorB". Le había puesto:

Código :

tiradorB.addEventListener (MouseEvent.CLICK, iniEscala);

cuando lo que tenía que haber puesto era:

Código :

tiradorB.addEventListener (MouseEvent.MOUSE_DOWN, iniEscala);

Es que estoy "albardao", gente.

Ahora parece que el engendro funciona bien, así que seguiré incorporando las funciones que me faltan, a ver por dónde me casca la próxima vez (que seguro que me cascará).

Me imagino que os daré la murga otra vez en breve.

Gracias a todos y todas por vuestro interés y ayuda.

Un saludo.

Por CidDeMizar

81 de clabLevel



 

firefox

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.