Muchas veces necesitamos dividir una imagen en partes independientes para hacer diversos efectos. Este código efectúa una partición en trozos de cualquier imagen. Las "piezas" quedan almacenadas como un array llamado pz[] para poder moverse o usarse según convenga. Está escrito como una función llamada puzzle a la que llamamos para dividir la imagen del siguiente modo:
Código :
puzzle("imagen", filas, columnas, false);
Imagen es el nombre de vinculación desde la biblioteca, luego las filas y colunmas deseadas y por último si hacer cuadros o piezas de puzzle (true o false).
Simplemente la llamamos y ya está hecho completamente el puzzle!!
Las piezas del puzzle tienen cada una una forma de borde distinta que se genera aleatoriamente. La profundidad y brillos de los bordes y el "imán" de posición se ajustan automáticamente dependiendo del tamaño de las piezas.
La partición en cuadraditos, tiras, etc es muy util para efectos de transiciones de imágenes tipo explotar, entrelazado, recombinación, etc. Pondré ejemplos posteriormente con estas y otras transiciones.
He añadido solamente el cambiador de nivel, un ajustador automático de posición y un detector de puzzle terminado o "todas en su sitio" en las funciones de drag. Las funciones de mezcla y dispersión no las incluyo porque son funciones aparte que dependen de la aplicación que demos al script.
Ejemplo: Clickear en las piezas para moverlas y usar los botones para ver distintas formas y divisiones.
puzzle("imagen", 4, 4, false); // tipo de llamada a la función
function puzzle(imagen, f, c, lin) { for (hg=0; hg<4*tpz; hg++){pz[hg].removeMovieClip();} // borra puzzle anterior si existe. a=new Array(1,12,0,.35,2,12,1,.15,3,2,4,.2,5,4,6,.5,7,6,8,.5,10,12,2,.15,9,8,10,.4,11,12,10,.15); tpz = f*c; c>f ? j=20/c : j=20/f; bF = new BevelFilter(1,45,0xffffff,.5,0,.5,j,j,4,3,"inner",false); img = BitmapData.loadBitmap(imagen); w = img.width; h = img.height; m1 = w/(3*c); m2 = h/(3*f); // creando matriz delados congruentes entre piezas contiguas p = []; d = 0; for (m=0; m<4*tpz; m+=4) { p[m+7] = p[m+1] = d++; if((d-1)%(2*c) == 2*(c-1)) {p[m+1]=p[(m+4)%(4*tpz) +3]=2*tpz-2}; p[m+4*c] = p[m+2] = d++; if(d>2*(tpz-c) && d%2 == 0) {p[m+2]=p[(m+4*c)%(4*tpz)]=2*tpz-1}; } for (g=0; g<2*tpz; g++) { b[g] = []; b[g][0] = new Point(m1, m2); alea()<0 ? sig=-1 : sig=1; // las curvas de encaje para distinto lado aleatoriamente if (g%2 == 0) { //puntos para lados horizontales b[g][12] = new Point(m1, 4*m2); b[g][4] = new Point(m1-m1*sig*.6, m2*(2+alea())); b[g][6] = new Point(m1-m1*sig*.9, m2*(2.5+alea())); b[g][8] = new Point(m1-m1*sig*.6, m2*(3+alea())); } else { //puntos para lados verticales b[g][12] = new Point(4*m1, m2); b[g][4] = new Point(m1*(2+alea()), m2-m2*sig*.6); b[g][6] = new Point(m1*(2.5+alea()), m2-m2*sig*.9); b[g][8] = new Point(m1*(3+alea()), m2-m2*sig*.6); } for (r=0; r<29; r+=4){ //puntos centrales de curvas para H y V b[g][a[r]] = Point.interpolate(b[g][a[r+1]],b[g][a[r+2]],a[r+3]+alea()); } } pz = []; pt=[]; for (n=0; n<f*c; n++) { pz[n] = createEmptyMovieClip("pz"+n, n+1); tmp2 = new BitmapData(5*m1, 5*m2, true, 0); pt[n] = new Point((n%c)*3*m1-m1, Math.floor(n/c)*3*m2-m2); tmp2.copyPixels(img,new Rectangle(pt[n].x,pt[n].y,5*m1,5*m2),null); //dibujando los 4 lados de cada pieza for (z=0; z<4; z++) { z == 2 ? sy=3*m2 : sy=0; z == 1 ? sx=3*m1 : sx=0; g = p[4*n+z]; pz[n].beginBitmapFill(tmp2); pz[n].moveTo(5*m1/2, 5*m2/2); pz[n].lineTo(b[g][0].x+sx, b[g][0].y+sy); if (g>(2*tpz-3) || lin){pz[n].lineTo(b[g][12].x+sx, b[g][12].y+sy);} else { pz[n].lineTo(b[g][1].x+sx, b[g][1].y+sy); for (j=2; j<12; j+=2){ pz[n].curveTo(b[g][j].x+sx, b[g][j].y+sy,b[g][j+1].x+sx,b[g][j+1].y+sy); } pz[n].lineTo(b[g][12].x+sx, b[g][12].y+sy); } pz[n].lineTo(5*m1/2, 5*m2/2); pz[n].endFill(); } //doblando la asignacion para evitar fallos de ajuste por decimales. pz[n]._x = pt[n].x; pt[n].x = pz[n]._x; pz[n]._y = pt[n].y; pt[n].y = pz[n]._y; pz[n].filters = [bF]; pz[n].v = n; } for (h=0; h<tpz; h++) { pz[h].onPress = function() { this.startDrag(); this.swapDepths(tpz+1); } pz[h].onRelease = function() { this.stopDrag(); // iman de colocación si la pieza está cerca de su sitio. cerca = new Point(this._x,this._y) if (Point.distance(pt[this.v],cerca)< 4+(m1+m2)/15){ this._x = pt[this.v].x; this._y = pt[this.v].y; } //comprobador de puzzle completo o piezas que faltan por colocar cnt=0; for (tt=0; tt<tpz; tt++){ if((pz[tt]._y == pt[tt].y) && (pz[tt]._x == pt[tt].x)) {++cnt;} cnt==tpz ? texto="completo" : texto="faltan: "+(tpz-cnt); } } } function alea() {return (.1-Math.random()/5);} // función de extración aleatoria en general. }
No son necesarias modificaciones pues todos los parámetros se autoajustan. Si acaso variar el radio mínimo de captación y la "potencia" del iman de colocación: if (Point.distance(pt[this.v],cerca)< 4+(m1+m2)/15){
En los ejemplos de transiciones y juegos que usan esta función que ya iré posteando, les he incluido volumen y sombras.
Aquí trato simplemente el modo de división, no el Puzzle de formas como juego específico. Ni el modo Sam Lloyd ni ningún otro. Mi idea era poner el "motor" de fabricación de piezas y luego ponerle unas tropecientas mil funciones para usarlo. Como digo en el tip:
" Las funciones de mezcla y dispersión no las incluyo porque son funciones aparte que dependen de la aplicación que demos al script."
En la aplicación específica para puzzle de formas SI tengo la función de agrupación exterior asi como botón de de fondo visionable, recomposición automática con movimiento, zoom, giro de piezas y ayuda focal, etc. Además de que el puzzle completo pueda ser de cualquier forma (no solo un rectangulo). Pero esa es una aplicación entera y no un Tip de uso.
Espectacular. Una pena que sea un principiante y no sepa cómo llamar a la funcion puzzle. He copiado y pegado el código tal como está y no funciona. Si colgaras el fla sería fantástico.
Para usar este ejemplo hay que hacer simplemente 3 cosas: TENER UNA IMAGEN EN LA BIBLIOTECA (PNG, GIF, BMP, JPG..) Poner la imagen en la biblioteca del FLA. y vincularla con el nombre "imagen" OJO : vincularla no es ponerla en el escenario. Colocar u MC, gráfico o botón en el Escenario y darle nombre de instancia es "instanciar", no es "vincular para attach". Instrucciones para vincular una imagen que está en la biblioteca: 1) En la biblioteca pones una imagen llamada digamos "paisaje". 2) Pinchas con ratón derecho sobre su icono en la biblioteca. 3) Pinchas en vinculación en el menú que aparece. 4) En la ventana que sigue: Propiedades de vinculación marcas Exportar para ActionScript , marcará también Exportar en primer fotograma, déjalo marcado. En identificador pon imagen (ese es el nombre que buscará el script para cargarlo en attach). Deja la entrada de Clase AS2 en blanco. pulsa Aceptar. Si todo ha ido bien, en las columnas de la biblioteca verás: nombre, tipo, nº de usos, y en vinculación la palabra imagen.
COLOCAR EL CODIGO EN LAS ACCIONES DEL PRIMER FRAME DE LA LINEA DE TIEMPO PRINCIPAL
LLAMAR A LA FUNCION PUZZLE CON LOS PARAMETROS QUE DESEEMOS: En el código hay una linea que hace la llamada: puzzle("imagen", 4, 4, false); // tipo de llamada a la función Cambiamos los parametros que deseemos de filas y columnas (4 y 4 en este ejemplo) y si deseamos cuadraditos( true) o piezas de puzzle (false). El primer parámetro "imagen" es el nombre que pusimos para la vinculación desde la biblioteca.
Muchísimas gracias por tu consideración hacia los torpes y principiantes como yo. Voy a seguir tus instrucciones al pie de la letra a ver si esta vez tengo más suerte.
Lo siento Teseo pero después de haberte tomado las molestias de explicar cómo se vincula una imagen yo he seguido tus pasos uno a uno y me sigue sin funcionar. Sigo pensando que no te cuesta ningún trabajo colgar el fla.
HOLA! Justamente esto es lo que necesito hacer pero con el MACROMEDIA FLASH MX 2004, con estos códigos me da error... ¿hay otra manera de hacerlo o sabéis como puedo hacer esto pero con este programa?? Muchas gracias!
Creo que Teseo ha configurado el código para que sólo 'funcione'en Flash8 aunque yo he copiado, pegado el código y he seguido sus instrucciones y tampoco funciona. Me encantaría poder ayudarte porque a mí me interesa muchísimo este código y espero que Teseo se apiade de nosotros y nos cuelgue el fla o nos diga qué es lo que hacemos mal. Yo estoy dispuesto a que si Teseo me proporciona su correo electrónico mandarle el fla con su código para que él vea que no funciona y me diga qué es lo que estoy haciendo mal.
andsigil, NO funciona con otra versión que NO sea Flash 8. Simplemente así es. Es por el uso de BitmapData. No hay forma de hacerlo funcionar en MX 2004. acéptalo, serás mejor persona
Ya sé que el código 'funciona' SÓLO en Flash 8. Lo que yo comento es que a mi ni siquiera me funciona en Flash8. Ya lo he comentado en el foro y estoy a la espectativa de que alguien me explique qué es lo que hago mal para que tampoco me funcione en Flash8. Acepto mis limitaciones y acepto que soy un torpe. Estaba intentando ayudar al mensaje puesto por AYUDA!!_blog. De todas formas, gracias por tus comentarios, Freddie.
Hola Teseo yo comparto la misma incertidumbre de andsigil_blog soy nueva en flash y no logro que tu codigo funcione, por favor me puedes mandar el FLA a mi correo confundida181083@yahoo.com. Te lo agradeceria muchisimo.
Hola mira yo necesito hacer algo más o menos parecido. El problema es: Tengo unos test psicométricos en el cual uno consiste en ensamblar piezas pequeñas para armar una pieza grande, apuesto que alguna vez lo han hecho, bueno el punto es que hay muchisimas formas de ensamblar la figura y no se quiere limitar a el usuario a solo armarla de la forma que a nosotros se nos ocurre, entonces lo único que necesito es como saber si una pieza esta encima de otra, pero las piezas son amorfas y hasta ahorita solo he encontrado detector de colisiones que toman la pieza como si fuese un cuadrado o un rectángulo, alguien me podría ayudar con eso, necesito algo asi como un detector de colisiones para figuras amorfas. gracias
dark: Veamos el código que fabrica las curvas de cada lado del puzzle:
Código :
for (g=0; g<2*tpz; g++) { b[g] = []; b[g][0] = new Point(m1, m2); alea()<0 ? sig=-1 : sig=1; // las curvas de encaje para distinto lado aleatoriamente if (g%2 == 0) { //puntos para lados horizontales b[g][12] = new Point(m1, 4*m2); b[g][4] = new Point(m1-m1*sig*.6, m2*(2+alea())); b[g][6] = new Point(m1-m1*sig*.9, m2*(2.5+alea())); b[g][8] = new Point(m1-m1*sig*.6, m2*(3+alea())); } else { //puntos para lados verticales b[g][12] = new Point(4*m1, m2); b[g][4] = new Point(m1*(2+alea()), m2-m2*sig*.6); b[g][6] = new Point(m1*(2.5+alea()), m2-m2*sig*.9); b[g][8] = new Point(m1*(3+alea()), m2-m2*sig*.6); } for (r=0; r<29; r+=4){ //puntos centrales de curvas para H y V b[g][a[r]] = Point.interpolate(b[g][a[r+1]],b[g][a[r+2]],a[r+3]+alea()); } }
La curva a generar necesita 13 puntos (0 a 12) para poder dibujarse. Primero tengo que determinar, a partir del punto 0, los puntos 12 (otro extremo del lado), 4 ,6 y 8 ("anchor" de cada curva). Hay dos grupos en el código según sea horizontal o vertical el lado. Esos puntos saldrán aleatoriamente a un lado u otro de la recta 0-12 según el signo de la variable sig : alea()<0 ? sig=-1 : sig=1; Para que sea la curva continua, tienen que estar alineados en la misma recta cada grupo según el gráfico. El array a[] se divide en grupos de 4 a=new Array( 1,12,0,.35, 2,12,1,.15, 3,2,4,.2, 5,4,6,.5, 7,6,8,.5, 10,12,2,.15, 9,8,10,.4, 11,12,10,.15); y va generando los puntos restantes(1,2,3,5,7,10,9 y 11) por interpolación en la recta. b[g][a[r]] = Point.interpolate(b[g][a[r+1]],b[g][a[r+2]],a[r+3]+alea()); Es decir: Para obtener el punto 1 interpolo en la recta 12-0 en porcentaje .35 (+/- un alea de .1) para el 2 recta 12-1 porcentaje .15 (+/- un alea de .1) ...y así continua el bucle con el resto del array. Observa que tengo que determinar el punto 10 antes que el 9 pues para determinar el 9 necesito previamente el 10. Ese es el motivo de la alteración del orden de esos elementos en el array. Los añadidos de aleatorio en el porcentaje de interpolación generan la variación en la forma de la curva.
Bueno, desde hace rato llevo buscando en que parte esta el punto de posicion de cada pieza, por que cuando le metes rotacion a una pieza, esta se posiciona de tal forma que el punto de registro esta en la esquina iquierda de arriba.(la verdad es qun poco mas movido a la izquerda la verdad)¿por que pasa esto y como se soluciona?