. .. : Swf.hu 1.0 archívum : Swf.hu főoldal >>> : .. .


 
 
SEGÉDLETEK ActionScript

Dinamikus képgaléria és képátmenet by BitmapData
  feltöltve: 2007.01.06 | szerző: Reider | olvasva: 12405 alkalommal

     
 

A moviecliploaderről és annak működéséről most nem írok mivel itt van rá segédlet ami teljes mértékben elmagyarázza a működését.

//Ez a függvény bontja darabokra a képünket
function initData(target:MovieClip):Void {
      preloader._visible = false;

      //Ha van már betöltött képünk akkor azt eltüntetjük a képernyőről
      movePicOut(loaded);
      //A loaded változó értékét az ellenkezőjére váltjuk vagy 1 vagy 2 lesz.
      loaded = loaded == 1 ? 2 : 1; //(*2*)
      //Eltároljuk a betöltött képünk méreteit
      var picWidth:Number = target._width;
      var picHeight:Number = target._height;

      //Kiszámoljuk hogy hova kerüljön a képünk bal felső sarka hogy a képünk középen legyen
      var xadder:Number = Stage.width/2-picWidth/2;
      var yadder:Number = Stage.height/2-picHeight/2;

      //Létrehozunk egy bitmapdata objektumot ami pontosan akkora mint a betöltött képünk.
      var fullPic:BitmapData = new BitmapData(picWidth, picHeight);
      //A draw segítségével a képünket átkonvertáljuk bitmapdata objektummá
      fullPic.draw(target); //(*3*)
      //Létrehozunk egy kétdimenziós tömböt amiben majd a képünk darabjait tároljuk
      var pictures:Array = multiDimArray(partsVert);
      //Kiszámoljuk mekkora méretűek lesznek a darabok
      var wnum:Number = picWidth/partsVert;
      var hnum:Number = picHeight/partsHor;
      var numx:Number = 0;
      var numy:Number = 0;

      //Elmentjük hogy hány darabból áll a betöltött képünk
      totalParts = partsVert*partsHor
      //Feltöltjük a kétdimenziós tömbünket a darabokkal
      for (var i:Number = 0; i<partsVert; i++) {
            for (var b:Number = 0; b<partsHor; b++) {

                  //Létrehozunk egy akkora bitmapData-t amekkorák a darabok
                  var tempBitmap:BitmapData = new BitmapData(wnum, hnum);
                  //Megadjuk hogy pontosan hol található az a darab amit át szeretnénk másolni a kis                   bitmapdatákba
                  var rect:Rectangle = new Rectangle(numx, numy, wnum, hnum);
                  //Készítünk egy Point ot ami azt adja meg hogy hova másoljuk a fent megadott darabunkat                   a kis bitmapdata-n
                  var point:Point = new Point(0, 0);
                  //Elvégezzük a pixelek átmásolását a fent megadott adatok alapján
                  tempBitmap.copyPixels(fullPic, rect, point); //(*4*)
                  //A tömbünkbe belerakjuk a kép egy darabját
                  pictures[i][b] = tempBitmap;
                  //Megnöveljük az y koordinátát az előző darabunk méretével tehát ugrunk a következő                   sorra
                  numy += hnum;
            }

            //Megnöveljük az x koordinátát vagyis ugrunk a következő oszlopra
            numx += wnum;
            //Az sorunkkal visszaugrunk
            numy = 0;
      }

      if (!swfLoaded) {
            //Kitöröljuk a betöltött képünket ha nem swf ugyanis már átmásoltuk így nincs rá szükség
            target.removeMovieClip();
      } else {
            //A végleges helyre mozgatjuk a még láthatatlan swf-et
            target._x = xadder;
            target._y = yadder;

            //Elmentünk egy referenciát hogy később elérhessük a betöltött swf-et
           swfContainer = target;
      }
      //Továbbadjuk az adatokat a megjelenítő függvénynek
      processData(pictures, loaded, xadder, yadder, picWidth, picHeight);
}

(*2*)
Akinek ez a szintaxis nem lenne ismerős, annak elmagyarázom.
A következő a jelentése: feltétel ? ha_igaz : ha_hamis
Ha a feltétel igaz, akkor a sor a kérdőjel utáni résszel tér vissza, ha hamis, akkor a kettőspont utáni résszel. Ez tulajdonképpen az if( feltétel ){ ha_igaz } else{ ha_hamis } sorral egyenértékű azonban az eredményt visszaadja.

(*3*)
A BitmapData.draw függvénynek egy kötelező paramétere van egy objektum, amiről aztán bitmapdatát készít. A bitmapdatát úgy képzelhetjük el, mint egy nagy táblázatot, aminek minden cellájában egy szín helyezkedik el. Tehát ha a képünk 300x400-pixeles, akkor az azt jelenti, hogy a táblázatunk is ekkora. Ennek segítségével tehát egyszerűen tudjuk manipulálni, másolni, vagy lekérni, hogy egy képen pontosan milyen színértékek vannak.

(*4*)
A BitmapData.copyPixels függvény egyszerűen átmásol egy megadott darabot a nagyobb bitmapdatából. A Rectangle objektum egyszerűen megad egy téglalapot az x,y koordinátái, a szélessége, és a magassága alapján. A Point objektum azt határozza meg, hogy hova kerüljön az átmásolandó téglalapunk, szimplán az x,y koordináták segítségével. Mivel a téglalapunk pontosan akkora, amekkora a kis képünk, ezért a 0,0 vagyis a bal felső sarokba másoljuk a kiválasztott képrészletet.

//Ez a függvény jeleníti meg a képernyőn a darabokat
function processData(map:Array, loaded:Number, xadder:Number, yadder:Number, picWidth:Number,       picHeight:Number):Void {
      var numx:Number = 0;
      var numy:Number = 0;

      //Lekérjük hogy mekkora egy képdarab mérete
      var pieceWidth:Number = map[0][0].width;
      var pieceHeight:Number = map[0][0].height;

      //Kiszámoljuk az átfogó méretét
      var posAdd:Number = calcMaxWidth(pieceWidth, pieceHeight); //(*5*)
      //Kiválasztjuk a megfelelő holdert amibe majd a kép kerül
      var bigPic:MovieClip = this["bigHolder"+loaded];
      //Kitöröljük a képeket ha léteznek a tömbünkből hogy ne okozzanak problémát
      this["mcPics"+loaded].splice(0);
      //A képernyőn elhelyezzük a kis képeket
      for (var i:Number = 0; i<map.length; i++) {
            for (var b:Number = 0; b<map[i].length; b++) {

                  //Minden kis képnek létrehozunk egy moveiClip-et
                  var thumb:MovieClip = bigPic.createEmptyMovieClip("temp"+i+b, bigPic._depth++);//(*6*)
                  //Hozzácsatoljuk a bitmapData-t a létrehozott kis képünkhöz
                  thumb.attachBitmap(map[i][b], 0); //(*7*)
                  //Elhelyezzük a darabokat a látható mezőn kívül véletlenszerűen szétszórva
                  thumb._x = -(random(picWidth))-posAdd;
                  thumb._y = -(random(picHeight))-posAdd;

                  //Beállítunk rajtuk egy véletlenszerű elforgatást
                  thumb._rotation = 180-Math.random()*500;
                  //Elmentjük rajtuk azt a pozíciót ahova majd kerülniük kell
                  thumb.numx = xadder+numx-pixelSnap;
                  thumb.numy = yadder+numy-pixelSnap;

                  //Elmentjük a kisképeket a betöltött képünknek megfelelő tömbben
                  this["mcPics"+loaded].push(thumb);
                  numy += pieceHeight;
            }
            numx += pieceWidth;
            numy = 0;
      }

      //Meghívjuk a beanimálásért felelős függvényt
      movePicIn(loaded);
}

(*5*)
A calcMaxWidth nevű függvény számolja ki a téglalapunk átlóját a Pitagorasz tétel segítségével. Erre azért van szükség, mivel tudnunk kell, hogy mekkora az a távolság, aminél ha nagyobb távolságra helyezzük el a darabjainkat a látómezőn kívül, akkor biztosan nem fognak belógni, akármilyen szögben is állnak.

(*6*)
A thumb nevű movieclip fogja tárolni a kis darabokat, amikből majd a nagy kép fog összeállni. A nevével nem foglakozunk különösebben, mivel az nem lényeg, nem az alapján fogunk rá hivatkozni. A "temp"+i+b összetételt látván, lehet, hogy valaki arra gondol, hogy itt mégis előfordulhat névütközés, mivel 1+2 vagy 2+1 is 3 tehát temp3-at kapnánk mindkét esetben. Ez így nem igaz, mert először a "temp"+i hajtódik végre, ami a számunkat sztringgé fogja konvertálni, és ehhez fogjuk hozzáadni a b-t ami string-szám pár révén újra stringgé konvertálódik, tehát az eredmény temp12 és temp21 lesz. Ha viszont i+b+"temp" lenne ott, akkor viszont végrehajtódna az összeadás, mivel egyenrangú műveletek balról jobbra hajtódnak végre. Zárójelezéssel viszont megadhatjuk a műveleti sorrendet.

(*7*)
Egy elkészített bitmapdata objektum önmagában nem jelenik meg a képernyőn, ahhoz, hogy láthatóvá tehessük, hozzá kell csatolnunk egy MoveClip objektumhoz. Ez pontosan olyan, mint amikor a library-ből veszün ki egy képet és berakjuk egy mc-be. Egy bitmapdatát több mc-hez is hozzá lehet csatolni, így lehetővé válik az újratöltés nélküli kép duplikálás, ami a korábbi flash verziókban nem volt lehetséges.

//Ez a függvény mondja meg a beúszó daraboknak hogy pontosan mit kell csinálniuk
function movePicIn(loaded:Number):Void {
      //Készítünk egy referenciát a betöltendő képeket tartalmazó tömbünkről
      var holdArray:Array = this["mcPics"+loaded];
      //Lenullázzuk a helyrekerült darabok számát
      inloadedParts = 0;
      for (var i:Number = 0; i<holdArray.length; i++) {
            //Létrehozzunk az árnyékot a kis képeknek
            holdArray[i].filters = [shadowFilter];
            //Beállítunk egy random várakozási időt
            holdArray[i].wait = random(30);
            //Beállítunk egy random sebességi értéket
            holdArray[i].speed = Math.random()*inSpeed+1;
            //A moveInPieces függvény meg fog hívódni minden enterframe-kor
            holdArray[i].onEnterFrame = moveInPieces;
      }
}

//Ez a függvény mondja meg kiúszó daraboknak hogy pontosan mit kell csinálniuk
function movePicOut(loaded:Number):Void {
      //Készítünk egy referenciát a betöltendő képeket tartalmazó tömbünkről
      var holdArray:Array = this["mcPics"+loaded];
      //Végigmegyünk a képeket tartalmazó tömbünkön
      for (var i:Number = 0; i<holdArray.length; i++) {
            //Ha egy kép a látómezőn kívül helyezkedik el akkor kitöröljük
            if (holdArray[i]._x<0 && holdArray[i]._y<0) {
                  holdArray[i].removeMovieClip();
            } else {

                  //He már látható helyen van a kép beállítjuk a kezdő elmozdulást
                  holdArray[i].pix = 1;
                  //Beállítunk egy véletlenszerű mozgási sebességet
                  holdArray[i].inc = Math.random()*outSpeed+.5;
                  //Beállítunk egy véletlenszerű elforgatási értéket

                  holdArray[i].rot = 2-Math.random()*4;
                  //Beállítjuk az árnyékot
                  holdArray[i].filters = [shadowFilter];
                  
//A moveOutPieces függvény meg fog hívódni minden enterframe-kor
                  holdArray[i].onEnterFrame = moveOutPieces;
            }
      }
}

//Ez a függvény mozgatja be a darabokat
function moveInPieces():Void {
      //Amíg a várakozás nem 0 nem csinálunk semmit
      if (this.wait != 0) {
            this.wait--;
      } else {

            //Megnézzünk hogy 1 pixelnél nagyobb-e a végleges pozíció és a jelenlegi pozíció távolsága
            var bol1:Boolean = Math.abs(this.numy-this._y)>1;
            var bol2:Boolean = Math.abs(this.numx-this._x)>1;
            var bol3:Boolean = Math.abs(this._rotation)>1;

            if (bol1 || bol2 || bol3) {
                  //Amíg valamelyik irányban mozogni kell addig mozgatjuk a képet
                  this._y += (this.numy-this._y)/this.speed;
                  this._x += (this.numx-this._x)/this.speed;
                  this._rotation += (-this._rotation)/this.speed;
            } else {

                  //Amikor megérkezik a kiskép a végleges pizícióba állítjuk
                  this._y = this.numy+pixelSnap; //(*8*)
                  this._x = this.numx+pixelSnap;

                  //Levesszük az elforgatást
                  this._rotation = 0;
                  //Levesszük az árnyékot
                  this.filters = [];
                  //Inkrementáljuk a végleges helyre került darabok számát
                  inloadedParts++;
                  //Ha az összes darab elfoglalta a helyét és swf volt az amit betöltöttünk
                  if (inloadedParts == totalParts && swfLoaded) {
                        //Láthatóvá tesszük az swf-ünket
                        swfContainer._visible = true;
                        //az első frame-re ugrunk ugyanis erről készítettünk képet
                        swfContainer.gotoAndPlay(1);
                  }
                  //Kitöröljük az enterframe-et így többet nem hívódik meg ez a függvény
                  delete this.onEnterFrame;
            }
      }
}

(*8*)
A pixelSnap változónk, amit fent definiáltunk felelős azért, hogy a kis képek a helyükre kerülés előtt, a változó által megadott értéket ugranak lefelé, amikor az árnyék eltűnik, így olyan hatást kelt, mintha a levegőben úszó darabok a földre zuhannának.

//Ez a függvény mozgatja a darabokat kifelé
function moveOutPieces():Void {
      //Megadjuk az elmozdulás mértékét
      this._x += this.pix;
      this._y += this.pix;

      //Beállítjuk a forgás mértékét
      this._rotation += this.rot;
      //Inkrementáljuk az elmozdulást így gyorsuló mozgást kapunk majd
      this.pix += this.inc;
      //Ha már nem látszik a kép vagyis kiért akkor kitöröljük
      if (this._x>Stage.width && this._y>Stage.height) {
            this.removeMovieClip();
      }
}

//Ez a függvény létrehoz egy kétdimenziós tömböt
function multiDimArray(dim:Number):Array {
      var dimArray:Array = new Array();

      for (var i:Number = 0; i<dim; i++) {
            dimArray.push(new Array());
      }
      return dimArray;
}

//Pitagorasz tételét felhasználva kiszámítjuk az átfogót
function calcMaxWidth(a:Number, b:Number):Number {
      var num:Number = Math.pow(a, 2)+Math.pow(b, 2);
      return Math.sqrt(num);
}

//Ez a függvény visszaadja a következő betöltendő képet
function getItem(num:Number):String {
      var ln:Number = picArray.length-1;
      if (num) {
            index>=ln ? index=0 : index++;
      } else {
            index<=0 ? index=ln : index--;
      }
      picInfoField.text = "Picture: "+(index+1)+"/"+(picArray.length);
      var element:String = picArray[index];
      //Megkeressük az utolsó pontot az elérési útvonalunkban
      var dotIndex = element.lastIndexOf(".");
     //Ezzel a művelettel megkapjuk a kiterjesztést és megnézzük hogy swf-e a betöltendő file
     swfLoaded = element.substr(dotIndex+1) == "swf"
     return element;
}

//Ez a függvény leellenőrzi hogy használható adatok vannak-e a beviteli mezőkben
function checkFields():Void {
      var inputVert:String = vertNumField.text;
      var inputHor:String = horNumField.text;
      if (inputHor == "0" || inputHor == "") {
            partsHor = 10;
            horNumField.text = 10;
      } else {
            partsHor = Number(inputHor);
      }
      if (inputVert == "0" || inputVert == "") {
            partsVert = 10;
            vertNumField.text = 10;
      } else {
            partsVert = Number(inputVert);
      }
}

//A next gomb eseménye
NextBtn.onRelease = function():Void {
      //Ellenőrizzük hogy jó adatok vannak-e a beviteli mezőkben
      checkFields();
      //Betöltjük a következő képet
      loadAndCreateBitmap(getItem(1));
      //Felülre rakjuk az új kép movieclipjét
      bigHolder1.swapDepths(bigHolder2);
};

//A prev gomb eseménye
PrevBtn.onRelease = function():Void {
      //Ellenőrizzük hogy jó adatok vannak-e a beviteli mezőkben
      checkFields();
      //Betöltjük az előző képet
      loadAndCreateBitmap(getItem(0));
      //Felülre rakjuk az új kép movieclipjét
      bigHolder1.swapDepths(bigHolder2);
};

Ezzel végére is értünk a segédletnek. Remélem sikerült ötleteket adnom azoknak, akik még nem használták a BitmapData osztályt, és ezután kedvet kapnak a megismeréséhez. A segédletben nem egy komponensszerű flasht akartam létrehozni, hanem inkább megértetni, hogy a különböző módszereket hogyan lehet együtt hatékonyan használni. Célom volt még, hogy segítséget tudjak nyújtani azoknak, akik hasonló effekteket akarnak készíteni, de nem tudják hogyan kezdjék, vagy nem tudták összekötni a külön részeket, hogy megfelelően működjenek.

 
     
 
 

© Devnet.hu. A segédletek semmilyen formában nem másolhatók, publikálhatók a Devnet.hu és a szerzők közös írásos engedélye nélkül.
 
. .. : Swf.hu 1.0 archívum : Swf.hu főoldal >>> : .. .