Comunidad de diseño web y desarrollo en internet online

Rompecabezas y puzzles con imágenes en Actionscript

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.


Código Puzzle


Código :

import flash.display.*;
import flash.geom.*;
import flash.filters.*;

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.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate