Definice cest k objektům a úrovním - Grafika.cz - vše o počítačové grafice

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



Webdesign

Definice cest k objektům a úrovním

Macromedia Flash tutorial

26. června 2001, 00.00 | Druhý díl miniseriálu o skriptování pro středně pokročilé ve Flashi, který ukazuje výhody i nevýhody objektově orientovaného přístup AS5.

Jedním z častých problémů, se kterým se "středně pokročilý" actionskriptař setká, je definování cest k objektům a úrovním, ve kterých existují.

V první řadě je třeba říci, že AS5 je objektově orientovaný a že právě verze 5, která se drží standardu ECMA-262, umožňuje velice pohodlný a jednoduchý/logický přístup k objektům a jejich vlastnostem.

Nejčastější chybou bývají záměny mezi _root a _level0. Jak tedy vypadá hierarchie úrovní? Flash při otevření nového dokumentu obsahuje jednu základní úroveň: _level0. Lze ale použít i další úrovně, označené _level1..... _levelXX. Tyto úrovně je třeba vytvořit, například načítáním externích .swf souborů:

loadMovieNum ("jmenoSouboru.swf", 1)
//tento skript nacte externi soubor do _level1

Každá jednotlivá úroveň má svůj jedinečný vlastní _root, tedy "hlavní časovou osu". Pokud mám tedy v _level1 proměnnou, definovanou jako _root.promenna, tato proměnná není z _level0 vidět cílením _root.promenna, ale jako _level1.promenna.

To bývá nejčastějším zdrojem nepříjemností, skriptař se domnívá, že když si všechny hlavní proměnné zapíše na _root, odevšud je uvidí touto cestou. Z jiných _level je však třeba používat cestu _level.variable nebo _level.MC.

Příklad: chci načíst externí .swf, obsahující proměnné, a tyto proměnné pak použít v _level0.

loadMovieNum ("data.swf", 3)

data.swf obsahuje definice proměnných:

_root.rychlostOtaceni = 5
_root.rotovat = true

Když chci "parametry", definované v uvedeném externím souboru, použít v _level0, nemohu použít následující syntaxi:

if (_root.rotovat) {
this._rotation += _root.rychlostOtaceni
}

Dojde ke dvěma věcem: jelikož AS nezná hodnotu _root.rotovat, nastaví jí na hodnotu "false" a i kdyby se skript dostal za logickou podmínku, vytvoří novou proměnnou _root. rychlostOtaceni a nastaví její hodnotu na 0.

Správné cílení je tedy:

if (_level3.rotovat) {
this._rotation += _level3.rychlostOtaceni
}

Dalším omylem bývá zaměňování mezi hloubkou (depth) a úrovní (_level). Depth se používá při metodách připojování MC z knihovny nebo duplikování:

attachMovie ("identifikacniJmeno", "jmenoSouboru", 5)

kde číslice 5 označuje depth. Připojený MC zůstává v _level, ve které proběhl příkaz pro připojení, ale ocitne se v "podvrstvě" s číslem 5. Takže proběhne-li v _level0:

this.duplicateMovieClip ("jmenoMC", 5)

je zduplikovaný MC normálně přístupný pomocí

_level0.jmenoMC

Depth se normálním objektovým cílením nedá ani cílit, ani měnit. Ke změně depth slouží speciální metoda swapDepths.

Pozor také na jeden zásadní rozdíl mezi depth a _level. Zatímco v _level může být obsažený libovolný počet objektů, v jedné konkrétní depth může být jen jeden objekt a přesunutí nebo zduplikování objektu do již obsazené depth má za následek smazání původního objektu.

Pozor také na další věc: depth je nadřazená layerům, ve kterých tvoříte strukturu animace. Udělejte si malý pokus:

  1. vytvořte si dva layery
  2. do spodního umístěte zelený obdélníček, udělejte z něj MC, dejte mu instance name třeba "zelObd"
  3. do horního layeru vložte třeba fialový obdélník, který překryje zelObd
  4. na zelObd jako handler vložte tento kód:
    onClipEvent (load) {
      if (!_root.duplicated) {
        this.duplicateMovieClip("zelObd2", 5)
        _root.duplicated = true
      }
    }
  5. otestujte

Vidíte? Zduplikovaný zelObd2 se ocitne NAD fialovým obdélníkem. Na to je při tvorbě struktury animace třeba pamatovat.

Zatímco _level slouží k základnímu členění projektu do jednotlivých "vrstev", depth se používají například pro z-stacking (taky mě ten název poprvé vyděsil :o))), ale je to jednoduchý způsob, jak dát objektům třetí souřadnici a dosáhnout například efektu, který je používaný např. ve windows: při kliknutí na lištu spodního okna se dané okno přesune zcela nahoru)(z-stacking se používá také v čistě flashovských 3D enginech).

Takže když si to celé shrneme:

Nejvýše v hierarchii stojí _level. Objekty, umístěné v _level, je třeba cílit pomocí _levelXX.objekt. Každá _level má svůj vlastní _root, který je přístupný jen uvnitř _level. Uvnitř kterékoliv _level mohou existovat hloubky - depth, které zůstávají uvnitř _level a které nelze klasickým objektovým cílením ovlivnit.

Depth jsou nadřazené layerům, které slouží ke tvorbě animace.

Dalším zdrojem nepříjemností bývají nejasnosti mezi absolutními a relativními cestami k objektům. Zkusím zde v krátkosti shrnout to, co je psáno v manuálu, a vysvětlit, kdy se která metoda cílení hodí.

Základním prvkem syntaxe přístupu k objektům je tečka (.). Tečka odděluje jednotlivé položky, tj. objekty a jejich vlastnosti. Takže zápis:

_root.matkaMC.dceraMC._xscale = 10

znamená "podívej se na _root, tam najdeš klip matkaMC, podívej se dovnitř něj, tam najdeš "podklip" dceraMC, vezmi jeho vlastnost _xscale a nastav jí na hodnotu 10". Toto je příklad absolutní cesty ke klipu a jeho vlastnosti, tedy "exaktní popis celé cesty".

Druhou možností je použít relativní cestu, která je založená na vlastnosti "_parent" a klíčovém slovu "this".

Vlastnost "_parent" specifikuje cestu k nadřízenému MC. Klíčové slovo "this" odkazuje na "tento" klip. Porovnejte následující dva skripty, zapsané uvnitř klipu "dceraMC":

_root.matkaMC.dceraMC.dceraDceryMC._x = 50
this.dceraDceryMC._x = 50

Oba skripty provedou to samé, vezmou objekt dceraDceryMC a nastaví jeho vlastnost "x-ová souřadnice" na hodnotu 50. Ten první skript používá absolutní cestu k objektu a vypisuje kompletní cestu k němu. Ten druhý používá relativní cestu a říká "v tomto klipu je podklip dceraDceryMC....".

Stejně tak můžete porovnat následující skripty, psané uvnitř klipu "dceraMC":

_root.matkaMC._alpha += 10
_parent._alpha += 10

Oba skripty opět udělají totéž, zvětší pro objekt matkaMC jeho vlastnost _aplha o 10. V prvním případě jde o absolutní cestu s jejím kompletním popisem, v druhém případě jde o relativní cestu, která říká "vezmi klip, který je rodičem tohoto a...".

Kdy používat relativní a absolutní cesty?
Absolutní cesty musíte použít, pokud píšete cestu zevnitř nějakého klipu k jinému klipu v případě, že tyto dva spolu nejsou v rodinném vztahu (jeden není součástí druhého).

Absolutní cestu doporučuji v případech, kdy ukládáte proměnné na základní časovou osu, aby byly přístupné odkudkoliv, nebo v případech, kdy je objektem jednoduchý klip, který je umístěný na hlavní časové ose.

Relativní cestu doporučuji používat vždy uvnitř složitějších klipů s více dcerami. Proč? Jednak si ušetříte čas při vypisování cesty, jednak při změně struktury klipu lze odkazování relativními cestami buď velice jednoduše změnit, nebo se měnit nemusí vůbec. Podívejte se na tento příklad:

  1. vytvořil jsem si klip, který má strukturu "_root.matkaMC.dceraMC.dceraDceryMC1"
    "_root.matkaMC.dceraMC.dceraDceryMC2"
    "_root.matkaMC.dceraMC.dceraDceryMC3"
  2. nyní mám v matkaMC nadefinovanou proměnnou "posuv"
  3. pomocí této proměnné řídím posuv klipů dceraDceryMC1, dceraDceryMC2 a dceraDceryMC3
  4. ... a teď zjistím, že potřebuji z toho všeho ještě udělat klip babickaMC, takže struktura bude následující:
    "_root.babickaMC.matkaMC.dceraMC.dceraDceryMC1"
    "_root.babickaMC.matkaMC.dceraMC.dceraDceryMC2"
    "_root.babickaMC.matkaMC.dceraMC.dceraDceryMC3"

Pokud jsem v klipu dceraDceryMC3 definoval cestu k proměnné "posuv" absolutní cestou takto:

this._x += _root.matkaMC.posuv
this._y += _root.matkaMC.posuv

musím všechny cesty přepsat na

this._x += _root.babickaMC.matkaMC.posuv
this._y += _root.babickaMC.matkaMC.posuv

a teď si představte, že to musíte provést třeba u dvaceti klipů...

Pokud jsem ovšem použil relativní cestu:

this._x += _parent._parent.posuv
this._y += _parent._parent.posuv

nemusím měnit vůbec nic, protože relativní cesta zůstala stejná.

K definování cest ke klipům rád ještě poznamenal následující:

  1. nepoužívejte starou "lomítkovou" (slash) syntaxi, ale důsledně pouze tečkovou. Lomítková syntaxe je nedoporučená a nebude nadále podporována.
  2. nepoužívejte tellTarget, který je také starý a v AS5 vám v podstatě jen přidá kus zdrojového kódu (tedy je zcela zbytečný)
  3. nepoužívejte zbytečně akce tam, kde můžete použít přímý přístup k vlastnostem objektu, použití akcí jen nafoukne zdrojový kód a údajně jsou přístupy k vlastnostem citelně rychlejší než akce: tedy NE:
    setProperty(_root.mujMC, _xscale, 50)
    ale:
    root.mujMC._xscale = 50
  4. nepoužívejte akce tam, kde můžete použít metody objektu, tedy místo:
    duplicateMovieClip(_root.mujMC, "lopata", 5)
    použijte:
    _root.duplicateMovieClip ("lopata", 5)

A na závěr ještě taková jedna perlička. V AS5 byla přidána jedna velice šikovná pomůcka, a to "syntaxe hranatých závorek". Ve své postatě nahrazuje funkci "eval", která umožňovala cílení objektů pomocí proměnných. Zatímco funkce "eval" byla nucená přečíst obsah závorek a z něj "rekonstruovat" cestu k objektu, syntaxe hranatých závorek umožňuje přímý přístup k objektu. Porovnejte následující dva kódy, které duplikují klip:

for (i=1;i<10;i++) {
_root.kytka.duplicateMovieClip ("petrklic" + i, i)
eval ("_root.petrklic" + i)._x = i + 5
eval ("_root.petrklic" + i)._y = i + 15
}

for (i=1;i<10;i++) {
_root.kytka.duplicateMovieClip ("petrklic" + i, i)
_root["petrklic" + i]._x = i + 5
_root["petrklic" + i]._y = i + 15
}

U složitějších syntaxí určitě oceníte jak úspornější zdrojový kód, tak rychlejší přístup k objektu.

Je však jeden případ, kdy syntaxe hranatých závorek nefunguje (asi jich je víc, ale já uvádím ten, na který jsem přišel a ze kterého mě málem trefilo). Nelze použít v preloaderu syntaxi:

nacist = ["_level" + promenna].getBytesTotal()

ale je třeba použít eval funkci:

nacist = eval("_level" + promenna).getBytesTotal()

Je to proto, že ve chvíli, kdy se vlastně vytváří nový _level, tak ještě neexistuje a syntaxe hranatých závorek není schopná objekt najít. Funkce eval však skutečně přečte obsah závorky, vyhodnotí jej a vrátí cestu k _level, ať již existuje nebo neexistuje, prostě změní string na použitelnou část cesty k objektu.

Možná, že se divíte, proč jsem už podruhé zmínil o rychlosti přístupu nebo vykompilovaného kódu. Ale ten, kdo už napsal složitější skript, ve kterém byly třeba použity v hojné míře Math objekty a k tomu přidal pár rozsáhlejších polí a operací s nimi, ten ví, že AS5 dokáže proměnit váš vysokovýkonný stroj na něco, co se chová jako 486sx/16. Takže čím více pozornosti věnujete optimalizaci kódu na rychlost, tím větší bude vaše radost z výsledku.

Tak, a to je pro dnešek vše. Pokusím se na příště najít zase nějaké vhodné téma, které by mohlo být pro středně pokročilé skriptaře zajímavé a které by jim pomohlo.

Tématické zařazení:

 » Rubriky  » Go verze  

 » Rubriky  » Webdesign  

 

 

 

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: