Rozdział 22.
Funkcje i tablice
W tym rozdziale:
Typy danych w ActionScript
Używanie funkcji w filmach Flasha
Tworzenie tablic, czyli elegancka organizacja danych
Tworzenie dynamicznego menu
Wiesz już teraz, jak pracować z podstawowymi danymi, jakimi są zmienne, możemy więc przystąpić do omawiania funkcji i tablic. W tym rozdziale poznasz typy danych, podprogramy, tablice oraz zaawansowane użycie funkcji.
Czym są typy danych?
We Flashu 4 dane w filmie nie miały wyraźnie określonych typów. Typ danych to pewna grupa klasyfikacyjna, do której należą określone dane. Niektórych typów danych nie można skonwertować do innych typów, natomiast inne mogą zostać przekonwertowane. Aby zilustrować typy danych, prześledzimy działający kod z filmu Flasha 4:
Set Variable: "sciezka1" = "/ballAnim/ballPath"
Set Variable: "sciezka2" = "/ballAnim"
Begin Tell Target (sciezka1)
Stop
End Tell Target
Begin Tell Target (sciezka2)
Stop
End Tell Target
W tym skrypcie mamy dwie zmienne Flasha 4, sciezka1 oraz sciezka2. Wartościami tych zmiennych są ścieżki adresowe do dwóch różnych klonów klipów filmowych, ballAnim oraz ballPath. We Flashu 4 mogliśmy użyć tych ścieżek jako ścieżek docelowych w akcji Tell Target. We Flashu 5 ten kod nadal działa:
sciezka1 = "_root.ballAnim.ballPath";
sciezka2 = "_root.ballAnim";
tellTarget(sciezka1){
stop;
}
tellTarget(sciezka2){
stop;
}
Ponieważ akcja tellTarget jest kompatybilna z Flashem 4, może obsługiwać wartości tekstowe (na przykład "_root.ballAnim.ballPath") jako ścieżki adresowe we Flashu 5. Jeśli jednak chcesz używać nowych metod obiektu typu Movie Clip do sterowania docelowym obiektem, wtedy sciezka1 oraz sciezka2 nie będą działać:
sciezka1 = "_root.ballAnim.ballPath";
sciezka2 = "_root.ballAnim";
sciezka1.stop();
sciezka2.stop();
Dlaczego? Dlatego, że zmienne te są wartościami tekstowymi i Flash 5 nie ma informacji, że reprezentują one ścieżki rzeczywistych obiektów. Trzeba usunąć cudzysłowy i napisać:
sciezka1 = _root.ballAnim.ballPath;
sciezka2 = _root.ballAnim;
sciezka1.stop();
sciezka2.stop();
Flash 5 otrzyma wiadomość, że w zmiennych sciezka1 oraz sciezka2 znajdują się ścieżki odnoszące się do obiektów ballPath oraz ballAnim. W tym momencie zastanawiasz się, jak użyć starej instrukcji eval(), aby skorzystać ze ścieżek dynamicznych klipów filmowych. We Flashu 4 mogłeś napisać:
Set Variable: "i" = 1;
Set Variable" "sciezka1" = "/ballAnim/ball_" + i;
Begin Tell Target (sciezka1)
Stop
End Tell Target
We Flashu 5, jeśli chcesz, aby zmienna wskazywała obiekt typu Movie Clip, musisz przypisać jej obiekt (w sensie typu zmiennej). Jeśli chcesz to samo wykonać we Flashu 5 za pomocą metody, możesz zmienić powyższy skrypt na następujący:
i = 1;
sciezka1 = eval("_root.ballAnim.ball_" + i);
sciezka1.stop();
Flash 5 wyznaczy wartość wyrażenia "_ root.ballAnim.ball_" + i, którego wynikiem będzie "_ root.ballAnim.ball_1". W tym momencie Flash nie „wie” jeszcze, że ten ciąg znaków odnosi się do obiektu typu Movie Clip. Dopiero zastosowanie funkcji eval() powoduje zamianę wartości tekstowej na odnośnik obiektu, w tym wypadku klon klipu filmowego _root.ballAnim.ball_1.
Jednak funkcja eval() jest już trochę za stara, jak na Flasha 5. W poprzednim rozdziale omówiliśmy użycie operatora dostępu do elementów tablicy „[ ]”, aby ominąć funkcję eval(). W połączeniu ze zmiennymi operator ten może zostać użyty w celu odniesienia się do klipu filmowego:
i = 1;
_root.ballAnim["ball_" + i].stop();
Ten kod spowoduje połączenie ciągu znaków "ball_" z wartością zmiennej i oraz odniesienie się do obiektu ball_1 na listwie czasowej klonu klipu filmowego ballAnim.
Jak dotąd zobaczyliśmy dwa typy danych w działaniu: wartości tekstowe oraz obiekty. Jeśli wartość zmiennej znajduje się w cudzysłowach, na przykład "_root.ballAnim", wtedy jest traktowana jako wartość tekstowa. Jeśli wartość zmiennej jest obliczana lub bezpośrednio wskazuje jakiś obiekt, na przykład _root.ballAnim, wtedy Flash 5 traktuje ją jako obiekt. Flash 5 zawiera akcję typeof, która zwraca typ wyrażenia lub zmiennej podanej jako parametr. Omawiamy ją w dalszej części tej sekcji. Zanim się jej przyjrzymy, poznamy pięć typów danych z ActionScript Flasha 5.
Typ string — wartość tekstowa
Czytając tę książkę, wielokrotnie spotkałeś się z tym typem danych. Za każdym razem, kiedy coś jest zawarte w cudzysłowach, masz do czynienia z wartością tekstową. Jeśli w wyrażeniu występuje wartość tekstowa, to wynikiem całości także będzie wartość tekstowa. Wszystkie poniższe definicje dotyczą wartości tekstowych.
imie = "Franciszek";
nazwisko = "Nowak";
imiePlusNazwisko = imie + nazwisko;
koncowkaSciezki = "1";
Wskazówka! Wejściowe i dynamiczne pola tekstowe odpowiednio przyjmują i wyświetlają wartości tekstowe. Jeśli chcesz przeprowadzić obliczenia na wartościach pochodzących z pól tekstowych, upewnij się, że wcześniej skonwertujesz je na liczby. Typ danych liczbowych omawiamy za chwilę.
Jeśli zmienna jest wartością tekstową, możesz przetwarzać ją za pomocą metod obiektu String. Na przykład, jeśli chcesz zamienić wszystkie znaki zmiennej imie na wielkie litery (na przykład zamienić „Franciszek” na „FRANCISZEK”), możesz użyć poniższego skryptu:
imie = "Franciszek";
imie = imie.toUpperCase();
W tym wypadku metoda toUpperCase() powoduje w ciągu znaków zamianę wszystkich małych liter na wielkie. Możesz także w podobny sposób wyekstrahować pewne informacje z tekstu. Jeśli na przykład chcesz się dowiedzieć, gdzie w tekście pojawia się znak spacji i zwrócić ciąg znaków od spacji do końca tekstu, możesz użyć następującego skryptu:
wersja = "Netscape 4.71";
poczatek = wersja.indexOf(" ") + 1;
wersja = wersja.slice(poczatek, -1);
trace("Wersja = " + wersja);
W powyższym kodzie metoda indexOf() szuka pierwszego wystąpienia spacji (" ") w wartości tekstowej zmiennej wersja. Metoda indexOf(" ") zastosowana wobec zmiennej wersja zwróci indeks znaku spacji (indeks jest numerem znaku w ciągu, przy czym pierwszy znak ciągu ma indeks zerowy). W tym wypadku zwróci wartość 9. Następnie do wartości zwróconej przez tę metodę dodajemy 1, więc uzyskamy indeks 10, wskazujący w ciągu znaków w zmiennej wersja na znak „4”. Tak obliczony indeks przypisujemy pomocniczej zmiennej poczatek. Następnie za pomocą metody slice() pobieramy wszystkie znaki tekstu, począwszy od znaku wskazywanego przez poczatek (czyli znaku o indeksie 10). Parametr -1 powoduje, że ostatni zwracany znak pokrywa się z końcem tekstu. Zauważ, że po zakończeniu skryptu w zmiennej wersja znajdzie się tekst „4.71”.
Odsyłacz! Więcej informacji na temat metod obiektu typu String i przetwarzania wartości tekstowych znajdziesz na stronach 376-383 książki ActionScript Reference Guide.
Typ number — liczby
Tego typu daną jest każda liczba (lub wartość wyrażenia liczbowego). Wszelkie operacje matematyczne są przeprowadzane na wartościach liczbowych.
wiek = "27";
przyszleLata = "5";
wiek = wiek + przyszleLata;
trace("Za " + przyszleLata + " lat będę miał " + wiek + " lat(a).");
Po wpisaniu tego skryptu i uruchomieniu filmu w oknie Output zobaczysz następujący komunikat:
Za 5 lat będę miał 275 lat(a).
Niestety, nie takiego wyniku się spodziewaliśmy. Ponieważ zmienne wiek oraz przyszleLata zostały określone jako tekst (ze względu na cudzysłowy), Flash po prostu połączył obydwa teksty i dlatego otrzymaliśmy „275”. Aby wszystko działało tak, jakbyśmy tego chcieli, musimy odrobinę zmodyfikować skrypt:
wiek = 27;
przyszleLata = 5;
wiek = wiek + przyszleLata;
trace("Za " + przyszleLata + " lat będę miał " + wiek + " lat.");
Teraz wartości zmiennych wiek oraz przyszleLata są wartościami liczbowymi. Operacja matematyczna spowoduje dodanie obydwu liczb (a nie ich połączenie). W oknie Output pojawi się następujący komunikat:
Za 5 lat będę miał 32 lat(a).
Możesz używać funkcji Number() do zamiany tekstu na liczbę. W skrypcie z poprzedniej sekcji moglibyśmy przekształcić uzyskany tekst na liczbę, dopisując następującą linię:
wersja = Number(wersja);
Dzięki temu możemy wykorzystać tę zmienną do obliczeń matematycznych, ponieważ wartość „4.71” została zamieniona na wartość 4,71.
Typ boolean — wartość logiczna
Czasami przydaje się zmienna, która może przyjmować tylko dwie wartości: true (prawda) lub false (fałsz). Zmienne takie nazywane są zmiennymi logicznymi. Wartości logiczne przydają się przy podejmowaniu decyzji lub przełączaniu — na przykład światło może być załączone albo wyłączone. W poniższym kodzie zmienna ladowanie inicjalizowana jest wartością true, ale po zakończeniu ładowania przełączana jest na false:
onClipEvent(load){
_root.ladowanie = true;
trace("Typ zmiennej ladowanie = " + typeof(_root.ladowanie));
}
onClipEvent(enterFrame){
if(this._framesloaded >= this._totalFrames){
_root.ladowanie = false;
}
}
Ten skrypt możemy umieścić w klonie klipu filmowego (jako skrypt obiektu). Kiedy klon klipu filmowego pojawi się na scenie, rozpocznie się ładowanie, a w oknie Output pojawi się komunikat:
Typ zmiennej ladowanie = boolean
Typ movieclip — obiekt typu Movie Clip
Klony klipów filmowych na obrazie są danymi typu movieclip. Dzięki operatorowi typeof możesz łatwo sprawdzić, jakiego typu są zadeklarowane zmienne lub obiekty. Flash odróżnia obiekty klipów filmowych od innych obiektów, więc dużo łatwiej wykryć obiekt typu Movie Clip. Zadeklarowana poniżej zmienna będzie typu movieclip:
sciezka = _root.ballAnim;
Dopóki klon klipu filmowego o nazwie ballAnim istnieje na głównej listwie czasowej, typem zmiennej sciezka będzie movieclip. Jeśli ballAnim nie istnieje, typ zmiennej zostanie określony jako undefined (niezdefiniowany).
Typ object
Ten typ dotyczy każdego obiektu utworzonego w skrypcie. Na przykład w poprzednich rozdziałach używaliśmy obiektów typu Color oraz Sound, aby wzbogacić interaktywne prezentacje. Zdefiniowane poniżej zmienne będą typu object:
kolor = new Color(_root.ballAnim);
dzwiek = new Sound();
obiekt = new Object();
Jeśli użyjesz tego kodu w filmie Flasha, zobaczysz typ object w oknie Output po wykonaniu polecenia Debug/List Variables w środowisku testowym:
Level #0:
Variable _level0.$version = "MAC 5,0,30,0"
Variable _level0.kolor = [object #1] {}
Variable _level0.dzwiek = [object #2] {}
Variable _level0.obiekt = [object #3] {}
Movie Clip: Target="_level0.ballAnim"
Typ function
W skryptach Flasha 5 możesz definiować własne funkcje. W dalszej części tego rozdziału omawiamy podprogramy oraz akcję function. Typ function zostanie przypisany w skrypcie każdemu kodowi, który zaczyna się od akcji function, na przykład:
function idzDo(etykieta){
gotoAndStop(etykieta);
}
Typ undefinied
Przy sprawdzaniu typu nieistniejącej w skrypcie zmiennej lub obiektu, Flash 5 zwraca typ undefined.
Sprawdzanie typu zmiennej za pomocą operatora typeof
Teraz, kiedy znasz już typy danych występujących we Flashu 5, będziesz zapewne chciał poznać sposób sprawdzania typu określonej informacji. Za pomocą operatora typeof możesz poznać typ określonego elementu skryptu. Operator typeof przyjmuje tylko jeden parametr: nazwę elementu skryptu, który chcesz przetestować. Na przykład możesz wyświetlić typ zmiennej (bądź obiektu) w oknie Output:
imie = "Robert";
trace("imie jest typu " + typeof(imie));
Po przetestowaniu filmu w oknie Output pojawi się tekst:
imie jest typu string
Możesz używać operatora typeof w pętlach for...in, dzięki czemu akcje zagnieżdżone wewnątrz pętli będą wykonywane tylko dla określonego typu danych. Poniższy skrypt spowoduje przeniesienie wszystkich zmiennych tekstowych z głównej listwy czasowej do obiektu (lub klonu klipu filmowego) o nazwie globalVar (znak ¬ oznacza kontynuację tej samej linii kodu; nie umieszczaj go w rzeczywistym skrypcie):
for(varName in _root){
if(typeof(_root[varName]) == "string" && ¬
_root[varName] !=_root["$version"]){
_root.globalVar[varName] = _root[varName];
delete _root[varName];
}
}
Powyższy kod spowoduje przeniesienie wszystkich zmiennych (poza automatyczną zmienną $version) do klonu klipu filmowego (lub obiektu) o nazwie globalVar.
Na CD-ROM-ie! Przetestuj filmy typeof_simple.fla, typeof_advanced.fla oraz moveVariables.fla znajdujące się w katalogu ch22 na CD-ROM-ie.
Funkcje jako podprogramy
Podstawowym blokiem kodu wykorzystywanym przez każdy język programowania jest podprogram. To kod, który przeznaczasz do określonych zadań. Podprogram jest bardzo przydatny, kiedy chcesz tych samych akcji używać w kilku miejscach (na przykład klonach przycisków lub ujęciach). We Flashu podprogramy są nazywane funkcjami i powstają za pomocą akcji function.
Co robią funkcje?
Funkcja (lub podprogram) powoduje oznaczenie pewnego fragmentu kodu tak, aby wywoływać go po umieszczeniu w skrypcie tylko jego nazwy. Funkcja może powodować wykonanie kilku akcji i przekazywać parametry (nazywane argumentami) do tych akcji. Funkcje muszą mieć różne nazwy, abyś później wiedział, do jakiego zestawu akcji się odwołujesz. W zasadzie funkcje mogą posłużyć do definiowania własnych, dodatkowych „poleceń” języka ActionScript. We Flashu 4 używaliśmy akcji call, aby wykonać kod znajdujący się w innym ujęciu filmu. We Flashu 5 możemy utworzyć funkcję na określonej listwie czasowej i wykonać ją, wpisując ścieżkę adresową oraz nazwę funkcji.
Kiedy tworzyć funkcję?
Osobom dopiero zaczynającym pisać skrypty duży problem sprawia to, kiedy należy tworzyć funkcje w filmie Flasha. Poniższe wskazówki pozwolą Ci zorientować się, kiedy powinieneś utworzyć funkcję.
Jeśli spostrzeżesz, że tego samego fragmentu kodu używasz w skryptach kilku klonów przycisków, klipów filmowych lub ujęć, wtedy powinieneś rozważyć umieszczenie powtarzających się akcji w funkcji. Zwykle nie powinieneś gromadzić całego kodu w pojedynczym klonie przycisku lub ujęciu.
Gdy musisz przeprowadzać te same operacje w różnych częściach filmu, na przykład ukrywać określony klon klipu filmowego na scenie, wtedy powinieneś rozważyć jednorazowe utworzenie funkcji, która później zajmie się wszystkim za Ciebie.
Jeśli do określenia jakiejś wartości używasz skomplikowanych operacji matematycznych, powinieneś je umieścić w funkcji.
Jak zdefiniować funkcję?
Gdy dodajesz funkcję do ujęcia głównej listwy czasowej lub listwy czasowej klipu filmowego, mówimy o definiowaniu funkcji. Funkcję, podobnie jak inne obiekty, możesz wywołać za pomocą ścieżki adresowej. Każda funkcja po swojej nazwie musi posiadać dwa nawiasy (otwierający i zamykający), jednak argumenty (parametry przekazywane do funkcji) znajdujące się wewnątrz nawiasów nie są wymagane.
Wskazówka! Funkcje zwykle definiuje się na samym początku filmu (lub wewnątrz klonu klipu filmowego ładowanego w pierwszym ujęciu filmu). Powinieneś umieszczać funkcje tylko w ujęciach listew czasowych — możesz jednak wywołać je z każdego detektora zdarzeń we Flashu.
Przypuśćmy, że chcesz utworzyć funkcję, która będzie zawierała tylko jedną akcję — gotoAndStop(). Jej nazwa będzie krótsza niż gotoAndStop(), dlatego szybciej ją wpiszesz i użyjesz w skrypcie. Umieścimy ją w pierwszym ujęciu na głównej listwie czasowej.
function gts(){
_root.gotoAndStop("start");
}
Ta funkcja po wywołaniu spowoduje przejście wskaźnika czasu do ujęcia o etykiecie start. Moglibyśmy ulepszyć naszą funkcję gts(), dodając argument o nazwie etykietaUjecia:
function gts(etykietaUjecia){
_root.gotoAndStop(etykietaUjecia);
}
W tej wersji funkcji gts(), zamiast na stałe określonej etykiety ujęcia (na przykład start) w akcji gotoAndstop(), określiliśmy argument o nazwie etykietaUjecia. Podobnie jak przy zmiennych, nazwa argumentu zależy tylko od Ciebie — nazwa etykietaUjecia nie ma tutaj żadnego znaczenia (w sensie treści nazwy). Flash po przekazaniu argumentu do funkcji gts() wstawi przekazany argument w miejsce nazwy etykietaUjecia w akcjach. Argument przechowuje informację, która została przekazana do funkcji, z tego też powodu możemy określić inną wartość etykietaUjecia podczas każdego wywołania funkcji gts().
Ostrzeżenie! Uważaj, abyś przypadkiem nie nazwał funkcji (lub argumentu) tak samo, jak jakiegoś słowa z języka ActionScript. Jeśli masz wątpliwości, powinieneś wybrać wyraz, który nie jest podobny do składni języka JavaScript (pamiętaj także o dodatkowych określeniach języka ActionScript). W wielu przykładach z ćwiczeń lub książek możesz zauważyć, że programiści często dodają prefiks do nazw, aby ustrzec się przed problemami związanymi z konfliktami nazw.
Jak wywołać funkcję?
Po zdefiniowaniu funkcji w ujęciu listwy czasowej możesz w innym miejscu dodać kod, który spowoduje jej wykonanie. Podstawowa składnia instrukcji powodującej wykonanie funkcji jest następująca:
[ścieżka funkcji].nazwaFunkcji([argumenty]);
W poprzedniej sekcji zdefiniowaliśmy funkcję o nazwie gts() na głównej listwie czasowej. Jeśli do filmu dodamy klon przycisku, będziemy mogli wywołać funkcję wewnątrz klonu, używając poniższego kodu:
on(release){
_root.gts("start");
}
Po kliknięciu przycisku zostanie wykonana funkcja gts() z argumentem "start" znajdująca się na listwie czasowej _root (główna listwa czasowa). W funkcji gts() określiliśmy argument etykietaUjecia jako argument akcji gotoAndStop(). Z tego też powodu główna listwa czasowa przejdzie do ujęcia o etykiecie start i zatrzyma się.
W dalszej części tego rozdziału użyjemy funkcji do tworzenia dynamicznego menu, które może być wielokrotnie używane w różnych sytuacjach.
Ostrzeżenie! Funkcja nie będzie wykonana, jeśli nie została wcześniej zdefiniowana i rozpoznana przez odtwarzacz filmów Flasha. Ujęcie zawierające deklarację funkcji musi być odtworzone, zanim funkcja stanie się dostępna. Na przykład, jeśli zdefiniowałeś funkcję w 10. ujęciu klonu klipu filmowego zatrzymywanego w ujęciu pierwszym (przejście do 10. ujęcia nigdy nie następuje), Flash nigdy nie „dowie się” o tym, że taka funkcja została gdzieś zdefiniowana.
Szare tło!
Ćwiczenie eksperta
ActionScript w grach
Autor: Mark Burrs
Jedną z najważniejszych zalet Flasha okazały się ogromne możliwości dynamiczne, jakie wniósł do sieci WWW. Flash 4 pozwolił użytkownikom aktywnie uczestniczyć w wydarzeniach. Nie dziwi więc fakt, że owe zdolności Flasha spowodowały dynamiczny rozwój gier na stronach internetowych lub przysyłanych pocztą elektroniczną jako projektory Flasha. Teraz, kiedy Flash 5 w zasadzie dwukrotnie zwiększył liczbę dostępnych narzędzi, myślę, że wcześniejsze wyczyny były dopiero początkiem.
To ćwiczenie pomoże Ci postawić pierwsze kroki we flashowych grach. Przejdziesz przez kolejne etapy tworzenia gry dzięki studium, po którym nastąpi techniczne wyjaśnienie tego, jak Flash 5 pomaga rozwiązać niektóre zadania omówione w studium.
Źródłowy plik .FLA oraz inne elementy potrzebne w tym ćwiczeniu znajdziesz w katalogu ch22\mark_burrs na CD-ROM-ie.
Klucze do sukcesu
Zanim załączysz Flasha, musisz zastanowić się nad kilkoma sprawami. Użyj poniższej procedury, aby lepiej zaplanować pracę nad projektem. Na tym etapie bardzo przydaje się tablica, szczególnie gdy nad projektem pracuje parę osób.
Napisz dokładnie, co będzie robił i jak działał produkt, który zamierzasz utworzyć.
Określ podstawowe elementy.
Sporządź listę właściwości tych elementów.
Sporządź listę metod (akcji), które poszczególne elementy powinny umieć wykonać.
Studium: hokej
Poniższe kroki przedstawiają proces tworzenia gry (czasem nazywanej także cymbergaj) pokazanej na rysunku.
Rysunek: Oto szata graficzna gry
Krok 1. Napisz dokładnie, co będzie robił i jak działał produkt, który zamierzasz tworzyć. Powinieneś także dołączyć listę życzeń. Możesz na razie nie wiedzieć, czy i jak zrealizować pewne elementy, ale tymi problemami zajmiesz się później. Jeśli jednak nie zrobisz listy, w zasadzie nie ruszysz dalej. Chodzi o to, aby zacząć określać to, co się chce zrobić, by umysł zaczął zastanawiać, jak wszystko wykonać. Oto parę przykładów:
tryb gry: komputer kontra gracz,
istnienie (cały czas na scenie) tablicy wyników oraz upływającego czasu,
tryb demonstracyjny,
na początku — wybór strony dla gracza (lewa lub prawa),
na początku — wybór stopnia trudności,
na początku (lub nawet w trakcie gry) — wybór szybkości krążka (szybko, powoli lub nawet suwak pozwalający na określenie wartości pośrednich),
na początku — określenie warunku wygranej: do x bramek lub wynik po x minutach gry,
na początku — wybór koloru „rakietki” gracza,
dźwięk odbicia,
gracz oraz komputer będą zdobywali punkty po trafieniu krążka do bramki przeciwnika. (Głupio się przyznać, ale w czasie pisania tego tekstu w moim prototypie działało tylko to).
Krok 2. Teraz, kiedy wiesz już, co chcesz zrobić, czas określić podstawowe elementy gry. Zacznij po prostu od opisowej listy wszystkich podstawowych elementów, które przyjdą Ci na myśl po określeniu zasad działania gry. Pamiętaj, że tutaj liczą się pomysły:
ładne „lodowisko,”
rakietka gracza,
rakietka komputera,
bramka gracza,
bramka komputera,
krążek,
tablica wyników,
ekran powitalny,
dźwięk odbicia,
ekran ustawień dotyczących gry.
Krok 3. Czas przejść do szczegółów, określając właściwości każdego elementu. (Pamiętaj, że wszystkich kroków nie musisz wykonać za jednym razem ani w tym samym dniu. W zasadzie osiągniesz lepsze wyniki, gdy każdy krok będziesz wykonywał po pewnej przerwie. Możesz też przeczytać wszystko jeszcze raz po jakimś czasie, aby ustalić pewne szczegóły. Zdziwisz się, jakie pomysły czasem przychodzą do głowy w czasie odpoczynku!). Oto one:
ładne „lodowisko,”
szerokość,
wysokość,
tarcie — jak bardzo w czasie ruchu będzie spowalniany krążek,
rakietka — gracza lub komputera,
xLocation (położenie na osi X),
yLocation (położenie na osi Y),
xSpeed (prędkość na osi X),
ySpeed (prędkość na osi X),
maxSpeed (maksymalna prędkość) — jest to wartość ograniczająca xSpeed oraz ySpeed,
color (kolor),
size (wielkość),
type (rodzaj) — gracz lub komputer,
bramka — gracza lub komputera,
x (położenie na osi X),
y (położenie na osi Y),
owner (właściciel) — gracz lub komputer,
width (na planszy wysokość, ale w rzeczywistości szerokość),
krążek,
xLocation (położenie na osi X),
yLocation (położenie na osi Y),
xSpeed (prędkość na osi X),
ySpeed (prędkość na osi Y),
color (kolor),
size (wielkość),
maxSpeed (maksymalna prędkość) — jest to wartość ograniczająca xSpeed oraz ySpeed,
tablica wyników,
playerScore (wynik gracza),
computerScore (wynik komputera),
timeRemaining (upływający czas),
ekran powitalny,
status (stan) — widoczny lub niewidoczny,
dźwięk odbicia,
panning (panorama dźwięku) — powinna odpowiadać miejscu odbicia w poziomie,
ekran ustawień dotyczących gry,
playMode (tryb gry) — „gracz kontra komputer” lub „demonstracyjny,”
playerSide (po której stronie gra gracz) — prawa lub lewa,
playerColor (kolor rakietki gracza) — czerwony, niebieski itd,
difficultyLevel (poziom trudności) — parametr: 0 - 10,
friction (tarcie) — parametr: 0 - 10,
gameType (rodzaj gry) — na czas lub do określonego wyniku.
Zapewne zauważyłeś, że w tym kroku przyjąłem już bardziej techniczne podejście. Jednak Ty nie musisz pisać aż tak technicznym językiem. Jeśli nie jesteś skryptowym guru w zespole, ale wizjonerem, możesz opisać wszystko dokładnie w normalnym języku, aby inni członkowie zespołu zrozumieli, o co chodzi.
Krok 4. W tym kroku wymienimy metody (lub akcje), które poszczególne komponenty powinny wykonać. Te metody także możesz opisać bardziej szczegółowo. Głównym zadaniem tych działań jest to, byś przed rozpoczęciem pracy we Flashu wiedział, co dokładnie chcesz zrobić i jak wszystkie części będą ze sobą współpracowały:
ładne „lodowisko” — brak,
rakietka — gracz i komputer,
obliczanie xSpeed oraz ySpeed — wartości te zależą od tego, jak szybko gracz porusza rakietką i w jakim kierunku,
sprawdzanie, czy nastąpiło zderzenie z krążkiem,
pozostanie w obrębie „lodowiska,”
rakietka gracza musi być przeciągalna,
rakietka komputera musi posiadać pewnego rodzaju sztuczną inteligencję,
bramka — gracza i komputer — brak,
krążek,
ruch w obrębie „lodowiska” z realistycznymi odbiciami,
odbicie od rakietki, gdy rakietka wykryje kolizję,
sprawdzanie położenia bramki i aktualizacja wyników na tablicy w przypadku zdobycia punktu,
tablica wyników,
wyświetlanie wyniku gracza oraz komputera,
licznik liczący wstecz,
ekran powitalny — inicjalizacja gry,
dźwięk odbicia,
odtworzenie,
ekran ustawień dotyczących gry — brak metod, jest to ekran gromadzący --> informacje[Author:RJ] .
Teraz, kiedy utworzyliśmy już zarys programistycznych problemów, z którymi się spotkamy, tworząc film, możemy zacząć myśleć nad ich rozwiązywaniem. Najpierw zajmiemy się animacją krążka.
Animacja krążka
Zadanie: ruch krążka w obrębie lodowiska i reagowanie na uderzenia rakietek.
Do sterowania ruchem krążka utworzę klip filmowy tylko z akcjami i nazwę go „sterownikiem krążka”. Będzie to klip filmowy niezawierający żadnych elementów graficznych, tylko kod ActionScript. Zostanie on wstawiony do klipu krążka, więc do rzeczywistego krążka będzie się odwoływał za pomocą ścieżki _parent. Użycie słowa kluczowego _parent pozwala odnieść się do klipu filmowego, w którym znajduje się aktualny klip. Realizując wszelkie animacje, za każdym razem będę stosował te same zasady.
Pobranie aktualnej wartości:
curX = _parent._x;
Zmiana aktualnej wartości przez dodanie prędkości oraz tarcia:
newX = curX + Xspeed - friction;
Sprawdzanie obszaru — krążek nie powinien wychodzić poza krawędzie wyznaczonego obszaru lodowiska. Możemy to sprawdzić za pomocą kilku warunków if, które porównują współrzędne krążka ze współrzędnymi krawędzi. Gdy krążek znajdzie się poza krawędzią, redukujemy odpowiednią współrzędną krążka, umieszczając go z powrotem na krawędzi.
if(newX+(_root.puck1._width*0.5) >= _root.dir_scene:bottom){
newX = _root.dir_scene:bottom - (_root.puck1._width * .5);
}
Ustawianie właściwości:
parent._x = newX;
Możliwe jest umieszczenie wszystkich akcji w jednym ujęciu, ale kod może stać się nieczytelny. Aby temu zapobiec, zwykle używam jednego ujęcia z akcjami call i innych ujęć ze skryptami, do których odnoszę się za pomocą tych akcji. Akcja call powoduje wykonanie skryptu znajdującego się w określonym ujęciu. Taki sam efekt osiągnąłbyś, używając funkcji, ale ja wolę tę metodę, ponieważ wszystkie części skryptu znajdują się wówczas w jednym miejscu. Funkcji używam w innych sytuacjach. W ujęciu loop znajduje się następujący kod (na następnym rysunku możesz zobaczyć, że wszystkie „wywoływane” ujęcia znajdują się na tej samej listwie czasowej):
call ("getCurrent");
call ("modify");
call ("setFlags");
call ("setProperties");
Używając akcji call, możesz podzielić większy skrypt na kilka mniejszych części, którymi łatwiej operować.
Często obserwowałem, jak inni tworzą podobne rzeczy. Stwierdziłem, że większość wpada w złość, gdy muszą coś zmienić lub poprawić. (Wiesz już, dlaczego tak dużo planuję na początku pracy). Używając mojej techniki dzielenia skryptu na części, po zauważeniu problemu z obliczaniem położenia możesz skupić się na ujęciu modify. Jeśli będziesz chciał zmienić granice odbić krążka, przyjrzysz się ujęciu setFlags.
Ruch rakietki
Zadanie: zamiana ruchu rakietki na wartości, które będą wpływały na kierunek i siłę odbicia krążka po kolizji z rakietką.
Jeśli rakietka poruszała się szybko, gdy uderzyła w krążek, to krążek powinien poruszać się po zderzeniu szybciej. I na odwrót, gdy rakietka tylko musnęła krążek, powinien się poruszyć tylko odrobinkę. Naszym zadaniem jest obliczenie, jak szybko i w jakim kierunku porusza się rakietka, gdy następuje zderzenie z krążkiem. W tym celu musimy znać położenie rakietki w chwili poprzedzającej kolizję:
counter = counter + 1;
if (counter==2){
oldPad1X = curPad1X;
oldPad1Y = curPad1Y;
counter = 0;
}
curPad1X = pad1._x;
curPad1Y = pad1._y;
Kod ten znajdzie się w klipie z akcjami, który nazywam „sterownikiem rakietki”. Śledzi on ruchy rakietek i wykrywa kolizje z krążkiem. Różnica między oldPad1X i curPad1X jest równa odległości na osi X, jaką rakietka przebyła w ciągu dwóch klatek. Podobnie mierzy się prędkość w kilometrach na godzinę, ale w tym wypadku jednostki są inne — piksele na dwie klatki. (Jeśli chcesz wydłużyć okres próbkowania, zwiększ przedział klatek branych pod uwagę). W chwili wykrycia kolizji wartości te są zamieniane na xPaddleSpeed i yPaddleSpeed i przesyłane do klipu sterującego krążkiem. Klip znajdujący się w klipie krążka na podstawie tych wartości może odpowiednio zareagować na uderzenie.
Sztuczna inteligencja komputerowego gracza
Zadanie: stworzenie „myślącego” komputerowego przeciwnika, którego poziom gry będzie ustalany przez gracza.
Interesującym zagadnieniem jest wykreowanie gry, w której komputerowy przeciwnik posiada pewnego rodzaju sztuczną inteligencję (AI — Artificial Intelligence). Tworząc sztuczną inteligencję, należy zastanowić się nad poziomem jej skomplikowania. W tym przykładzie użyłem bardzo prostego modelu sztucznej inteligencji, który opierać się będzie na trzech zmiennych:
skill: określa precyzję śledzenia położenia krążka,
aggr: określa agresję automatycznego gracza,
maxSpeed: określa szybkość działań automatycznego gracza.
Dodatkowe opcje mogą dotyczyć progów, przy których będzie następowała zmiana zachowania automatycznego gracza. Jeśli komputer przegrywa o pięć punktów, zwiększa się jego agresja, zaś jeśli przegrywa, a do końca gry pozostało 10 sekund, jego agresja sięga zenitu, ale zmniejsza się dokładność uderzeń. Tego typu urozmaicenia zależą tylko od Twojej wyobraźni (oraz budżetu projektu).
Klip z akcjami realizującymi sztuczną inteligencję działa podobnie do klipu sterującego ruchem krążka. Główne podobieństwo polega na tym, że korzysta on z kilku parametrów gry — w pierwszym ujęciu są określone trzy profile gry komputera, z czego jeden z nich wybieramy na drodze losowania.
playType = random(3);
// Szybki, agresywny gracz
if (playType == 0) {
skill = 1;
aggr = 5;
maxSpeed = 60;
}
// Średni gracz
if (playType == 1) {
skill = 20;
aggr = 7;
maxSpeed = 30;
}
// Słaby gracz - mam nadzieję, że będzie potrafił uderzyć w krążek
if (playType == 2) {
skill = 20;
aggr = 20;
maxSpeed = 20;
}
W tym przypadku im niższa wartość, tym większe zdolności w danym kierunku. Oczywiście mógłbym każdy z trzech parametrów losować, ale chciałem ustalić pewne style gry, aby łatwo sprawdzić, czy działają.
Ujęcie oznaczone etykietą modify sprawdza położenie krążka. Symuluje przy tym pewną niedokładność, biorąc pod uwagę umiejętności określone przez parametr skill. Następnie, bazując na tym położeniu, obliczane jest nowe umiejscowienie rakietki z uwzględnieniem parametru agresywności (aggr).
W ujęciu oznaczonym etykietą setFlags znajduje się kod sprawdzający, czy rakietka nadal znajduje się w obrębie lodowiska.
Tryb demonstracyjny
Zadanie: stworzenie trybu demonstracyjnego, w którym obydwaj przeciwnicy sterowani są przez komputer.
Po utworzeniu klipu ze sztuczną inteligencją można bez problemów dodać tryb demonstracyjny. Oto odpowiedzialny za to fragment kodu znajdujący się w funkcji initGame:
_root.attachMovie("paddle", "paddle1", 201);
c = new Color(_root.paddle1);
c.setRGB(parseInt("666699",16));
_root.paddle.side="right";
_root.paddle1.control="computer";
_root.attachMovie("paddle", "paddle2", 1);
_root.paddle2.side="left";
if (playMode == "demo"){
_root.paddle2.control="computer";
} else {
_root.paddle2.control="human";
}
Zauważ, że warunek if powoduje ustawienie _root.paddle2.control albo na wartości tekstowej human, albo na computer. Wszystko będzie działało, ponieważ klip filmowy rakietki w pierwszym ujęciu zawiera skrypt:
if (control eq "computer"){
this.attachMovie("ai", "ai", 210);
}
Dołączany klip filmowy zawiera sztuczną inteligencję. Oznacza to, że każda paletka będzie posiadała własny klip filmowy ze sztuczną inteligencją. To wystarczy, by uzyskać wersję demonstracyjną gry. (Zauważ także, że w powyższym kodzie pokazano też, jak zmieniać kolor klipu filmowego).
Wykrywanie kolizji rakietki z krążkiem
Zadanie: wykrywanie, czy rakietka i krążek zderzyły się ze sobą.
Istnieje wiele sposobów na wykrywanie zderzeń. We Flashu 5 pojawiła się nowa metoda klipu filmowego o nazwie hitTest.
Uwaga autora. Dokładniejsze omówienie zastosowania nowej metody hitTest znajdziesz w ćwiczeniu Doriana Nisinsona „Użycie metody hitTest dla wielu obiektów” z rozdziału 23., „Klipy filmowe jako obiekty złożone”.
Składnia metody hitTest jest następująca:
klipFilmowy.hitTest(obiekt docelowy);
Niestety moje obiekty (krążki!) są okrągłe, więc metoda hitTest nie spisze się tutaj najlepiej. Sprawdza ona, czy ramki ograniczające klipy filmowe nachodzą na siebie. Jest to pokazane na następnym rysunku.
Wykrywanie kolizji przy użyciu metody hitTest stwierdzi, że nastąpiło zderzenie, ponieważ ramki ograniczające nachodzą na siebie. Wykrywanie zderzeń na podstawie twierdzenia Pitagorasa nie uzna tego za kolizję, ponieważ koła nie nałożyły się na siebie.
Użyłem twierdzenia Pitagorasa do obliczenia odległości między środkami obydwu obiektów, a następnie otrzymany wynik porównałem z sumą promieni obydwu krążków. Twierdzenie Pitagorasa stwierdza, że a2 + b2 = c2. (Zobacz następny rysunek). Chcemy obliczyć c, które jest odległością pomiędzy środkami obydwu obiektów.
Twierdzenia Pitagorasa można użyć do obliczenia odległości między obiektami.
a = różnica pomiędzy paddle._x i puck._x
b = różnica pomiędzy paddle._y i puck._y
c = Math.sqrt((a*a)+(b*b))
Umieściłem wszystko w funkcji, którą można wywołać w każdej chwili w każdym miejscu:
function checkCollision (source, target) {
a = target._y - source._y;
b = target._x - source._x;
c = Math.sqrt((a*a)+(b*b));
dist = (target._width *.5) + (source._width*.5);
if (c<=dist) {
return true;
} else {
return false;
}
}
Gdy w czasie wykonywania funkcji Flash natknie się na słowo kluczowe return, zwraca wartość występującą po instrukcji return i przerywa wykonywanie funkcji. Aby wywołać funkcję, muszę się odnieść do klipu filmowego zawierającego definicję funkcji, a w nawiasach przekazać wymagane argumenty:
if(_root.functions.checkCollision(_root.paddle1, _root.puck1){
// Nastąpiło zderzenie
} else {
// Nie nastąpiło zderzenie
}
Dźwięk odbicia
Zadanie: sterować położeniem dźwięku na panoramie stereo, tak aby pokrył się z miejscem odbicia krążka na obrazie (w poziomie).
Jedną z nowości we Flashu 5 jest możliwość sterowania dźwiękiem za pomocą skryptów. Umożliwia to obiekt typu Sound, który pozwala między innymi na zmianę panoramy dźwięku. W naszym przypadku panorama będzie się zmieniała w zależności od tego, gdzie nastąpiło odbicie. Poniższa funkcja jest wywoływana, gdy tylko wystąpi odbicie.
Uwaga autora. Inne przykłady użycia nowego obiektu typu Sound znajdziesz w ćwiczeniu Jay'a Vaniana „Sterowanie dźwiękiem” z rozdziału 19., „Sterowanie klipami filmowymi”.
function playSound(name,start,duration,vol,x){
max=_root.dir_scene.right;
inc=max/200;
// Linia poniżej powoduje dostosowanie do skali od -100 do 100
pan = (x/inc)-100;
s = new Sound();
s.attachSound(name);
s.setPan(pan);
s.setVolume(vol);
s.start(start,duration);
}
Oto wyjaśnienie przekazywanych zmiennych:
name — nazwa dźwięku określona we właściwościach łączenia,
start — przesunięcie od początku dźwięku,
duration — jak długo należy odtwarzać dźwięk,
vol — głośność (w zakresie od 0 do 100),
x — poziome położenie wystąpienia odbicia, które później zostaje dostosowane do skali odpowiedniej dla panoramowania (od -100 do 100).
Aby panoramowanie działało prawidłowo, wystarczy dla argumentu x przekazać wartość właściwości _root.puck1._x.
Dobrze jest umieścić wszystkie funkcje w jednym miejscu. Oto przykład klipu filmowego zawierającego funkcje użyte w tej grze.
Klipu filmowego można użyć jako „pojemnika” na funkcje.
Załączamy Flasha
Gdy leży już przed Tobą plan tworzenia gry, określiłeś wszystkie podstawowe elementy i rozwiązałeś parę podstawowych problemów, możesz załączyć Flasha i wprowadzić swój projekt w życie.
Przypis do szarego tła!
Mark Burrs powiedział, że znalazł Flasha, kiedy „szukał programu, w którym mógłby robić diagramy dla sieci WWW i który jednocześnie współpracowałby z Lotus Notes”. Mark pochodzi z Stillwater w Minnesocie. Jest założycielem i prezesem CyBurrs Solutions Inc. w WhiteBear Like w Minnesocie i nauczycielem Lynda.com's Ojai Digital Arts Center w Ojai w Kalifornii. Jego najlepsze prace można podziwiać na witrynach www.cyburrs.com, www.swfstudio.com oraz www.swfstudio.com/demo-lessons, która „jest bardzo intensywnym systemem szkoleniowym opartym na Flashu i używającym Lotus Notes jako narzędzia do organizacji danych”. Kiedy kończył szkołę średnią największym hitem był film „Total Eclipse of the Heart”. Co Mark najbardziej lubi robić? „Bawić się z dziećmi i spędzać czas z żoną. Programowanie w Flashu i Lotus Notes jest wspaniałe, ale nie mógłbym tego umieścić na pierwszy miejscu”.
Koniec szarego tła!
Operowanie danymi powiązanymi ze sobą — obiekt Array
Czasem musimy pracować z dużą liczbą zmiennych, które są ze sobą w pewien sposób powiązane. Na przykład mogą to być zmienne o nazwach imie_1, imie_2, imie_3, imie_4, itd. Tworzą one coś na kształt listy podobnych informacji, na przykład:
imie_1 = "Jan";
imie_2 = "Maria";
imie_3 = "Patrycja";
imie_4 = "Franciszek";
W językach programowania tablica jest listą wartości, które można odczytać, podając ich położenie. Tablice opracowuje się za pomocą konstruktora obiektu Array.
odwiedzajacy = new Array();
Powyższy kod tworzy tylko miejsce, w którym przechowujesz elementy tablicy. Możesz utworzyć tablicę, która już na początku zawiera pewne elementy, na przykład:
odwiedzajacy = new Array("Jan","Maria","Patrycja","Franciszek");
Aby odnieść się do elementu tej tablicy, możesz użyć operatora dostępu do tablicy, w którym podajesz indeks elementu. Żeby odnieść się do pierwszego elementu tablicy, użyjesz poniższego kodu:
komunikat = "Cześć " + odwiedzajacy[0] + ". Zapraszamy!");
W tym wypadku odwiedzajacy[0] zwróci wartość "Jan". Jeśli użyjesz akcji trace do wyświetlenia zmiennej komunikat, przeczytasz:
Cześć Jan. Zapraszamy!
W większości języków programowania pierwszy indeks tablicy (numer jej pierwszego elementu) jest równy 0, a nie 1. W poniższej tabeli widać, że kolejne indeksy odnoszą się do kolejnych elementów tablicy odwiedzajacy.
Położenie w tablicy (indeks) |
0 |
1 |
2 |
3 |
Wartość indeksu |
Jan |
Maria |
Patrycja |
Franciszek |
Możesz ustawiać i pobierać wartości z tablicy, używając operatorów dostępu do tablicy. Możesz zastąpić istniejący element innym, wpisując pod podany indeks nową wartość, a nowe elementy dodawać, zwiększając indeks, na przykład:
odwiedzajacy = new Array("Jan","Maria","Patrycja","Franciszek");
odwiedzajacy[3] = "Natalia";
odwiedzajacy[4] = "Klaudiusz";
W tym przykładzie „Natalia” zastąpiła „Franciszka”, a „Klaudiusz” został dodany na końcu tablicy. Możesz także dodawać elementy do tablicy, używając metody push obiektu Array, na przykład:
odwiedzajacy = new Array("Jan","Maria","Patrycja","Franciszek");
nowaDlugosc = odwiedzajacy.push("Natalia","Klaudiusz");
Ten skrypt doda „Natalię” oraz „Klaudiusza” po „Franciszku” i do zmiennej nowaDlugosc wpisze aktualną wielkość tablicy odwiedzajacy (właściwość length). Właściwość lenght zwraca liczbę elementów znajdujących się w tablicy. W powyższym kodzie do nowaDlugosc zostanie wpisana liczba 6, ponieważ w tablicy znajduje się sześć imion.
Odsyłacz! Więcej na temat metod obiektu Array znajdziesz na stronach 214 - 224 książki ActionScript Reference Guide.
W dalszej części tego rozdziału znajdziesz przykład wykorzystania tablic.
Szare tło!
Symulacja tablic w filmach Flasha 4
We Flashu 4 możesz tylko symulować tablice, używając wyrażeń dla nazw zmiennych. Powyższy przykład w wersji dla języka ActionScript Flasha 5 można symulować we Flashu 4, używając struktury podobnej do tablicy. Oto przykład:
imie_1 = "Jan";
imie_2 = "Maria";
imie_3 = "Patrycja";
imie_4 = "Franciszek";
Teraz możesz użyć innej zmiennej (i) do pośredniego odniesienia się do różnych zmiennych zaczynających się od słowa imie_, na przykład:
i = 2;
aktualneImie = eval("imie_" add i);
komunikat = "Cześć " add aktualneImie add ". Zapraszamy!";
Dla kompatybilności z Flashem 4 użyliśmy operatora add (zamiast operatora +) oraz funkcji eval() do wyznaczenia aktualnej wartości zmiennej imie_, której używamy w ostatniej linii kodu. Jeśli będziesz śledził zmienną komunikat, w oknie Output pojawi się napis:
Cześć Maria. Zapraszamy!
Wspomnieliśmy o symulacji tablic w tej sekcji, ponieważ wielu flashowych twórców może mieć klientów, którzy chcą, aby ich filmy (lub witryny) były kompatybilne z modułem odtwarzającym filmy Flasha 4, bo właśnie ta wersja jest, jak na razie, najczęściej spotykana na komputerach użytkowników.
Koniec szarego tła!
Tworzenie dynamicznego menu wielokrotnego użytku
W tej sekcji użyjemy tablic do utworzenia dynamicznego menu opartego na skrypcie, którego możesz użyć w każdym filmie. Opracujesz główną listwę czasową z sześcioma częściami dla witryny prezentującej prace fotograficzne oraz menu, które będzie pozwalało poruszać się między częściami. Zadanie to nie wydaje się trudne, zaś całe menu utworzymy za pomocą skryptów.
Utwórz nowy film Flasha (klawisze Ctrl+N lub Command+N). W oknie właściwości filmu (klawisze Ctrl+M lub Command+M) ustaw prędkość odtwarzania na 20 klatek na sekundę i zmień kolor tła na biały. Wielkość obrazu ustal na taką, jaka Ci odpowiada.
Zmień nazwę warstwy na labels (etykiety).Utwórz ujęcia kluczowe (klawisz F6) w klatkach numer 2, 10, 20, 30, 40, 50. Zaznacz ujęcie 60. i naciśnij klawisz F5.
Począwszy od drugiej klatki warstwy labels, opatrz następującymi etykietami ujęcia kluczowe utworzone w 2. kroku: about, interiors, exteriors, landscapes, portraits, editorial.
Dodaj nową warstwę i nazwij ją actions (akcje). Dodaj ujęcie kluczowe w 2. klatce tejże warstwy. Z zaznaczonym ujęciem kluczowym otwórz edytor skryptów i dodaj akcję stop(). Używając panelu Frame, nadaj temu ujęciu etykietę //stop. W ten sposób dodasz komentarz informujący o zatrzymaniu odtwarzania. Dodana akcja stop() „chroni” główną listwę czasową przed przejściem do odtwarzania pozostałych części strony po załadowaniu filmu.
Utwórz jeszcze jedną warstwę. Nazwij ją artwork (grafika). Dodaj ujęcia kluczowe do tej warstwy tak, aby odpowiadały ujęciom kluczowym z warstwy labels. Dodaj jakąś grafikę do każdego ujęcia kluczowego odpowiadającego tejże części. Na początku może to być po prostu tytuł każdej części (na przykład: „Informacje o firmie”, „Zdjęcia wnętrz” itp.). Potrzebujemy tej warstwy, żeby wiedzieć, czy wskaźnik czasu głównej listwy czasowej w rzeczywistości zmienił miejsce po kliknięciu elementu menu.
Opracujemy teraz tablicę zawierającą wszystkie etykiety. Dodaj nową warstwę do głównej listwy czasowej i nazwij ją menu actions (akcje dla menu). Kliknij dwukrotnie pierwsze ujęcie tej warstwy. W edytorze skryptów wpisz następujący kod (pamiętaj, że znak ¬ oznacza kontynuację tej samej linii; nie wstawiaj tego znaku do rzeczywistego kodu):
sectionNames = new Array("about","interiors","exteriors", ¬
"landscapes","portraits","editorial");
Ta linia spowoduje utworzenie obiektu typu Array o nazwie sectionNames. Możemy się teraz odwołać do każdej części listwy czasowej, używając indeksu, na przykład sectionNames[0], sectionNames[1] itd. Poszczególne elementy tej tablicy będą przechowywały napisy wyświetlane w naszym menu.
W tym samym skrypcie dodaj tę linię poniżej już wpisanej:
sectionCount = sectionNames.length;
Powyższy kod powoduje utworzenie nowej zmiennej o nazwie sectionCount. Właściwość length zwraca aktualną liczbę elementów znajdujących się w tablicy. Ponieważ umieściliśmy w niej sześć elementów (w kroku 6.), wartość zmiennej sectionCount wyniesie 6. Możesz zastanawiać się, dlaczego po prostu nie wpisaliśmy do tej zmiennej szóstki. Chodzi o to, że liczbę elementów tablicy możesz zmienić w każdym momencie. Pozostała część kodu automatycznie dostosuje się do tych zmian. W ten sposób możemy utworzyć dynamiczne menu.
Zapisz film w pliku menuNaTablicy.fla. Teraz film Flasha powinien wyglądać mniej więcej tak, jak na rysunku 22.1.
Rysunek 22.1. Na głównej listwie czasowej znajdują się etykiety ujęć oraz grafika dla każdej części prezentacji
Teraz musimy utworzyć elementy graficzne, które wejdą w skład dynamicznego menu tworzonego w języku ActionScript. Najpierw musimy utworzyć klip filmowy zawierający pozycje menu. Jego klon umieścimy później na scenie. Naciśnij klawisze Ctrl+F8 (Command+F8), aby utworzyć nowy symbol. Nadaj mu nazwę menu i pozostaw wybraną opcję Movie Clip. Flash automatycznie przejdzie do trybu edycji symbolu.
Zmień nazwę warstwy istniejącej na listwie czasowej na menuItemBase. Na tej warstwie znajdzie się klon szablonu elementu menu. Jeszcze raz utwórz symbol klipu filmowego, naciskając klawisze Ctrl+F8 (Command+F8). Nadaj symbolowi nazwę menuItem i pozostaw wybraną opcję Movie Clip.
Będąc na listwie czasowej symbolu menuItem, zmień nazwę istniejącej warstwy na button. W tej warstwie utwórz lub dodaj symbol przycisku. Użyliśmy symbolu Pill Button z biblioteki przycisków (Window/Common Libraries/Buttons). Będzie to przycisk pojawiający się w menu. Upewnij się, że jest wystarczająco szeroki, aby pomieścić najdłuższą nazwę części prezentacji. Rozciągnęliśmy przycisk do 175% (rysunek 22.2). Wyśrodkuj klon przycisku na obrazie, używając panelu Align.
Rysunek 22.2. Klonu menuItem użyjemy do utworzenia poszczególnych przycisków z dynamicznego menu. Dzięki skryptowi pole tekstowe labelName będzie wypełniane nazwą odpowiedniej części witryny
Dodaj nową warstwę do symbolu menuItem i nazwij ją textField. Na tej warstwie utwórz dynamiczne pole tekstowe o długości klonu przycisku. W panelu Text Options przypisz do pola tekstowego zmienną labelName. W panelu Character wybierz taką czcionkę, jaką chcesz. W panelu Paragraph wybierz opcję wyśrodkowania tekstu w polu.
Dodaj jeszcze jedną warstwę. Nazwij ją actions. W pierwszym ujęciu tej warstwy umieść akcję stop(). Oznacz także to ujęcie etykietą //stop. (Informację, jak to zrobić, znajdziesz w kroku 4.).
Zaznacz klon przycisku dodanego w kroku 10. Otwórz edytor skryptów i wpisz następujący kod:
on(release){
_root.gotoAndStop(labelName);
}
Dzięki temu kodowi po kliknięciu zostanie wykonana akcja gotoAndStop() z parametrem labelName, który jest zmienną zawierającą wartość z dynamicznego pola tekstowego. Zauważ, że zmieniamy położenie wskaźnika czasu na głównej listwie czasowej, stosując słowo kluczowe _root. Teraz wystarczy, że każdemu klonowi symbolu menuItem nadamy odpowiednią wartość zmiennej labelName.
Otwórz symbol klipu filmowego menu, klikając go dwukrotnie w oknie biblioteki. Przeciągnij teraz klon symbolu menuItem z biblioteki na warstwę menuItemBase symbolu menu. Z zaznaczonym przeciągniętym klonem w pole Name panelu Instance wpisz menuItemBase (rysunek 22.3). Użyjemy tego przycisku jako szablonu dla prawdziwych przycisków w symbolu menu. Umieść klon na środku sceny, korzystając z panelu Align.
Rysunek 22.3. Za pomocą skryptu będziemy duplikować klon menuitemBase, aby utworzyć całe menu
Zapisz film.
Powróć do głównej listwy czasowej i utwórz nową warstwę o nazwie menu. Umieść na niej klon symbolu menu z biblioteki. W panelu Instance nadaj klonowi nazwę menu.
Otwórz edytor skryptów dla pierwszego ujęcia z warstwy menu actions. Na końcu znajdującego się tam skryptu dodaj linię:
menuItemSpacing = 10;
Linia ta powoduje utworzenie zmiennej o nazwie menuItemSpacing. Jej wartość będzie określała odstęp (w pikselach) między elementami menu.
Następnie dodaj poniższy kod do 1. ujęcia warstwy menu actions (pamiętaj, że znak ¬ oznacza kontynuację tej samej linii; nie wstawiaj tego znaku do rzeczywistego kodu):
for(i=1;i<=sectionCount;i++){
_root.menu.menuItemBase.duplicateMovieClip("menuItem_"+i, i);
_root.menu["menuItem_"+i].labelName = sectionNames[i-1];
if(i != 1){
_root.menu["menuItem_"+i]._y = _root.menu["menuItem_"+¬
i-1)]._y + _root.menu["menuItem_"+(i-1)]._height +¬
menuItemSpacing;
}
}
Ten kod zawiera pętlę for, która duplikuje klon menuItemBase (wewnątrz klonu menu) dla każdego elementu z tablicy sectionNames. W każdym tworzonym klonie umieszcza zmienną labelName zawierającą nazwę części, której dotyczy klon. Zauważ także, że do określenia odpowiedniego indeksu tablicy sectionNames używamy i - 1, ponieważ każda tablica zaczyna się od indeksu 0, a my numerujemy elementy menu od 1.
Po zduplikowaniu nowy klon umieszczamy poniżej poprzedniego. Operację tę przeprowadzamy tylko dla drugiego i dalszych klonów, ponieważ pierwszy po utworzeniu znajduje się na swoim miejscu. Zauważ, że stosujemy wartość zmiennej menuItemSpacing do oddzielenia elementów menu.
Zanim przetestujemy film, musimy ukryć szablon menuItemBase, z którego tworzymy klony. Za pętlą for dodaj następującą akcję:
_root.menu.menuItemBase._visible = false;
Zapisz i przetestuj film (klawisze Ctrl+Enter lub Command+Enter). Jeżeli nie popełniłeś żadnego błędu przy wpisywaniu kodu lub nie zapomniałeś nazwać jakiegoś klonu klipu filmowego, powinieneś zobaczyć dynamiczne menu utworzone za pomocą skryptu (zobacz rysunek 22.4).
Rysunek 22.4. Skrypt znajdujący się w pierwszym ujęciu warstwy menu actions duplikuje klon menuItemBase wewnątrz klonu menu. Każdemu zduplikowanemu klonowi nadawana jest wartość zmiennej labelName pobierana z tablicy. Jest ona wykorzystywana przez akcję gotoAndStop() oraz klon przycisku
Możesz wzbogacić to dynamiczne menu, umieszczając animację na listwie czasowej symbolu menuItem. Możesz też zmodyfikować skrypt, tak aby działał z oddzielnymi klipami filmowymi w poszczególnych sekcjach (sectionName) zamiast etykiet ujęć. Jeśli wykonasz tę modyfikację prawidłowo, być może już nigdy nie będziesz musiał tworzyć skryptu dla menu! Po prostu zmienisz grafikę i napisy w przycisku, umieszczając go w interfejsie o innym stylu.
Na CD-ROM-ie! W katalogu ch22 na CD-ROM-ie znajdziesz podstawową (menuArray_basic.fla) oraz zaawansowaną (menuArray_advanced.fla) wersję menu. W wersji zaawansowanej używana jest funkcja, która sprawdza, jaki jest wybrany element z menu i dla niego uruchamia niewielką animację.
Funkcje jako metody obiektów
Omówiliśmy już funkcje będące podprogramami w filmach Flasha. Funkcje mogą zostać użyte do zdefiniowania zestawu akcji, które będą wykonywane po wywołaniu funkcji. We Flashu 5 możesz także używać funkcji jako metod obiektów. Metody są akcjami przeznaczonymi do pewnych zadań. W odróżnieniu od właściwości oraz zmiennych metody wykonują pewne zadania na zawierającym je obiekcie. W tej sekcji przeanalizujemy plik .FLA zawierający funkcję tworzącą menu wyłącznie za pomocą skryptów.
Na CD-ROM-ie! Skopiuj na dysk twardy plik createMenu.fla znajdujący się na CD-ROM-ie w katalogu ch22.
Otwórz we Flashu 5 skopiowaną wcześniej na dysk twardy kopię pliku createMenu.fla. Zauważysz, że główna listwa czasowa wygląda podobnie jak listwa czasowa z przykładu z poprzedniej sekcji. Mamy pewną liczbę etykiet określających części filmu. Gdy przetestujesz film, zobaczysz dynamiczne menu. Kliknięcie elementu menu przeniesie Cię do odpowiedniej części filmu.
Jednak, w odróżnieniu od poprzedniego przykładu, na przyciskach oraz na listwie czasowej znajdują się różne napisy. Na przykład element menu o nazwie „Our Product” przenosi wskaźnik odtwarzania od ujęcia oznaczonego etykietą products. W tym filmie funkcja z paroma argumentami pozwala na określenie różnych tekstów dla przycisków menu oraz docelowych etykiet (lub listew czasowych).
Kliknij dwukrotnie pierwsze ujęcie warstwy functions. W edytorze skryptów zobaczysz definicję następującej funkcji (pamiętaj, że znak ¬ oznacza kontynuację tej samej linii; nie wstawiaj tego znaku do rzeczywistego kodu):
function createMenu(names,targets,labels){
this.itemName = names.split(",");
this.itemTarget = targets.split(",");
this.frameLabel = labels.split(",");
_root.menuBase.duplicateMovieClip("menu_1",1);
for(i=1;i<=this.itemName.length;i++){
this.attachMovie("menuItem","menuItem_"+i,i);
this["menuItem_"+i].name = this.itemName[i-1];
this["menuItem_"+i].itemTarget = this.itemTarget[i-1];
this["menuItem_"+i].frameLabel = this.frameLabel[i-1];
if(i>1){
this["menuItem_"+i]._y = this["menuItem_"+(i-1)]._y +¬
this["menuItem_"+(i-1)]._height;
}
}
}
Funkcja createMenu() posiada trzy argumenty: names, targets oraz labels. Wartości tych argumentów zostaną przekazane, gdy funkcja będzie wywołana jako metoda klonu klipu filmowego. Podobnie jak w poprzednim przykładzie, użyjemy tablic do przechowywania etykiet (oraz nazw części). Utworzyliśmy jednak dodatkowy argument (oraz tablicę) przechowujący tekst pojawiający się na przyciskach menu. W ten sposób tekst ten nie musi być taki sam jak etykiety ujęć wykorzystywane przez akcję Go To. Argument targets używany jest do tworzenia tablicy docelowych listew czasowych.
Funkcja używa także metody attachMovie (zamiast duplicateMovieClip), aby dodawać klipy filmowe menuItem do listwy czasowej wykonującej funkcję. W tym przykładzie na scenie znajduje się klon klipu filmowego menu. Temu pustemu klonowi przypisywana jest funkcja createMenu() jako metoda, podobnie jak duplicateMovieClip lub attachMovie są metodami obiektu typu Movie Clip:
_root.menu.createMenu = createMenu;
Ta linia powoduje utworzenie metody o nazwie createMenu dla klonu (obiektu) menu oraz wpisanie do tej metody funkcji createMenu jako wartości. Z tego też powodu każde wywołanie metody createMenu dla klonu menu będzie powodowało wykonanie akcji zawartych w funkcji createMenu.
Ostrzeżenie! Utworzenie lub przypisanie metody obiektowi nie powoduje jej wykonania. Jest to po prostu definiowanie metody dla obiektu, aby można ją było później wykorzystać. Podczas przyporządkowywania metody (lub funkcji) nie dodawaj nawiasów — będzie to błędem.
Zauważ, że możesz metodę nazwać dowolnie — nie musi odpowiadać nazwie funkcji jak w naszym przykładzie. Możesz więc napisać:
_root.menu.mojeMenu = createMenu;
Funkcja createMenu używa słowa kluczowego this, aby odnieść się do obiektu ją wykonującego. Po przypisaniu metody za pomocą instrukcji _root.menu.createmenu = createMenu słowo kluczowe this będzie równoznaczne ze ścieżką _root.menu. Jeśli jednak użylibyśmy innego klonu menu, na przykład menu_2, który używa funkcji createMenu jako metody, wtedy słowo kluczowe this odpowiadałoby ścieżce do tego klonu. Użycie słowa kluczowego this jest podstawą funkcji używanej jako metoda — możesz ją przypisać do różnych obiektów (lub klonów klipów filmowych) na obrazie.
Aby wywołać metodę createMenu dla klonu menu, musisz podać jej nazwę oraz wszystkie argumenty. W tym przykładzie następująca linia (pamiętaj, że znak ¬ oznacza kontynuację tej samej linii; nie wstawiaj tego znaku do rzeczywistego kodu) spowoduje wykonanie metody createMenu dla klonu menu:
_root.menu.createMenu("Home,Our Products,Our Services", ¬
"_root,_root,_root","main,products,services");
Dzięki tej linii poszczególne argumenty funkcji przyjęły następujące wartości:
names = " Home,Our Products,Our Services"
targets = "_root,_root,_root"
labesl = "main,products,services"
Po wywołaniu metody funkcja createMenu przekaże argumenty do akcji zawartych w funkcji. Metoda split (dla obiektów typu String) umożliwia podzielenie argumentów na części i umieszczenie każdej z nich w tablicy (części w argumentach są rozdzielone przecinkiem):
itemName[0] = "Home"
itemName[1] = "Our Products"
itemName[2] = "Our Services"
W kodzie funkcji nie znajdziesz powyższych linii, ale odniesienie do elementów tej tablicy
this.itemName[i-1]
używane jest do pobrania z tablicy nazwy elementu i umieszczenia go w zmiennej klonu klipu filmowego menuItem.
Tablica itemTarget zawiera informacje dla klonów menuItem na temat tego, w jakiej listwie czasowej należy wywołać akcję gotoAndStop() (znajdującą się w klonie przycisku w symbolu menuItem w bibliotece). Tablica frameLabel przekazuje odpowiednią nazwę etykiety dla akcji gotoAndStop() z klonu przycisku.
Film używa także funkcji (i metody) resetMenu do usuwania klonów menuItem oraz tablic.
Funkcje jako konstruktory obiektów
Funkcje mogą być także używane w połączeniu z konstruktorem new, co umożliwia tworzenie obiektów o właściwościach i metodach określonych przez funkcję. Oznacza to, że możesz używać funkcji do tworzenia unikalnych obiektów bazujących na parametrach przekazywanych do funkcji w czasie inicjalizacji. W tej sekcji pokażemy funkcję, która tworzy całą bibliotekę dźwięków za pomocą skryptu i nie używa żadnych klonów klipów filmowych.
Na CD-ROM-ie! Skopiuj na dysk twardy plik soundObjects.fla znajdujący się na CD-ROM-ie w katalogu ch22.
Otwórz skopiowany plik we Flashu 5. Zauważysz, że na scenie nie znajdują się żadne klipy filmowe ani inne elementy. Kliknij dwukrotnie pierwsze (i jedyne) ujęcie warstwy actions. W edytorze skryptów zobaczysz następujący skrypt:
function createLib(start,end){
for(i=start;i<=end;i++){
if(i==start){
this.snd = new Array();
}
this.snd[i] = new Sound();
this.snd[i].attachSound("sound_"+i);
}
}
this.soundLib = new createLib(1,7);
this.soundLib.snd[1].start();
this.soundLib.snd[2].start();
Skrypt ten można podzielić na trzy części: definicję funkcji, tworzenie i przypisywanie obiektu oraz wykonanie metod obiektów typu Sound.
Definicja funkcji
Funkcja createLib posiada dwa argumenty: start (początek) oraz end (koniec). Pamiętaj, że nazwy funkcji oraz argumentów zależą od Ciebie. Możesz je nazwać tak, jak zechcesz. Pętla zawarta w funkcji tworzy tablicę w obiekcie wywołującym funkcję (this). Tablica będzie zawierała obiekty typu Sound powiązane z plikami dźwiękowymi .AIFF z biblioteki. Pamiętaj, że każdy z dźwięków zawartych w bibliotece musi mieć ustawioną opcję Export this symbol. Możesz to zrobić w oknie Symbol Linkage Properties.
Odsyłacz! Zajrzyj do rozdziałów 19., „Sterowanie klipami filmowymi” oraz 20., „Współdzielenie i ładowanie elementów”, aby dowiedzieć się czegoś więcej o właściwościach współdzielenia symbolu.
Tworzenie i przypisywanie obiektu
Po zdefiniowaniu funkcji createLib możemy jej użyć do tworzenia nowych obiektów. W przykładzie nowy obiekt o nazwie soundLib jest tworzony po definicji funkcji:
this.soundLib = new createLib(1,7);
Obiekt deklarowany jest na listwie czasowej this. Dzięki temu będziemy mogli wczytywać ten film do innych filmów Flasha, bo wszystkie docelowe ścieżki dla funkcji createLib będą prawidłowe. Jeśli będziesz testował tylko ten film (nie wczytując go do innych), słowo kluczowe this będzie odpowiadało poziomowi _root lub _level0. Używając konstruktora new, utworzyliśmy tablicę snd oraz obiekty typu Sound wewnątrz obiektu soundLib. Powstał unikalny obiekt o określonych właściwościach. Dzięki niemu za pomocą jednej funkcji możesz tworzyć tyle różnych obiektów, ile zechcesz:
this.soundLib_1 = new createLib(1,3);
this.soundLib_2 = new createLib(4,7);
Te akcje (nieużywane w przykładzie) powodują utworzenie dwóch różnych obiektów soundLib. Każdy obsługuje określony zestaw dźwięków z biblioteki.
Liczby podawane w nawiasach określają dźwięki z biblioteki, jakie zostaną przyporządkowane tworzonemu obiektowi. Pamiętaj, że w funkcji createLib argumenty start oraz end używane są do tworzenia identyfikatora współdzielonego symbolu:
"sound_"+i
gdzie i zmienia się od argumentu start aż do argumentu end.
Wywoływanie metod obiektu typu Sound
Po utworzeniu obiektów typu Sound wewnątrz obiektu soundLib możemy odtwarzać dźwięki, używając metody start() obiektów typu Sound:
this.soundLib.snd[1].start();
this.soundLib.snd[2].start();
Te linie spowodują odtworzenie dźwięków powiązanych z obiektami typu Sound, które znajdują się w tablicy snd pod indeksami 1 oraz 2 (w tym przykładzie spowoduje to odtworzenie dźwięków sound_1 oraz sound_2 z biblioteki).
Jest to tylko jeden z przykładów użycia funkcji do tworzenia nowych obiektów. Możesz ich używać do opracowania innych typów obiektów zawierających dane, aby łatwiej obsługiwać przepływ informacji. Możesz także wykreować obiekt typu Color, który będzie odnosił się do więcej niż jednego klonu klipu filmowego.
Ostrzeżenie! W czasie testów wykryliśmy, że metoda setVolume obiektów typu Sound powoduje zmianę głośności wszystkich klonów obiektu typu Sound na danej listwie czasowej. Z tego też powodu powinieneś używać tylko jednego takiego obiektu na listwę czasową. Na przykład, jeśli chciałbyś osobno sterować głośnością pięciu różnych dźwięków, każdy klon obiektu typu Sound musi się znaleźć w innym klonie klipu filmowego.
Podsumowanie
W języku ActionScript z Flasha 5 można wyróżnić pięć typów danych: string, number, movieclip, object oraz function.
Typ danego elementu można sprawdzić za pomocą operatora typeof.
Najczęściej funkcji używa się jako podprogramów, czyli zestawu akcji, które są wykonywane, gdy w skrypcie napotkana zostanie nazwa funkcji.
Podprogram (funkcja) powinien być tworzony w momencie, gdy zauważysz, że w filmie używasz tej samej grupy akcji w kilku miejscach lub chcesz rozbić długi skrypt na kilka mniejszych.
Funkcję definiuje się, używając akcji function w następujący sposób: function nazwa(argumenty){ akcje }.
Funkcja jest wykonywana, gdy w kodzie wystąpi jej nazwa. Format wywołania funkcji jest następujący: ścieżkaAdresowa.nazwaFunkcji(argumenty);, na przykład _root.createLib(1,7);.
Tablice pomagają organizować dane, na przykład listy. Tablica tworzona jest za pomocą konstruktora obiektu Array, na przykład tablica = new Array();.
Każdy element tablicy posiada indeks, który wskazuje na jego położenie w tablicy. Indeks zaczyna się od 0 i przy każdym nowym elemencie zwiększa się o 1.
Funkcji można używać jako metod obiektów. Metodę przypisuje się do obiektu przez podanie jej nazwy po nazwie obiektu i przypisanie tej nazwy jako wartości (na przykład _root.menu.createMenu = createMenu;). Nawiasy oraz argumenty są pomijane.
Obiekty tworzy się za pomocą konstruktora funkcji. Użyta funkcja opisuje właściwości oraz metody, które znajdą się w obiekcie; ich nazwy są poprzedzone słowem kluczowym this. Nowy obiekt tworzy się, określając jego nazwę i przyrównując ją do nowego klonu funkcji, na przykład obiekt = new createLib(1,7);.
Jeśli będziesz używał polskich nazw, a nie angielskich, w zasadzie nie musisz używać prefiksu. Prawie wszystkie zarezerwowane nazwy języka ActionScript nie pokrywają się z polskimi słowami (przyp. tłum.).
W tym ćwiczeniu autor opisuje fazę projektowania gry, natomiast pliki zawierają jej gotową, w pełni działającą, wersję, która w trakcie produkcji przeszła kilka modyfikacji. Dlatego zawartość plików nie w pełni pokrywa się z treścią ćwiczenia (przyp. tłum.).
2 Część I ♦ Podstawy obsługi systemu WhizBang (Nagłówek strony)
10 C:\helion\f5bpopr\r22-06.doc
Do składu: ostatni podpunkt usunąłem, bo nijak miał się do reszty podpunktów (tłumacz).