wz
Živě.cz

Živě.cz o počítačích a internetu

Začínáme s Flash MX 2004: 13. díl – odkrývání objektu pomocí maskování

Ondřej Brichta 6.6.2005

V minulém díle jsme se naučili vytvořit masku pomocí ActionScriptu. Dnes si vyzkoušíme vytvořit zajímavý efekt odkrývání objektu pomocí malých čtverců tvořících jednu masku, při kterém opět využijeme maskování pomocí ActionScriptu a další již naučené funkce.

Následující postup lze použít například při zobrazení malých náhledů obrázků, krátkých textů apod. Ovšem nevýhoda se projeví při maskování velkého objektu. Pokud totiž provedeme maskování velkým množstvím malých objektů (řádově tisíce), které tvoří samotnou masku, dojde k neúměrnému zatížení procesoru a animace se začne trhat, ztrácí na plynulosti. Je proto dobré maskovat menší objekty (cca 200 x 200 pixelů) nebo snížit rychlost maskování například na 2 a více sekund (viz poznámka u proměnné „opakovani“).

Popis scény

Na scéně se budou vyskytovat dva objekty. Jeden, který bude tvořit masku a druhý, který bude objektem maskovaným.

Maskovaným objektem může být prakticky cokoliv. Jen musíme mít na paměti, že pokud budeme chtít maskovat textové pole, nebude maska fungovat při použití tzv. “device fonts“. Pokud chceme maskovat text, musí se jednat o statický text. V případě dynamického textového pole je nutné „přibalit“ použité fonty ( Properties - Character... - Specify Ranges...).

Funkci masky bude plnit MovieClip (MC), který obsahuje MovieClipy tvaru čtverce, jejichž počet a umístění nastavíme podle rozměrů objektu, který chceme maskovat.

Vytvoření dynamické masky

Importujeme na scénu obrázek nebo si objekt nakreslíme sami. Doporučuji pro začátek velikost již zmiňovaných 200x200px. Z objektu vytvoříme MC (klikneme pravým tlačítkem myši na objekt a vybereme položku - Convert to symbol - MovieClip.), název může být třeba „foto“.

Nezapomeneme umístit registrační značku symbolu do levého horního rohu.

Otevřeme panel vlastností „Properties“ a pojmenujeme objekt „image“ . Máme tak pojmenovanou instanci objektu, abychom mohli později zjišťovat jeho polohu a rozměry.

Na scéně vytvoříme čtverec o rozměrech 10x10px. Kliknutím pravého tlačítka myši zobrazíme menu ze kterého vybereme položku „Convert to Symbol“ a změníme objekt na MC. Nazveme jej například „čtverec“.

Nyní musíme instanci klipu čtverec pojmenovat.V panelu Properties napíšeme jako jméno instance „m1“.

Dále potřebujeme vytvořit MC masky, ve které bude tento čtverec tvořit základní objekt, který se bude duplikovat a vytvářet tak celou masku. Klikneme pravým tlačítkem myši na objekt čtverce, zvolíme „Convert to Symbol“ a vytvoříme z čtverce další MC. Nazveme jej „maska“ a pojmenujeme na panelu „Properties“ pro změnu také „maska“.

Nyní máme na scéně dva objekty, jeden pojmenovaný „image“ a druhý „maska“. Objekt „image“ budeme postupně odkrývat pomocí objektu „maska“ a to díky tomu, že v objektu maska vytvoříme několik kopií malého čtverce.

Dále si vytvoříme MC, který ale zůstane prázdný a bude nám sloužit pouze jako ovládací prvek animace. Pomocí Ctrl+F8 vytvoříme nový movie clip, necháme jej prázdný a umístíme kamkoliv na hlavní pracovní plochu (přetažením z knihovny ).

Dosud jsme pouze kreslili a pojmenovávali instance objektů. Už je tedy nejvyšší čas začít něco programovat.

ActionScript

Následující kód je přiřazen prázdnému MC. Na hlavní scéně klikneme na náš prázdný clip (malé kolečko) a na panelu akcí se objeví „Actions - Movie Clip“. Otevřeme panel akcí a začneme psát první řádky kódu:

onClipEvent (load) {
//po načtení MC
//umístíme objekt maska na souřadnice obrázku - proto jsme umístili registrační značku obrázku vlevo
//nahoru, protože se souřadnice MC počítají právě od ní
// this._parent odkazuje na nadřazený objekt (instanci), v našem případě to je hlavní osa
  this._parent.maska._x = this._parent.image._x;
  this._parent.maska._y = this._parent.image._y;
  //zjistíme rozměry malého čtverce
  sirka = this._parent.maska.m1._width;
  vyska = this._parent.maska.m1._height;
  //zjistíme parametry obrázku
  imsirka = this._parent.image._width;
  imvyska = this._parent.image._height;
  //nastavení počtu řádků, počet malých čtverců nutných pro zakrytí obrázku na výšku
//po zaokrouhlení přičteme 1, protože ne vždy je rozměr objektu přesným násobkem rozměru
//malého čtverce
  radku = Math.round(imvyska/vyska)+1;
  //určení počtu sloupců
  sloupcu = Math.round(imsirka/sirka)+1;
  //zjistíme polohu objektu čtverce, použijeme jí následně pro dopočítání umístění nových objektů
  xpozice = this._parent.maska.m1._x;
  ypozice = this._parent.maska.m1._y;
  // nastavení počítadla objektů na úvodní hodnotu (jeden objekt už máme. proto 1)
  pocet = 1;
  //nastavení začátku generování, tedy číslo řádku a sloupce , nulu zde máme, protože se s ní lépe   
  //pracuje v další části
  radek = 0;
  sloupec = 0;
  //vytvoříme si zatím prázdná pole, která budou sloužit pro uložení souřadnic nově generovaných objektů
// číslo prvku pole je příslušné číslo nového objektu
  polex = new Array();
  poley = new Array();
//px, rd a sl jsou pomocná proměnné aktuálního kroku v cyklu „DO“
  px = 1;
  rd = radek;
  sl = sloupec;
  //celkový počet objektů
  celkem = radku*sloupcu;
// v tomto cyklu uložíme do obou polí souřadnice později generovaných čtverců
  do {
    polex[px] = sl*sirka+xpozice;
    poley[px] = rd*vyska+ypozice;
    px++;
    sl++;
//pokud jsme na posledním sloupci (-1 protože jsme začínali od 0), zvýšíme hodnotu proměnné //určující řádek o 1, skočili jsme tedy na další řádek
    if (sl>sloupcu-1) {
      sl = 0;
      rd++;
    }
//opakujeme dokud nevložíme souřadnice všech objektů
  } while (px<celkem+1);
//opakovani je konstanta která je použita v následující části. Prakticky se jedná o počet objektů,
//které se najednou odkryjí, jinak je to funkčně počet opakování cyklu „DO“ v následující části scriptu.
//Zde je uvedeno automatické nastavení počtu opakování tak, abychom celou změnu stihli do 1 vteřiny
// celkem/12  - počet snímků za vteřinu je 12, proto dělíme 12
  opakovani = Math.round(celkem/12);
//pokud chceme odkrýt velký objekt a máme tak velké množství malých čtverců, animace se trhá. Proto
//můžeme nastavit proměnnou „natvrdo“ a zamezit tak trhání.Například:  opakovani = 10;
}

Funkce pro maskování

Nyní jsme si nastavili základní parametry pro další funkce. Dále budeme chtít vytvořit maskovací efekt. K dispozici máme dvě pole, ve kterých jsou uloženy souřadnice všech malých čtverců, nutných k pokrytí celého obrázku. Takže jediné co potřebujeme, je vytvořit kopii příslušného čtverce, náhodně vybrat jednu položku z pole souřadnic x a stejnou z pole souřadnic y, přečíst jejich hodnoty a podle toho umístíme nově vytvořený objekt.

Nesmíme zapomenout přečtenou položku z obou polí vymazat. A protože nechceme aby se nám animace spouštěla ihned po načtení, dáme na začátek podmínku, která nám vše spustí.

Pokračujeme tedy v akcích pro náš ovládací MC:

onClipEvent (enterFrame) {
//pokud jsme dali příkaz ke startu maskování
  if (this._parent.startMask) {
    //zjistíme celkový počet objektů v poli (-1) je protože v poli má první prvek index 0, ale ten jsme
//nevložili
    delkapole = polex.length-1;
//pomocná proměnná pro počet opakování
    numx = 1;
//provedeme cyklus duplikování a umístění nových objektů
    do {
//pokud nejsme na konci (pole souřadnic je prázdné)
      if (delkapole != 0) {
        //uchováme číslo předchozího objektu kvůli umístění dalšího objektu
        predchozi = pocet;
        //zvýšíme počet o 1, pocet = aktuální číslo objektu
        pocet++;
        //sloupec zvýšíme o 1
        sloupec++;
//pokud jsme na konci řádku, skočíme na další
        if (sloupec>sloupcu+1) {
          radek++;
          sloupec = 0;
        }
        // duplikujeme instanci objektu m1, novou pojmenujeme podle pořadí,úroveň
//nastavíme také  podle pořadí
        this._parent.maska.m1.duplicateMovieClip("m"+pocet, pocet);
        //pro nově duplikovanou instanci objektu určíme polohu, jinak by  zůstala na
//původním objektu. Náhodně vygenerujeme číslo, které vynásobíme délkou pole
//sníženou o 1 abychom mohli po přičtení 1 dostat náhodné číslo
// v rozmezí 1-aktuální délka pole
        rNum = Math.random();
        rndNum = Math.round(rNum*delkapole+1);
//zjistíme a použijeme příslušné hodnoty souřadnic pro vytvořenou instanci
//objektu
        eval("this._parent.maska.m"+pocet)._x = polex[rndNum];
        eval("this._parent.maska.m"+pocet)._y = poley[rndNum];
//odstraníme z polí již použité záznamy
        polex.splice(rndNum, 1);
        poley.splice(rndNum, 1);
      }
      numx++;
// opakujeme dokud nejsme na předem stanoveném počtu opakování.
    } while (numx<opakovani);
  }
}

Schéma proměnných masky:

  sloupec; sl
radek;rd 1,1 2,1 3,1 4,1 5,1 6,1
1,2 2,2 3,2 4,2 5,2 6,2
1,3 2,3 3,3 4,3 5,3 6,3
... ... ... ... ... ...
... ... ... ... ... ...
... ... ... ... ... ...

Ovládání

Poté co jsme dokončili hlavní část skriptu, musíme ještě vytvořit tlačítko pro spuštění celé animace.

Nejdříve objektu „image“ přiřadíme funkci:

onClipEvent (load) {
  this._visible = false;
}

Pak umístíme jakékoliv tlačítko na plochu a přiřadíme mu následující akci:

on (release) {
//pomocí tohoto příkazu určíme že objekt „image“ bude maskován
//objektem „maska“
  this.image.setMask(this.maska);
// chceme aby byl objekt „image“ viditelný
  this.image._visible = true;
//spustíme animaci masky
  startMask = true;
}

Pokud budeme chtít vrátit animaci do původního stavu, stačí když umístíme na plochu další tlačítko a přiřadíme mu následující akci:

on (release) {
//zablokujeme znovuspuštění animace
  startMask = false;
// tento příkaz ruší funkci objektu „image“ jako masky
  this.image.setMask(null);
  gotoAndPlay(2);
}

Protože se v tomto tlačítku odkazujeme na snímek číslo 2, musíme jej vytvořit. Nejdříve ale přiřadíme prvnímu snímku funkci: stop();

Pak vložíme do snímku 2 prázdný klíčový snímek (klikneme pravým tlačítkem myši na snímek a zvolíme „Insert Blank Keyframe“) a máme hotovo.

Uspořádání celé scény může vypadat takto:

Zdrojový soubor ukázky ke stažení zde.