Strona wykorzystuje ciasteczka by usprawnić komfort z jej korzystania. Korzystając ze strony akceptujesz naszą Politykę Ciasteczek. X

Wysyłanie danych z preloader'a do wczytanego SWF'a [podstawowy]

Kontynuują temat interfejsów z poprzedniego wpisu, wspomniałem tam o scenariuszach w których ich wykorzystanie jest niezastąpione i jednym z takich przykładów jest komunikacja z plikiem SWF wczytanym do aplikacji, najczęściej spotykanym w preloaderach właśnie.
Zacznijmy od standardowego przykładu preloadera:
var loadLoader:Loader = new Loader();
loadLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
loadLoader.load(new URLRequest("MyAnimation.swf"));
		
function onLoaded(e:Event):void {
	addChild(loadLoader.content);
}
W tym wypadku plik MyAnimation.swf i jego zawartość zostanie wrzucony na scenę jak tylko preloader go w pełni załaduje. Jest to najprostsze rozwiązanie nie dające nam praktycznie żadnej kontroli nad tym kto i jak może wczytać ową animację, dlatego powiedzmy że chcielibyśmy aby ta odtwarzała się jedynie wtedy gdy preloader poda prawidłowe hasło. W tym celu należy przejść do pliku animacji i utworzyć dla niej nową klasę dokumentu:

W taki sposób aby animacja nie startowała automatycznie oraz aby nie dało się tego wymusić z zewnątrz:
public class MyAnimation extends MovieClip {
	public function MyAnimation() {
		super.gotoAndStop(1);
	}
public override function gotoAndStop(frame:Object,scene:String=null):void {
		return;
	}
	public override function gotoAndPlay(frame:Object,scene:String=null):void {
		return;
	}
	public override function play():void {
		return;
	}

}
Teraz nawet my nie będziemy w stanie odtworzyć danej animacji, dlatego czas przygotować obejście z którego tylko my będziemy mogli skorzystać, oczywiście wykorzystując do tege interfejs. Niech wygląda on tak:
public interface IMyInterface {
	function playUsingPassword(pass:String):void;
}
A zaimplementowany w naszej klasie MyAnimation:
public class MyAnimation extends MovieClip implements IMyInterface {
	public function MyAnimation() {
		super.gotoAndStop(1);
	}
	public function playUsingPassword(pass:String):void {
		if(pass == "MyPassword") super.play();
	}
public override function gotoAndStop(frame:Object,scene:String=null):void {
		return;
	}
	public override function gotoAndPlay(frame:Object,scene:String=null):void {
		return;
	}
	public override function play():void {
		return;
	}

}
(Nie zapomnij o implements!)
Napisanie super.play() spowoduje, że pominięta zostanie nasza implementacja a wykorzystany zostanie "prawdziwy" play() z klasy MovieClip. Pozostaje nam już tylko to prze testować w preloaderze:
var loadLoader:Loader = new Loader();
loadLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
loadLoader.load(new URLRequest("MyAnimation.swf"));
		
function onLoaded(e:Event):void {
	addChild(loadLoader.content);

	var main:IMyInterface = loadLoader.content as IMyInterface;
	if(main != null) main.playUsingPassword("MyPassword");
}
W efekcie dostając:
(Plik animacji znajduje się tutaj: MyAnimation.swf - każdy kto szuka wyzwania może spróbować wczytać ten plik samemu)
Źródła: PreloaderInterface.zip

Preloader'y we Flash'u [podstawowy]

"Preloading" to prosta idea która istnieje już od samego początku Internetu - a może nawet i wcześniej. Chodzi tutaj o uprzednie wczytywanie aplikacji lub multimediów z których będziemy korzystać do pamięci komputera, dzięki czemu będziemy mogli z nich korzystać bez przerw na doczytywanie brakujących danych. Nie inaczej jest w przypadku Flash'a, korzystając z preloader'a mamy pewność, że nasz widz będzie oglądał płynną animację, a nie pokaz slajdów.
O ile idea preloader'a jest prosta to z implementacją we Flash'u może być różnie. Generalnie, zależnie od tego czego potrzebujemy, wszystko sprowadza się do 3 rozwiązań:

1. Dla animacji.
Filmiki we Flash'u, które w minimalnym stopniu korzystają z jakiegokolwiek kodu ActionScript, są najłatwiejszym celem do implementacji Preloadera - zwykle wystarczy jedynie skopiować gotowe rozwiązanie, a tych w Internecie jest cała masa.
Jednym z najprostszych jest stworzenie w pierwszej klatce animacji MovieClip'a o nazwie instancji "preloader" (na zakładce właściwości) a potem wklejenie do tej samej klatki poniższego kodu:

import flash.events.Event;
import flash.events.ProgressEvent;

stop();
loaderInfo.addEventListener(ProgressEvent.PROGRESS,onProgress);
loaderInfo.addEventListener(Event.COMPLETE,onLoaded);

function onProgress(e:ProgressEvent):void {
	var percent:Number = loaderInfo.bytesLoaded/loaderInfo.bytesTotal;
	preloader.gotoAndStop( int(percent*preloader.totalFrames)+1);
}
function onLoaded(e:Event):void {
	loaderInfo.removeEventListener(ProgressEvent.PROGRESS,onProgress);
	loaderInfo.removeEventListener(Event.COMPLETE,onLoaded);
	//klatka do ktorej ma sie udac animacja po wczytaniu filmu
	gotoAndPlay(2);
}
MovieClip "preloader" zostanie przesunięty do klatki która odpowiada procentowemu postępowi procesu wczytywania filmiku, tak więc jeśli "preloader" ma 10 klatek animacji, a filmik jest już wczytany w 20%, wyświetlona zostanie 2 klatka (10*20% = 2).
Gotowy przykład: preloaderSimple.zip

2. Dla aplikacji w środowisku Flash Professional.
W tym wypadku już jest nieco trudniej. Tworząc projekty które wymagają dużej ilości ActionScript'u często nie myślimy o Preloaderze w pierwszej kolejności i szczerze mówiąc nie jest w tym nic strasznego, ale może przysporzyć komplikacji, szczególnie jeśli całą grafikę eksportujemy do pierwszej klatki animacji.
Skoro już wspomniałem o eksporcie do pierwszej klatki, zajmijmy się właśnie tym. Eksportując grafikę do ActionScript mamy do dyspozycji opcję "eksportuj w 1 klatce", która robi dokładnie to co opisuje - wsadza całą grafikę do pierwszej klatki - sęk w tym, że chcą później wstawić nasz preloader nie możemy zrobić tego wcześniej niż pierwsza klatka. W Flash Professional można sobie z tym poradzić na dwa sposoby:
- zmieniając docelową klatkę eksportu w ustawieniach ActionScript

- lub po prostu samemu ustawić grafikę na scenie w odpowiedniej klatce. Jeśli na przykład, mamy klasę która korzysta z eksportowanej grafiki w 3 klatce głównej linii czasu, nic nie stoi na przeszkodzie by wyłączyć "eksportowanie do 1 klatki" i samemu ją położyć w drugiej, nawet jeśli będzie po prostu poza ekranem.

3. Dla aplikacji w środowisku FlashDevelop.
… lub jakichkolwiek innych środowisk programistycznych wczytujących SWC. Chodzi tutaj o importowanie zewnętrznych bibliotek ActionScript, które oprócz samych klas zawierać mogą również grafikę lub inne elementy multimedialne. Owe elementy multimedialne zostaną wczytane jak tylko pojawi się odwołanie do klas z nimi powiązaniami, co w skrócie oznacza, że jakikolwiek import z SWC zostanie zablokowany, aż do czasu gdy grafika zostanie w pełni załadowana do pamięci. Z drugiej strony pominięcie jakichkolwiek importów spowoduje, że wybrane klasy zwyczajnie nie zostaną dodane do aplikacji w trakcie kompilowania. Tak więc, rodzi się pytanie: jak coś dodać do aplikacji bez korzystania z importu? Sposób jest jeden i odkryty został przez Keith Peters na: www.bit-101.com. W wielkim skrócie, ten genialny trick sprowadza się do pojedynczej linijki: [Frame(factoryClass="Preloader")] ("Preloader" to nazwa klasy która ma posłużyć za preloader), którą należy wstawić przed definicję klasy dokumentu (ale po wszystkich importach) - dla przykładu, nazwijmy ją "Main". Main zostanie wczytany, ale nie zainicjalizowany, ponieważ rolę główne linii czasu przejmie Preloader.
Teraz jeszcze zostaje kwestia stworzenia Main po zakończeniu procesu wczytywania do pamięci, ponieważ wciąż nie możemy korzystać z importu - my zaimportujemy Main, Main zaimportuje coś innego, co z kolei importuje jeszcze coś innego i prędzej czy później trafi się klasa która importuje z SWC, zatrzymując całą aplikacje na czas wczytywania grafiki. Na pomoc przychodzi funkcja flash.utils.getDefinitionByName, którą należy wywołać gdy aplikacje zostanie już wczytana w następujący sposób:

var mainClass:Class = getDefinitionByName("Main") as Class;
if(mainClass) {
	addChild(new mainClass() as DisplayObject); 
}
UWAGA! Funkcja getDefinitionByName() może od czasu do czasu zwrócić NULL, więc najlepiej do całości jeszcze podpiąć Event ENTER_FRAME, by próbować ponownie co pewien czas.
Jak zwykle do ściągnięcia jest przykładowy kod: preloader.zip
A owy przykład w akcji można zobaczyć tutaj: Preloader.html