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

Zrozumieć symbol "Graphics"

Każdy kto spędził trochę czasu z ActionScript'em na pewno doskonale zna działanie MovieClip'ów jednak Flash pozwala również na stworzenie czegoś w miarę podobnego, ale zwanego symbolem "Graphics". Na pierwszy rzut oka mogą się po prostu wydawać uproszczonymi wersjami MovieClip'ów i jest to po części prawda ale w ich działaniu obowiązuje pewna o wiele prostsza zasada... w trakcie eksportu do SWF wszystkie obiekty "Graphics" zostają rozbite na kawałki, podobnie jak to robi polecenie "break apart" (CLTR+B) z tą różnicą, że wszystkie ustawienia i tween'y zostają nałożone na obiekty w środku. Z punktu widzenia ActionScript daje to nam ciekawe możliwości optymalizacji w sytuacjach gdy mamy do czynienia z zagnieżdżającymi się MovieClip'ami.
Weźmy na przykład scenariusz w którym chcemy, aby dwa obiekty krążyły w około siebie ale jednocześnie razem przesuwały się na nową pozycję:

Tak więc symbol Anim zawiera animację krążących obiektów, a tymczasem na scenie przesuwamy całość w prawo. Nic nadzwyczajnego, ale jeśli dodamy do tego chęć dostępu do owych krążących obiektów z poziomu ActionScript instynktownie pierwszym krokiem będzie zmiana Anim z "Graphics" na "MovieClip" by następnie nadać mu nazwę instancji i dalej odwoływać się przez nią by dotrzeć do dwóch obiektów w środku. To właśnie w takich sytuacjach wykorzystanie symbolu Graphics zamiast MovieClip pozwoli pozbyć się dodatkowego zagnieżdżenia, o ile oczywiście wiemy jak Graphics działa.
Proponuje przeprowadzić następującym eksperyment, stwórz na scenie dwa MovieClip'y z dwoma różniącymi się klatkami animacji, następnie nazwij je "mc1" oraz "mc2" (nazwy instancji, tak żeby można było się do nich odwołać z ActionScript) a całość dodatkowo zamknij w symbolu Graphics. Co się stanie jeśli ze sceny gdzie znajduje się owy symbol Graphics wywołamy poniższe funkcje?
mc1.gotoAndStop(1);
mc2.gotoAndStop(2);
Ponieważ Graphics zostanie rozbity i wszystkie wewnętrzne elementy wylądują na zewnątrz odwołania do "mc1" i "mc2" przejdą bez problemów.
Gotowy przykład do ściągnięcia tutaj: GraphExample.zip

Precyzyjne porównanie do typu klasy bez wykorzystywania 'is' i 'instanceof'

W ActionScript2 i 3 istnieje możliwość sprawdzenia czy dany obiekt należy do pewnej klasy - w AS2 jest to słowo instanceof a w AS3 is i oba spełniają swoja zadanie całkiem nieźle, jednak należy pamiętać, że oba zwrócą 'true' nawet jeśli docelowy obiekt nie jest dokładnie z tej samej klasy, tylko ją rozszerza. Innymi słowy porównanie obiektu MovieClip do Sprite zwróci 'true':
var mc:MovieClip = new MovieClip();
trace(mc is Sprite); //true
Tak więc co zrobić gdy chcemy sprawdzić, że wybrany obiekt faktycznie należy do docelowej klasy i nic po za tym? Rozwiązania są dwa:
1. Funkcja getQualifiedClassName.
Czyli najprostsze podejście - wyciągamy nazwę klasy w postaci String i porównujemy ją do nazwy której szukamy.
var mc:MovieClip = new MovieClip();
trace(getQualifiedClassName(mc) == "MovieClip"); //true
trace(getQualifiedClassName(mc) == "Sprite"); //false
2. Porównanie konstruktorów.
To już temat nieco bardziej zaawansowany, a do tego możliwy tylko w AS3. Nie jest to do końca jasno napisane, ale każdy obiekt w ActionScript3 ma pole o nazwie 'constructor' zawierające odniesienie do konstruktora użytego przy tworzeniu obiektu, a ponieważ w AS konstruktor w każdej klasie może być tylko jeden wystarczy je porównać:
var mc:MovieClip = new MovieClip();
var con:Object = MovieClip.prototype.constructor;
trace(mc.constructor == con); //true
Przy czym pamiętać tutaj należy o kilku rzeczach:
- ponieważ 'prototype' i 'constructor' są przydzielone dynamicznie ich czas dostępu będzie wolniejszy niż ten z wykorzystaniem funkcji getQualifiedClassName.
- aczkolwiek w odpowiednio dużej pętli, zrzucając uprzednio konstruktor do lokalnej zmiennej, czas wykonania może być nawet o połowę szybszy.
- mc.constructor w FlashDevelop (ale nie Flash Professional) najprawdopodobniej wyrzuci błąd, który można obejść rzutując mc do klasy Object:
var con:Object = MovieClip.prototype.constructor;
trace((mc as Object).constructor == con); //true
Niestety, rzutowanie spowolni czas wykonania o jakieś 10%.

Podstawy silnika kafelkowego część 1: widok izometryczny [podstawowy]

W tym trzyczęściowym artykule postaram się przybliżyć kilka najbardziej podstawowych zagadnień z silników opartych o kratki - czy też kafelki (tile-based). Owe silniki istnieją już od bardzo dawna i wydawać by się mogło, że już wszystko w tej sprawie zostało powiedziane, jednak wciąż wiele osób ma z nimi problemy, nierzadko komplikując trywialne zagadnienia.
Jednym z takich zagadnień jest widok izometryczny (czasem nazywanym "widokiem po skosie") będący specyficznym rodzajem transformacji 3D bez dodatku perspektywy, często wykorzystywanym w starszych grach strategicznych. Chociaż definicja mówi o transformacji 3D takowa wcale nie jest wymagana i można ją zastąpić czymś o wiele prostszym, co niestety nie wszyscy próbują zrobić i dlatego w Internecie można całkiem sporo podobnych artykułów, które jednak najpierw tłumaczą podstawy 3D - nie potrzebnie.
Całość można sprowadzić do pojedynczej funkcji:
function getTile(nTargetX:Number,nTargetY:Number,nWidth:Number,nHeight:Number):Point {
	var nScale:Number = nWidth/nHeight;
	var nTransY:Number = (nScale*nTargetY-nTargetX)/2;
	var nTransX:Number = nTargetX+nTransY;
	var nTmpY:Number = Math.round( nTransY/(nHeight*nScale) );
	var nTmpX:Number = Math.round( nTransX/nWidth );	
	var nTileX:Number = (nTmpX-nTmpY)*nWidth;
	var nTileY:Number = (nTmpX+nTmpY)*nHeight;
	return new Point(nTileX,nTileY);
}
W efekcie dostając:
(Zielone kółko to Point zwrócony przez getTile)
Gotowy przykład: tile_example.zip

I to w zasadzie wszystko, dalej tylko jeszcze poświecę parę słów na wyjaśnienie działania funkcji getTile krok po kroku:
1.
var nScale:Number = nWidth/nHeight;
Skala będzie nam potrzebna przy transformacji by wyrównać wysokość do szerokości (ponieważ algorytm działa tylko w skali 1:1).
2.
var nTransY:Number = (nScale*nTargetY-nTargetX)/2;
var nTransX:Number = nTargetX+nTransY;

W tym miejscu następuje transformacja punktu na ekranie, na punkt w rzucie izometrycznym.
Najczęściej mówiąc o rzucie izometrycznym mamy na myśli przestrzeń obróconą o kąt 45 stopni, w taki sposób że ruchowi w prawo nie będzie odpowiadać samo +X, ale raczej pewna wartość X plus częściowo również i Y. Najlepiej zobrazować to na przykładzie:

Jak widać przesunięcie kursora w prawo, przesuwa punkt transformacji w prawo tylko po części, ponieważ dochodzi do tego jeszcze przesunięcie do góry. Uzbrojeni w ta wiedzę, możemy spróbować napisać generalny wzór - skoro przesunięcie w prawy (+X) daje nam również trochę przesunięcia do góry (-Y) można powiedzieć, że Y maleje wraz ze wzrostem X, czyli innymi słowy Y = -nTargetX. Jednak należy pamiętać, że nie jest to transformacja x=>y (inaczej mieli byśmy do czynienia z obrotem o 90 stopni), stąd też do równania należy dołączyć również dzielnie przez 2 (bo 90 stopni podzielone przez 2 to nasze 45 stopni... w wielkim uproszczeniu). Teraz gdy już znamy Y, obliczenie X jest trywialne i wystarczy, że odejmiemy wartość Y od docelowego X (by pokonany dystans był identyczny z tym przed transformacją), a ponieważ Y już jest ujemne wstawiamy znak dodawania Y = nTargetX+nTransY;. Przy okazji, plus i minus można w tych równaniach zamienić miejscami by uzyskać transformację dla obrotu -45 stopni.
3.
var nTmpY:Number = Math.round( nTransY/(nHeight*nScale) );
var nTmpX:Number = Math.round( nTransX/nWidth );
var nTileX:Number = (nTmpX-nTmpY)*nWidth;
var nTileY:Number = (nTmpX+nTmpY)*nHeight;

Tutaj zmieniamy wybrany punkt na podpadający pod niego kafelek, poprzez "skurczenie" całej przestrzeni o wysokość i szerokość kratki, następnie usunięcie informacji po przecinku i przywrócenia całości do "normalnych rozmiarów". Ponieważ uwielbiam przykłady o to następny: jeśli szerokość kafelki numer #0 wynosi 20 pikseli, to wszystko pomiędzy 0 a 20 pikseli będzie podpadać właśnie pod nią, tak więc: jak sprawdzić do której kafelki należy siódma piksela? Bierzemy owe 7, dzielimy przez 20 i dostajemy 0.35. Z rezultatu usuwamy wszystko po przecinku i dostajemy naszą kratkę #0. Jeszcze spróbujmy tego samego dla pikseli 27; 27/20 = 1.35; usuwamy liczby po przecinku i dostajemy #1, co się zgadza bo dwudziesta siódma piksela nie należy do kratki #0.

Uff, starczy na dzisiaj. Za dwa tygodnie napisze jak w najłatwiejszy sposób zaimplementować znajdywanie ścieżki w silnikach kafelkowych.