You are on page 1of 84

02/2010 (182)

SPIS TREŚCI
17 Opis DVD

BIBLIOTEKA MIESIĄCA PROGRAMOWANIE C++


6 Biblioteka cocos2d-iphone – Łatwe programo- 30 Fabryki obiektów
wanie gier 2D pod iPhone Robert Nowak
Jakub Węgrzyn Techniki opisane w tym artykule pozwalają tworzyć obiekty na
Biblioteka cocos2d-iphone zapewnia wygodny i łatwy w uży- podstawie identyfikatorów dostarczanych w czasie działania pro-
ciu zestaw klas, które pozwalają na szybkie tworzenie dwu- gramu, co jest wygodniejsze niż podawanie typów w formie zro-
wymiarowych gier pod iPhone. Jeśli marzysz o tym, aby napi- zumiałej dla kompilatora.
sać własną grę na ten właśnie telefon, to koniecznie przeczy-
taj ten artykuł.

PROGRAMOWANIE GIER
KLUB TECHNICZNY 34 Jak napisać swoją pierwszą grę komputerową
Konstanty Kalicki
18 Co nowego we Flex 4 Prawdopodobnie każdy gracz ma w głowie co najmniej jeden po-
Rafał Nagrodzki mysł na rewelacyjną grę. Niektórzy idą dalej i zakładają zeszyty w
Flex jest jedną z najbardziej zaawansowanych technologii do kratkę, których strony zapełniają pomysłami i szkicami. Niestety
budowania aplikacji typu RIA w bezpośrednim tłumaczeniu bo- w tym szczególnym przypadku sam pomysł to zbyt mało i – bez
gatych aplikacji internetowych. Silnikiem wyświetlającym apli- konkretnych kroków – jest niewiele wart.
kacje Flex’owe jest technologia Adobe Flash, która pozwala na
osiągnięcie jednolitego wyglądu uruchamianej aplikacji, nieza-
leżnie od wykorzystywanej przeglądarki czy systemu operacyj- 38 Techniki renderingu 2,5D w grach
nego. City-Interactive team
Pierwsze gry wykorzystujce technik 2,5 D nazywan równie pseudo
3D powstay w latach 70 XXw. na 8 bitowe komputery Atari oraz
22 Technologie Progress OpenEdge – Część 6. C64. Pionierami tej techniki byy gry „Night Driver”, „Outrun”, „Pole
Obiekty ProDataSet Position”. To technika uywana w rónych kategoriach gier, ma za za-
Piotr Tucholski danie stworzenie w grze dwuwymiarowej wraenia przestrzennoci.
Progressowe obiekty typu Dataset (ProDataSet) rozszerzają moż-
liwości definiowania złożonych obiektów biznesowych oraz rela-
cji między nimi. Są bardzo ważnym elementem w procesie budo- 42 Mapy kafelków w grach 2D – Wstęp i rysowanie
wania nowoczesnych aplikacji rozproszonych i wymiany danych z Jacek Zagrodzki
innymi aplikacjami lub ich modułami poprzez XML. Marzysz o stworzeniu swojej wymarzonej dwuwymiarowej plat-
formówki albo klasycznego RTSa? Od czego zacząć? Oczywiście
od map kafelków (ang. tiled maps). Dzięki temu artykułowi po-
znasz podstawy tej techniki – dowiesz się, jak mapy kafelków za-
programować i jak je rysować.
CLOUD COMPUTING
26 Enterprise Private Clouds 54 Efektywny blitter – metody optymalizacji
Michał Kuratczyk Bartosz Taudul
Cloud computing robi od pewnego czasu zawrotną karierę me- Jak to jest, że jedne gry posiadają świetnie wyglądającą i płynną gra-
dialną. Tematem zajmują się nie tylko tytuły poświęcone bran- fikę, podczas gdy inne, mimo znacznie uboższego wyglądu, ledwo
ży IT, ale także biznesowe i popularno-naukowe. Nawet Dilbert sobie radzą z przerysowywaniem pola gry? Dlaczego u konkuren-
wspomina już o cloud computing. Warto zatem zastanowić się cji na ekranie może poruszać się całe mrowie przeciwników, podczas
czym jest, a czym nie jest cloud computing i jak wpłynie na two- gdy u nas już przy pięciu jest problem? Różnica tkwi w kunszcie pro-
rzenie i zarządzanie oprogramowaniem. gramisty odpowiedzialnego za niskopoziomową obsługę grafiki.

4 02/2010
60 Xcode – Xcode – oto czytelnik. Czytelniku –oto Miesięcznik Software Developer’s Journal (12 numerów w roku)
Xcode. Poznajcie się. Czyli wprowadzenie do pro- jest wydawany przez Software Press Sp. z o.o. SK
gramowania najpopularniejszego urządzenia
mobilnego na świecie. Redaktor naczelny:
Patryk Bukowiecki, Jarosław Wojczakowski Łukasz Łopuszański lukasz.lopuszanski@software.com.pl
iPhone i App Store to światowy fenomen. Firma Apple dokonała
niemożliwego i uwolniła wielką siłę niezależnych developerów Projekt okładki: Agnieszka Marchocka
mogących od teraz spełniać swoje wizje i tworzyć gry jak daw-
niej, w pojedynkę lub w małych zespołach, siedząc nad nimi po Skład i łamanie:
Monika Grotkowska monika.grotkowska@software.com.pl
pracy, w garażach.

Kierownik produkcji:
64 Cyfrowa kreacja – Artystyczne projektowania Andrzej Kuca andrzej.kuca@software.com.pl
gier
Arkadiusz Wychadaczuk Dział produkcji i kolportażu:
Alina Stebakow alina.stebakow@software.com.pl
Niezalenie od tego, czy tworzymy film, spot reklamowy, efekty
specjalne, wizualizacj czy gr, potrzebujemy narzdzi, które pozwol
nam w produktywny i elastyczny sposób stworzy to, co widzimy
oczami wyobrani. Wtedy pojawia si konieczno wybrania oprogra-
mowania do tzw. cyfrowej kreacji. Nakład: 6 000 egz.

Adres korespondencyjny:
68 Programowanie wizualne – co to takiego? Software Press Sp. z o.o. SK,
Arkadiusz Brzegowy ul. Bokserska 1, 02-682 Warszawa, Polska
tel. +48 22 427 36 91, fax +48 22 224 24 59
Niniejszy tekst to informacje, przykłady i tutorial przybliżające
www.sdjournal.org cooperation@software.com.pl
technologię Quest3D. Artykułem tym chcę pokazać, że można
tworzyć aplikacje 3D i gry szybko oraz bez znajomości języka pro-
gramowania, bibliotek DirectX czy OpenGL. Jeszcze raz – można.
Jest do tego gotowe narzędzie. Resztę znajdziecie poniżej. Dział reklamy: adv@software.com.pl

Obsługa prenumeraty:
72 Producent – A kto to jest? pren@software.com.pl
Łukasz Szczepański
Rola producenta w procesie budowania gry komputerowej bywa, Dołączoną do magazynu płytę CD przetestowano programem
AntiVirenKit firmy G DATA Software Sp. z o.o.
szczególnie dla osób postronnych, dość niejasna. Czytając poniż-
szy artykuł, przekonasz się, kim jest producent i jaka jest jego rola Redakcja dokłada wszelkich starań, by publikowane w piśmie
we wspomnianym procesie. i na towarzyszących mu nośnikach informacje i programy były
poprawne, jednakże nie bierze odpowiedzialności za efekty
wykorzystania ich; nie gwarantuje także poprawnego działania
programów shareware, freeware i public domain.

EFEKTYWNOŚĆ PRACY Uszkodzone podczas wysyłki płyty wymienia redakcja.

Wszystkie znaki firmowe zawarte w piśmie są własności


74 Wspinaczka do profesjonalizmu – Modelowa odpowiednich firm.
Zostały użyte wyłącznie w celach informacyjnych.
ścieżka rozwoju kompetencji – podejście pragma-
tyczne Redakcja używa systemu automatycznego składu
Sławomir Sobótka
Autor przedstawi jeden z modeli rozwoju kompetencji – Model Osoby zainteresowane współpracą prosimy o kontakt:
Braci Dreyfus, który odnosi się nie tylko do umiejętności technicz- cooperation@software.com.pl
nych, ale również do ogólnej aktywności każdego z nas. Model
pozwoli Ci uświadomić sobie swój aktualny poziom kompetencji Druk: Artdruk www.artdruk.com
w dowolnej dziedzinie oraz zaplanować dalszą drogę ich rozwo-
ju. Spojrzenie przez pryzmat modelu na kolegów z zespołu oraz Wysokość nakładu obejmuje również dodruki. Redakcja nie
ew. podwładnych zwiększy efektywność Twej komunikacji i może udziela pomocy technicznej w instalowaniu i użytkowaniu
znacząco wpłynąć na redukcję frustracji. programów zamieszczonych na płycie CD-ROM dostarczonej
razem z pismem.

Sprzedaż aktualnych lub archiwalnych numerów pisma po


innej cenie niż wydrukowana na okładce – bez zgody wydawcy

FELIETON – jest działaniem na jego szkodę i skutkuje odpowiedzialnością


sądową.

82 GeeCon 2010

www.sdjournal.org 5
Biblioteka Miesiąca

Biblioteka
cocos2d-iphone
Łatwe programowanie gier 2D pod iPhone

Biblioteka cocos2d-iphone zapewnia wygodny i łatwy w użyciu zestaw


klas, które pozwalają na szybkie tworzenie dwuwymiarowych gier pod
iPhone. Jeśli marzysz o tym, aby napisać własną grę na ten właśnie
telefon, to koniecznie przeczytaj poniższy artykuł.
giem jest posiadanie komputera Mac z pro-
Dowiesz się: Powinieneś wiedzieć: cesorem Intela, co wyklucza większość star-
• Jakie są podstawowe konstrukcje języka Ob- • Jak programować w języku C. szych urządzeń. Ponadto konieczne jest po-
jective-C; siadanie zainstalowanego systemu Mac OS
• Jak przygotować środowisko pozwalające X w wersji 10.5 lub wyższej. Niestety łącz-
na tworzenie gier; ny koszt zakupu telefonu i komputera mo-
• Jak korzystać z biblioteki cocos2d-iphone. że swobodnie dotrzeć do pułapu 10 tysięcy
złotych , co dla wielu osób stanowi barierę
nie do przebicia.
gość tytułów opracowanych za jej pomocą, Jeżeli jednak jesteśmy szczęśliwymi po-
które skutecznie walczą o swoje miejsce w siadaczami odpowiedniego sprzętu, musi-
Poziom AppStorze. my zaopatrzyć się w iPhone SDK zawierają-
trudności ce niezbędne biblioteki oraz edytor XCode.
Wymagane narzędzia W tym celu należy założyć darmowe konto
Rozpoczęcie prac nad tworzeniem apli- na portalu iPhone Dev Center. I na tym eta-
kacji dla iPhone’a wymaga sporych nakła- pie moglibyśmy już zakończyć kompleto-

C
hyba każdy pamięta, jaka rewo- dów finansowych. Podstawowym wymo- wanie narzędzi pod warunkiem, że wystar-
lucja została dokonana przez la-
ta królowania odtwarzacza iPod,
którego główną siłą był internetowy sklep
z muzyką iTunes. Dziś można już powie-
dzieć, że Apple ponownie wyprzedził
konkurencję, wprowadzając do sprzedaży
telefon iPhone, jednocześnie uruchamia-
jąc sklep z aplikacjami AppStore. Telefon
mimo wielokrotnie wytykanych wad, bra-
ków funkcjonalności czy też wysokiej ceny
sprzedaje się doskonale. Ogromną część
sprzedawanych aplikacji stanowią gry.
Wystarczy wspomnieć, że kilka tytułów
sprawiło, iż ich autorzy zarobili miliony
dolarów i w tej chwili mają swoje firmy
tworzące kolejne gry. Nic nie stoi na prze-
szkodzie, aby samemu spróbować swoich
sił w tej dziedzinie.
Wielką pomocą w pierwszych próbach
tworzenia własnej gry jest biblioteka coco-
s2d-iphone. Zapewnia ona wygodny i ła-
twy w użyciu zestaw klas, które pozwala-
ją na szybkie tworzenie gier 2D dla telefo-
nu iPhone. O jej sile świadczyć może mno- Rysunek 1. Tworzenie przykładowego projektu Objective-C

6 02/2010
Programowanie gier pod iPhone

czy nam możliwość testowania tworzonych


aplikacji za pomocą emulatora, przewrotnie Listing 1. Instalacja szablonu projektu cocos2d-iphone
noszący nazwę iPhone Simulator. Niestety, $ cd cocos2d-iphone/
nawet jeżeli jesteśmy posiadaczami telefo- $ ./install_template.sh
nu wyprodukowanego przez firmię Apple,
nie dostąpimy możliwości uruchamiania na Listing 2. Witaj świecie!
nim naszej aplikacji. Po raz kolejny będzie- #import <Foundation/Foundation.h>
my musieli sięgnąć do naszej kieszeni i po-
święcając sto dolarów amerykańskich, sta- int main (int argc, const char *argv[])
niemy się posiadaczami konta na iPhone {
Developer Program Portal. Dla pocieszenia NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
dodam tylko, że od tej chwili nie musimy NSLog (@"Hello World");
ponosić żadnych dodatkowych kosztów, na- [pool drain];
wet jeżeli zdecydujemy się umieścić naszą return 0;
aplikację w AppStore i zacząć zarabiać na }
niej pieniądze.
Ostatni element procesu przygotowania Listing 3. Przykładowa deklaracja klasy
do tworzenia gier to zainstalowanie bibliote- #import <Cocoa/Cocoa.h>
ki cocos2d-iphone, która na dzień powstania
niniejszego artykułu dostępna jest w wersji @interface Student : NSObject
0.8.1. Po jej pobraniu i rozpakowaniu otrzy- {
manego archiwum warto zainstalować sza- NSString* name;
blon projektu, który pozwoli na szybkie two- }
rzenie gier z poziomu edytora XCode. W tym
celu z poziomu terminala systemu Mac OS X - (void) displayName;
należy wykonać operacje przedstawione na @end
Listingu 1.
Od tej chwili moglibyśmy rozpocząć przy- Listing 4. Implementacja przykładowej klasy
godę z tworzeniem gier dla iPhone’a. Tutaj #import "Student.h"
pojawia się jednak kolejny problem – język
Objective-C. Co prawda możliwe jest wyko- @implementation Student
rzystanie w tym celu języka C++, jednak i tak
pewne fragmenty będą musiały powstać za - (void) displayName
pomocą Obj-C. Ponadto wiązać się to będzie {
z utratą wszelkiego wsparcia ze strony biblio- NSLog( name );
teki cocos2d-iphone. }
@end
Podstawy języka Objective-C
Poniższy artykuł absolutnie nie pretendu-
je do miana kompletnej specyfikacji tego ję-
zyka. Zajęłoby to zdecydowanie zbyt dużo
miejsca i czasu, jednak aby rozpocząć swoją
przygodę z tworzeniem gier, nie potrzebuje-
my rozległej wiedzy. Wystarczy kilka wska-
zówek i jestem przekonany, że każdy, kto
zdążył do tej pory zapoznać się z dobrym,
klasycznym językiem C, poradzi sobie z tym
zadaniem.
Nie byłby to artykuł wprowadzający
w podstawy programowania w dowolnym
języku, bez przykładu Hello World. Leni-
wych czytelników uprzedzam, że urucho-
mienie go nie wymaga przepisania nawet
linijki kodu. Otóż twórcy edytora XCode
okazali się odpowiednio przewidujący. Aby
nie przedłużać oczekiwania, rozpocznijmy
od utworzenia nowego projektu – w tym
wybieramy z menu aplikacji File>New pro-
ject… i w nowo otwartym oknie wybieramy
z listy opcję Command Line Utility, a w polu
znajdującym się po prawej stronie zaznacza-
my ikonę Foundation Tool (Rysunek 1). Po
kliknięciu przycisku Choose… pozostaje tyl- Rysunek 2. Tworzenie projektu z wykorzystaniem biblioteki cocos2d

www.sdjournal.org 7
Biblioteka Miesiąca

ko wprowadzić odpowiednią nazwę projek- sy umieszcza się w pliku z rozszerzeniem metod sprowadza się do podania jej nagłów-
tu i wybrać katalog na dysku, w którym ma .h, jednak pliki zawierające jej implemen- ka i wprowadzenia odpowiedniego kodu po-
zostać utworzony. W tym momencie dyspo- tację mają rozszerzenie .m. Listing 3 przed- między nawiasami klamrowymi. Zakończe-
nujemy podstawowym projektem wraz z ko- stawiający deklarację prostej klasy wyraźnie nie implementacji klasy oznacza się słowem
dem przedstawionym na Listingu 2. ujawnia, jak daleko Objective-C odsunął się kluczowym @end.
Na pierwszy rzut oka kod nie różni się od stylu języka C++. Warto w tym miejscu zaprezentować, w
zbytnio od tysięcy podobnych programów Przedstawia on minimalistyczną klasę jaki sposób Objective-C pozwala na dekla-
pisanych w czystym C. Jednak odrobi- o nazwie Student, która zawiera jedno po- rację metod przyjmujących argumenty. Na
nę dłuższa chwila pozwoli na wychwyce- le typu NSString o nazwie name. Łatwo za- początek przykład metody jednoargumen-
nie pierwszych różnic. Na początek dyrek- uważyć, iż deklaracja klasy w języku Objec- towej:
tywa #import – jest ona odpowiednikiem tive-C rozpoczyna się słowem kluczowym
#include, jednak zapewnia ona, iż plik zo- @interface, po którym wpisana została na- - (void) displayText: (NSString*)text;
stanie dołączony tylko raz. Kolejna linia ko- zwa klasy. Po dwukropku powinna znaleźć
du ujawnia korzenie Objective-C sięgają- się nazwa klasy bazowej – w tym wypadku Na powyższym przykładzie widać, iż de-
ce wspomnianego języka C. Mamy więc do NSObject. Nawiasy klamrowe określają ob- klaracja argumentu składa się z jego typu
czynienia z funkcją main zwracającą wartość szar, który pozwala na deklarację pól kla- (zawartego w nawiasach – w przykładzie
typu int i przyjmującą dwa parametry po- sy, które domyślnie są polami chronionymi wskaźnik na typ NSString) oraz jego na-
zwalające na dostęp do argumentów przeka- (atrybut @protected). zwy. Sam argument jest oddzielony od na-
zanych z linii poleceń. Kolejna linia jest od- Poza nawiasami klamrowymi przewi- zwy funkcji dwukropkiem. Pozostaje tyl-
powiedzialna za rezerwację pamięci tworzo- dziano miejsce na deklarację metod klasy. ko przedstawić deklarację funkcji wieloar-
nych od tej pory obiektów. W tym momen- Znak - określa iż metoda jest metodą in- gumentowej, która powstaje w analogicz-
cie dochodzimy do sedna prezentowanej stancyjną. Wykorzystanie znaku + pozwo- ny sposób:
aplikacji, czyli wyświetlenia na wyjściu stan- liłoby oznaczyć metodę jako statyczną.
dardowym komunikatu Hello World. W tym Następnie w nawiasach podany został typ - (int) sum: (int)a with: (int)b;
celu użyta została funkcja NSLog. Przyda zwracanej wartości. Po tym pozostaje już
nam się ona podczas prac nad praktycznie tylko podać nazwę metody. Warto tutaj do- Powyższej zadeklarowana metoda zwraca
każdą kolejną aplikacją. Kolejne linie są od- dać, iż w języku Objective-C wszystkie me- sumę dwóch liczb całkowitych. Warto tu-
powiedzialne za zwolnienie pamięci i zwró- tody są publiczne. taj zauważyć, iż język Objective-C stosuje
cenie odpowiedniej wartości. Na zakończenie deklaracji klasy wystar- nazwane argumenty. Pozwala to na czytel-
Po tym lekko przydługim wstępie pozo- czy wpisać słowo kluczowe @end. Niestety niejsze przedstawienie działania metody
staje tylko uruchomienie opisanego pro- taka deklaracja klasy mało przypomina to, za pomocą samego nagłówka, jednak spra-
gramu. Możemy tego dokonać za pomocą z czym można się spotkać w innych języ- wia, iż zagnieżdżone wywołania metod
przycisku znajdującego się na pasku narzę- kach programowania. Jednak zapewniam, mogą stać się prawdziwym utrapieniem
dziowym lub wybierając menu Build>Bu- że po krótkim czasie stanie się to natural- dla programisty chcącego utrzymać swój
ild and Go (Run). Aby zobaczyć wiado- ne i zrozumienie takiego kodu stanie się kod w ryzach.
mość, jaką nasza aplikacja wysłała w świat, proste. Wywołanie prostej metody odbywa się w
należy otworzyć okno konsoli (menu Ru- Pora teraz przejść do implementacji kla- prosty sposób, który niestety ponownie jest
n>Console). sy – Listing 4. Zadeklarowana wcześniej unikalny dla języka Objective-C:
Wiemy już, że deklarowanie i wywoły- klasa zawiera tylko jedną metodę, więc
wanie funkcji jest dokładnie takie samo jak przedstawiony kod powinien być w mia- [stud displayName];
mechanizm znany nam z języka C. Jednak rę zrozumiały. W pierwszej kolejności na-
pora przesunąć się bliżej w stronę obiekto- leży za pomocą dyrektywy #import dołą- Pomiędzy nawiasami kwadratowymi na-
wości, która przecież znalazła swoje miej- czyć odpowiedni nagłówek. Słowo kluczo- leży w pierwszej kolejności podać nazwę
sce w nazwie omawianego języka progra- we @implementation jest tutaj naturalnym utworzonego wcześniej obiektu, a następ-
mowania. Dodatkowo, warto wyjaśnić, iż odzwierciedleniem słowa @implementation nie nazwę wywoływanej metody. Gdy-
podobnie jak w języku C++ nagłówek kla- z nagłówka klasy. Implementacja kolejnych by displayName była metodą statycz-
ną (dla przypomnienia – oznaczona zna-
kiem +), jej wywołanie miałoby następu-
jącą formę:

[Student displayName];

Jak widać, nazwa obiektu została zastąpiona


odpowiednią nazwą klasy. Wywołanie me-
tod przyjmujących parametry odbywa się w
analogiczny sposób:

[stud displayText:@”Hello World”];

Korzystanie z metod zwracających wartość


już nie powinno być zaskoczeniem:

Rysunek 3. Uruchomiona aplikacja cocos2d int c = [stud sum:3 with:5];

8 02/2010
Programowanie gier pod iPhone

Powyższy wstęp stanowi tylko niewielki uła- iphone, jest tworzenie menu gry. W poniż- składające się z kilku prostych ekranów. Na
mek wiedzy niezbędnej do świadomego ko- szym przykładzie zostanie stworzone menu początek zajmiemy się menu głównym, któ-
rzystania z właściwości języka Objective-C.
Pominięte zostały tutaj tak ważne elemen- Listing 5. Plik CocosGameAppDelegate.m
ty jak chociażby zarządzanie pamięcią. Oso-
by chcące zgłębić tę wiedzę zapraszam do #import "CocosGameAppDelegate.h"
skorzystania z materiałów wymienionych #import "cocos2d.h"
w ramce. #import "HelloWorldScene.h"
@implementation CocosGameAppDelegate
Witaj świecie po raz drugi @synthesize window;
Tym razem pora na pierwszy przykład wy- - (void) applicationDidFinishLaunching:(UIApplication*)application
korzystania biblioteki cocos2d-iphone. Jeże- {
li instalacja szablonu projektu powiodła się, // Init the window
wystarczy z menu File > New Project… wybrać window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
odpowiednią pozycję (Rysunek 2) i nadać na- // cocos2d will inherit these values
zwę CocosGame. W wyniku tych działań po- [window setUserInteractionEnabled:YES];
wstanie kompletny projekt zawierający źró- [window setMultipleTouchEnabled:YES];
dła biblioteki oraz prostą aplikację wyświe- // must be called before any othe call to the director
tlającą komunikat tekstowy na ekranie tele- // WARNING: FastDirector doesn't interact well with UIKit controls
fonu (Rysunek 3). // [Director useFastDirector];
Warto przeanalizować plik CocosGame- // before creating any layer, set the landscape mode
AppDelegate.m przedstawiony na Listin- [[Director sharedDirector] setDeviceOrientation: CCDeviceOrientationLandscapeLeft];
gu 5. Zawiera on automatycznie wyge- [[Director sharedDirector] setAnimationInterval:1.0/60];
nerowany kod odpowiedzialny za inicja- [[Director sharedDirector] setDisplayFPS:YES];
lizację gry. Na początek dokonamy zmia- // Default texture format for PNG/BMP/TIFF/JPEG/GIF images
ny orientacji ekranu z poziomej na piono- // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
wą. W tym celu należy zlokalizować nastę- // You can change anytime.
pującą linię: [Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
// create an openGL view inside a window
[[Director sharedDirector] [[Director sharedDirector] attachInView:window];
setDeviceOrientation:CCDeviceOrientation [window makeKeyAndVisible];
LandscapeLeft];
[[Director sharedDirector] runWithScene: [HelloWorld scene]];
I dokonać jej zamiany na: }

[[Director sharedDirector] - (void)applicationWillResignActive:(UIApplication *)application {


setDeviceOrientation:CCDeviceOrientat [[Director sharedDirector] pause];
ionPortrait]; }

Kolejna linia, na którą warto zwrócić uwagę, - (void)applicationDidBecomeActive:(UIApplication *)application {


to ta odpowiedzialna za wyświetlanie liczni- [[Director sharedDirector] resume];
ka klatek na sekundę. Jego wyłączenia moż- }
na dokonać, komentując linię:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[Director sharedDirector] setDisplayFPS: [[TextureMgr sharedTextureMgr] removeAllTextures];
YES]; }

Cocos2d tak jak każda biblioteka tego typu - (void)applicationWillTerminate:(UIApplication *)application {


narzuca pewną filozofię podziału aplikacji. [[Director sharedDirector] end];
W tym przypadku najważniejsze elemen- }
ty to sceny (klasa Scene) i warstwy (kla-
sa Layer), przy czym użytkownik ma peł- - (void)applicationSignificantTimeChange:(UIApplication *)application {
ną dowolność w interpretacji zakresu tych [[Director sharedDirector] setNextDeltaTimeZero:YES];
bytów. Proponuję scenę rozważać jako poje- }
dynczy ekran, taki jak menu główne, ekran
gry itp. Każda scena może zawierać dowol- - (void)dealloc {
ną liczbę warstw. Tworzenie własnych scen [[Director sharedDirector] release];
i warstw odbywa się poprzez dziedziczenie [window release];
z odpowiednich klas. [super dealloc];
}
Tworzenie prostego menu
Jednym z zadań, które można realizować bar- @end
dzo szybko za pomocą biblioteki cocos2d-

www.sdjournal.org 9
Biblioteka Miesiąca

re zawiera trzy przyciski. W tym celu należy ra dziedziczy z klasy Scene (Listing 6). Składa • init– jest odpowiedzialna za inicjaliza-
utworzyć nową klasę o nazwie MainMenu, któ- się ona z czterech metod: cję sceny, w tym przypadku utworzenie
trzech przycisków i ich wyświetlenie na
Listing 6. MainMenu.h ekranie;
• onPlayItem, onHelpItem, onAboutItem
#import "cocos2d.h" – metody zostaną automatycznie wy-
@interface MainMenu : Scene wołane w przypadku wciśnięcia odpo-
{ wiedniego przycisku przez użytkow-
} nika.
- (id) init;
- (void) onPlayItem: (id)sender; Podczas tworzenia menu wykorzystywa-
- (void) onHelpItem: (id)sender; na jest przede wszystkim klasa Menu odpo-
- (void) onAboutItem: (id)sender; wiedzialna za zarządzanie przyciskami, wy-
@end świetlanie ich w odpowiedniej kolejności
oraz automatyczne pozycjonowanie. Na po-
Listing 7. Plik MainMenu.m czątek jednak należy utworzyć przyciski.
#import "MainMenu.h" W tym celu wykorzystana zostanie klasa
#import "Game.h" MenuItemFont reprezentująca proste przyci-
#import "HelpMenu.h" ski tekstowe:
#import "AboutMenu.h"
MenuItem* planitem = [MenuItemFont
@implementation MainMenu itemFromString:@”Play” target:
self selector:@selector
- (id) init (onPlayItem:)];
{
self = [super init]; Pierwszy z argumentów określa etykie-
if ( self != nil ) tę przycisku, natomiast drugi określa
{ obiekt, do którego zostanie wysłana in-
MenuItem* playItem = [MenuItemFont itemFromString:@"Play" target:self formacja o jego wciśnięciu. Ostatni argu-
selector:@selector(onPlayItem:)]; ment definiuje metodę obsługi tego zda-
MenuItem* helpItem = [MenuItemFont itemFromString:@"Help" target:self rzenia.
selector:@selector(onHelpItem:)]; Po zdefiniowaniu kilku przycisków, można
MenuItem* aboutItem = [MenuItemFont itemFromString:@"About" target:self przystąpić do utworzenia kompletnego me-
selector:@selector(onAboutItem:)]; nu. W tym celu należy wykorzystać metodę
menuWithItems:
Menu* menu = [Menu menuWithItems:playItem, helpItem, aboutItem, nil];
[menu alignItemsVertically]; Menu* menu = [Menu menuWithItems:
[self addChild:menu]; playItem, helpItem,
} aboutItem, nil];

return self; Klasa Menu pozwala również na auto-


} matyczne rozmieszczenie przycisków na
ekranie. W tym przypadku przyciski zo-
- (void) onPlayItem: (id) sender staną ułożone w jednej pionowej kolum-
{ nie:
[[Director sharedDirector] replaceScene:[RotoZoomTransition
transitionWithDuration:1.0 scene:[Game node]]]; [menu alignItemsVertically];
}
Kompletna implementacja klasy MainMenu
- (void) onHelpItem: (id) sender została przedstawiona na Listingu 7. Imple-
{ mentacja metod odpowiedzialnych za obsłu-
[[Director sharedDirector] replaceScene:[RotoZoomTransition gę zdarzeń związanych z przyciskami menu
transitionWithDuration:1.0 scene:[HelpMenu node]]]; zostanie omówiona w dalszej cześci artyku-
} łu. Aby przetestować nową scenę, należy w
pliku CocosGameAppDelegate.m dodać na-
- (void) onAboutItem: (id) sender główek:
{
[[Director sharedDirector] replaceScene:[RotoZoomTransition #import "MainMenu.h"
transitionWithDuration:1.0 scene:[AboutMenu node]]];
} Następnie po zlokalizowaniu linii:

@end [[Director sharedDirector] runWithScene:


[MainMenu scene]];

10 02/2010
Programowanie gier pod iPhone

Należy dokonać jej zmiany na następującą: W taki sposób zakończyliśmy proces two- Kółko i Krzyżyk
rzenia menu, które mimo swojej prostoty Jak wskazuje tytuł paragrafu, naszym ce-
[[Director sharedDirector] runWithScene: jest w pełni funkcjonalne. Nie pozostaje nic lem będzie stworzenie mobilnej wersji kla-
[MainMenu node]]; innego jak przejść do sedna artykułu – two- sycznej gry Kółko i Krzyżyk (Rysunek 5).
rzenia prostej gry. Skupimy się jednak na aspektach związa-
W ten sposób poinformowaliśmy bibliote-
kę cocos2d, że pierwszą sceną aplikacji jest Listing 8. Plik AboutMenu.h
menu główne reprezentowane przez klasę
MainMenu. Uruchomiona aplikacja zosta- #import "cocos2d.h"
ła przedstawiona na Rysunku 4.
Implementacja kolejnych ekranów została @interface AboutMenu : Scene
przedstawiona na Listingach 8-11. Ze wzglę- {
du na ich podobieństwo do menu głównego }
nie będą one dokładniej omawiane.
Mając trzy ekrany menu, możemy doko- - (id) init;
nać ich połączenia. W tym celu należy w me- - (void) onBackItem: (id)sender;
todach obsługi zdarzeń dla przycisków doko-
nać zamiany aktualnie wyświetlanej sceny na @end
tą wybraną przez użytkownika:
Listing 9. Plik AboutMenu.m
[[Director sharedDirector] replaceScene:
[AboutMenu node]]; #import "AboutMenu.h"
#import "MainMenu.h"
Powyższa linia wyświetli na ekranie telefo-
nu scenę reprezentującą ekran informacji o @implementation AboutMenu
aplikacji. W tym miejscu warto skorzystać
z kolejnej ciekawej możliwości oferowanej - (id) init
przez omawianą bibliotekę. Chodzi o możli- {
wość użycia efektów przejścia pomiędzy sce- self = [super init];
nami. Wszystkie klasy z tym związane moż- if ( self != nil )
na znaleźć w pliku Transitions.h. Poniższy {
przykład wykorzystuje efekt szybkiego ob- MenuItem* backItem = [MenuItemFont itemFromString:@"Back" target:self
racania ekranu wraz ze skalowaniem, która selector:@selector(onBackItem:)];
trwa przez jedną sekundę:
Menu* menu = [Menu menuWithItems:backItem, nil];
[[Director sharedDirector] replaceScene: [menu alignItemsVertically];
[RotoZoomTransition transitionWithDuration: [self addChild:menu];
1.0 scene:[AboutMenu node]]]; }

return self;
}

- (void) onBackItem: (id) sender


{
[[Director sharedDirector] replaceScene:[RotoZoomTransition
transitionWithDuration:1.0 scene:[MainMenu node]]];
}

@end

Listing 10. Plik HelpMenu.h

#import "cocos2d.h"

@interface HelpMenu : Scene


{
}

- (id) init;
- (void) onBackItem: (id)sender;

@end
Rysunek 4. Widok prostego menu

www.sdjournal.org 11
Biblioteka Miesiąca

nych z wykorzystaniem biblioteki cocos2d aplikacji, należy je umeścić w katalogu Reso- go MarkType pozwalającego na określenie każ-
i w pełni świadomie zostaną pominięte ta- urces widocznego w panelu znajdującego się dego z tych stanów.
kie elementy jak opracowanie algorytmów po lewej stronie okna edytora XCode. Podstawowym obiektem wykorzysty-
sztucznej inteligencji, które mogłyby za- W grze kółko i krzyżyk mamy do czynie- wanym w grze będzie pole gry reprezento-
ciemnić główną treść. nia z polem gry w rozmiarze 3x3, przy czym wanie przez klasę BoardField. Jej interfejs
Na początek potrzebne są trzy pliki graficz- każde z nich może być w jednym z trzech sta- wraz z definicją opisanego wcześniej wyli-
ne w formacie PNG przedstawiające odpo- nów: puste, oznaczone krzyżykiem lub ozna- czenia został przedstawiony na Listingu 12.
wiednio pojedyncze pole gry, kółko oraz krzy- czone kółkiem. Dlatego też pierwszym kro- Warto zwrócić uwagę na deklarację interfej-
żyk. Aby możliwe było ich wykorzystanie w kiem będzie utworzenie typu wyliczeniowe- su TargetedTouchDelegate. Jest on dostar-
czany przez bibliotekę cocos2d i ułatwia ob-
Listing 11. Plik HelpMenu.m sługiwanie zdarzeń związanych z interfej-
sem dotykowym na poziomie pojedyncze-
#import "HelpMenu.h" go obiektu graficznego (w naszym przypad-
#import "MainMenu.h" ku pola gry). Klasa BoardField będzie im-
plementować dwie z czterech udostępnia-
@implementation HelpMenu nych metod.
Pierwsza metoda ccTouchBegan jest wy-
- (id) init woływana za każdym razem, gdy aplikacja
{ otrzyma informacje o nowym dotknięciu
self = [super init]; ekranu urządzenia przez użytkownika. Ko-
if ( self != nil ) rzystając z otrzymanych danych na temat
{ pozycji, należy dokonać decyzji, czy zda-
MenuItem* backItem = [MenuItemFont itemFromString:@"Back" target:self rzenie to powinno zostać przechwycone i
selector:@selector(onBackItem:)]; zwrócić wartość logiczną YES lub NO. Po-
zwala to na uniknięcie konieczności imple-
Menu* menu = [Menu menuWithItems:backItem, nil]; mentacji często skomplikowanych i podat-
[menu alignItemsVertically]; nych na błędy, algorytmów śledzących po-
[self addChild:menu]; szczególne ruchy. Interfejs multitouch do-
} stępny w urządzeniu jest bardzo wygodny
dla użytkownika, ale przeciętnego progra-
return self; mistę może przyprawić o ból głowy. Dlate-
} go też warto korzystać z ułatwień , jakie w
tej dziedzinie zostały udostępnione przez
- (void) onBackItem: (id) sender bibliotekę cocos2d.
{ Drugą metodą implementowaną przez
[[Director sharedDirector] replaceScene:[RotoZoomTransition opisywaną klasę jest ccTouchEnded, której
transitionWithDuration:1.0 scene:[MainMenu node]]]; nazwa jednoznacznie wskazuje, iż jest wy-
} woływana w momencie zakończenia poje-
dynczego ruchu na ekranie. Jednak w tym
@end

Listing 12. Plik BoardField.h


#import "cocos2d.h"

typedef enum
{
MarkTypeNone,
MarkTypeCross,
MarkTypeCircle
} MarkType;

@interface BoardField : TextureNode <TargetedTouchDelegate>


{
MarkType mark;
}

@property (assign) MarkType mark;

+ (id)itemWithTexture:(Texture2D *)texture;
- (id)initWithTexture:(Texture2D *)texture;

@end
Rysunek 5. Widok gry

12 02/2010
Programowanie gier pod iPhone

wypadku nie jest konieczne sprawdzanie,


czy otrzymaliśmy zdarzenie związane z do- Listing 13. Plik BoardField.m
tykiem, który jest powiązany z obiektem. #import "BoardField.h"
Otrzymamy informację o takim zdarzeniu
tylko wtedy, gdy metoda ccTouchBegan @implementation BoardField
zwróci wartość YES. Na początku może
się to wydawać nieco zagmatwane, jednak @synthesize mark;
kompletny kod źródłowy opisywanej klasy
przedstawiony na Listingach 12 i 13 powi- + (id)itemWithTexture:(Texture2D *)texture
nien wszystko wyjaśnić. {
Warto przy tym zwrócić uwagę na meto- return [[[self alloc] initWithTexture:texture] autorelease];
dy onEnter i onExit. Są one wywoływane w }
momencie, gdy obiekt klasy dziedziczącej
po klasie CocosNode (lub jej pochodnej) zo- - (id)initWithTexture:(Texture2D *)texture
stanie dodany lub usunięty ze sceny. W na- {
szym przypadku zostały one wykorzystane self = [super init];
w celu uruchomienia mechanizmu śledze- if ( self )
nia zdarzeń związanych z interfejsem doty- {
kowym. self.texture = texture;
Krótkiego wyjaśnienia może wymagać mark = MarkTypeNone;
implementacja opisanej wcześniej meto- }
dy ccTouchBegan. W pierwszej kolejności
sprawdza ona, czy pole nie zostało już wcze- return self;
śniej zaznaczone. Jeżeli jest ono puste, na- }
leży na podstawie współrzędnych określić,
czy właśnie to pole zostało dotknięte przez - (void)onEnter
użytkownika. Jeżeli oba powyższe warun- {
ki są spełnione, wystarczy zwrócić wartość [[TouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0
YES, aby poinformować, iż zdarzenie zwią- swallowsTouches:YES];
zane z tym konkretnym dotknięciem zo- [super onEnter];
stało na stałe powiązane z rozpatrywanym }
obiektem.
Dziedziczenie z klasy TextureNode zwal- - (void)onExit
nia programistę z konieczności ręcznego {
renderowania obiektu na ekranie. Należy je- [[TouchDispatcher sharedDispatcher] removeDelegate:self];
dynie dostarczyć teksturę, która ma poja- [super onExit];
wić się na ekranie urządzenia. Zajmuje się }
tym metoda iniWithTexture, która jest od-
powiedzialna za inicjalizację obiektu kla- - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
sy BoardField. Bliźniacza metoda statyczna {
itemWithTexture upraszcza proces tworze- if ( mark != MarkTypeNone )
nia obiektu. {
Klasa BoardField wykorzystuje prosty, return NO;
ale ogromnie przydatny mechanizm powia- }
domień, który jest udostępniany przez bi-
bliotekę Cocoa. Jego sercem, a jednocześnie CGSize size = [self.texture contentSize];
samowystarczalnym elementem jest klasa CGRect rect = CGRectMake( -size.width/2, -size.height/2, size.width, size.height );
NSNotificationCenter udostępniana w for- if ( !CGRectContainsPoint( rect, [self convertTouchToNodeSpaceAR:touch] ) )
mie singletonu. W celu wysłania do wszyst- {
kich nasłuchujących obiektów, informacji o return NO;
zaistnieniu jakiegoś zdarzenia (identyfikowa- }
nego za pomocą nazwy) wystarczy wywołać
metodę postNotificationName z odpowied- return YES;
nimi parametrami. Przykład jej użycia przed- }
stawia metoda ccTouchEnded, która infor-
muje o zaznaczeniu danego pola przez użyt- - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
kownika. {
[[NSNotificationCenter defaultCenter] postNotificationName:@"BoardFieldTouch"
Silnik gry object:self];
Możliwe, że w przypadku gry w kółko i }
krzyżyk określenie silnik gry jest lekką
przesadą, jednak posłużymy się nim z bra- @end
ku lepszej alternatywy. Zostanie on zawar-

www.sdjournal.org 13
Biblioteka Miesiąca

Listing 14. Plik Game.h

#import "cocos2d.h" -(void) fieldTouched:(NSNotification*)notification;


#import "BoardField.h" -(void) opponentTurn;
@interface Game : Scene <UIAlertViewDelegate> -(BOOL) checkBoard:(MarkType)mark;
{ -(void) markField:(BoardField*)field mark:(MarkType)mark;
NSMutableArray* fields; -(void) markRandomField:(MarkType)mark;
int fieldsCounter; -(void) displayMessage:(NSString*)message;
} @end

Listing 15. Plik Game.m

#import "Game.h" {
#import "MainMenu.h" [fields release];
#include <stdlib.h> [super dealloc];
@implementation Game }
-(id) init -(void) fieldTouched:(NSNotification*)notification
{ {
self = [super init]; fieldsCounter++;
if( self ) // Mark touched board field
{ BoardField* field = [notification object];
// Reset marked fields counter [self markField:field mark:MarkTypeCross];
fieldsCounter = 0; // Check if player has won
// Load board field texture if ( [self checkBoard:MarkTypeCross] )
Texture2D* fieldTexture = [[TextureMgr {
sharedTextureMgr] addImage:@"ttt- [self displayMessage:@"You won the game!"];
field.png"]; }
// Calculate position of top-left board field else if ( fieldsCounter == 3*3 )
CGSize displaySize = [[Director sharedDirector] {
winSize]; [self displayMessage:@"Tie!"];
float x = ( displaySize.width - 2*fieldTexture.contentS }
ize.width )/2.0f; else
float y = displaySize.height - ( displaySize.height {
- 2*fieldTexture.contentSize.height id delay = [DelayTime actionWithDuration:0.5];
)/2.0f; id call = [CallFunc actionWithTarget:self selector:
// Create game board @selector(opponentTurn)];
fields = [[NSMutableArray alloc] initWithCapacity:3]; id sequence = [Sequence actions:delay, call, nil];
for ( int i = 0; i < 3; ++i ) [self runAction:sequence];
{ }
NSMutableArray* column = [NSMutableArray }
arrayWithCapacity:3]; -(void) opponentTurn
[fields addObject:column]; {
for ( int j = 0; j < 3; ++j ) fieldsCounter++;
{ // Mark random field
BoardField* field = [BoardField itemWithTexture: [self markRandomField:MarkTypeCircle];
fieldTexture]; // Check if player has lost the game
field.position = CGPointMake( if ( [self checkBoard:MarkTypeCircle] )
x + i*fieldTexture.contentSize.width, {
y - j*fieldTexture.contentSize.height [self displayMessage:@"You have lost!"];
); }
[self addChild: field]; }
[column addObject: field]; - (BOOL) checkBoard:(MarkType)mark
} {
} int i, j;
// Listen for board fields touch notifications // Check columns
[[NSNotificationCenter defaultCenter] addObserver: for ( i = 0; i < 3; ++i )
self selector:@selector(fieldTouched:) {
name:@"BoardFieldTouch" object:nil]; for ( j = 0; j < 3; j++ )
} {
return self; BoardField* field = [[fields objectAtIndex:i]
} objectAtIndex:j];
- (void) dealloc if ( field.mark != mark )

14 02/2010
Programowanie gier pod iPhone

Listing 15. Plik Game.m

{ Texture2D* texture = NULL;


break; if ( mark == MarkTypeCircle )
} {
} texture = [[TextureMgr sharedTextureMgr] addImage:
if ( j == 3 ) @"ttt-circle.png"];
{ }
return YES; else if ( mark == MarkTypeCross )
} {
} texture = [[TextureMgr sharedTextureMgr] addImage:
// Check rows @"ttt-cross.png"];
for ( i = 0; i < 3; ++i ) }
{ else
for ( j = 0; j < 3; j++ ) {
{ return;
BoardField* field = [[fields objectAtIndex:j] }
objectAtIndex:i]; TextureNode* node = [TextureNode node];
if ( field.mark != mark ) node.texture = texture;
{ CGSize size = [field contentSize];
break; node.position = CGPointMake( size.width/2, size.height/2 );
} [field addChild:node];
} id fadeIn = [FadeIn actionWithDuration:0.75];
if ( j == 3 ) [node runAction:fadeIn];
{ }
return YES; -(void) markRandomField:(MarkType)mark
} {
} BoardField* field = NULL;
// Check diagonally from top-left to bottom-right corner while ( !field || field.mark != MarkTypeNone )
for ( i = 0; i < 3; i++ ) {
{ int index = arc4random()%(3*3);
BoardField* field = [[fields objectAtIndex:i] int column = index/3;
objectAtIndex:i]; int row = index%3;
if ( field.mark != mark ) field = [[fields objectAtIndex:column] objectAtIndex:row];
{ }
break; [self markField:field mark:mark];
} }
} -(void) displayMessage:(NSString*)message
{
if ( i == 3 ) [[Director sharedDirector] pause];
{ UIAlertView* dialog = [[UIAlertView alloc] init];
return YES; [dialog setDelegate:self];
} [dialog setTitle:@"Game Over"];
// Check diagonally from bottom-left to top-right corner [dialog setMessage:message];
for ( i = 0; i < 3; i++ ) [dialog addButtonWithTitle:@"OK"];
{ [dialog show];
BoardField* field = [[fields objectAtIndex:2-i] [dialog release];
objectAtIndex:i]; }
if ( field.mark != mark ) -(void) alertView:(UIAlertView *)alert clickedButtonAtIndex:
{ (NSInteger)buttonIndex
break; {
} [[Director sharedDirector] resume];
} // Return to main menu
if ( i == 3 ) [[Director sharedDirector] replaceScene:
{ [RotoZoomTransition
return YES; transitionWithDuration:1.0 scene:
} [MainMenu node]]];
return NO; }
} @end
-(void) markField:(BoardField*)field mark:(MarkType)mark
{
field.mark = mark;

www.sdjournal.org 15
Biblioteka Miesiąca

ty w klasie GameScene reprezentującej po- ekranie. W metodzie tej kolejny raz pojawia projektu. Wystarczy otworzyć go za pomo-
jedynczą rozgrywkę przedstawionej na Li- się klasa NSNotificationCenter. Do tej po- cą edytora XCode i uruchomić w symula-
stingach 14 i 15. W związku z prostotą opi- ry wykorzystaliśmy ją tylko w celu wysyła- torze. Warto bliżej przyjrzeć się samej bi-
sywanej gry nie jest ona zbyt złożona, jed- nia informacji o zdarzeniach. W tym miej- bliotece cocos2d-iphone i poeksperymen-
nak warto opisać kilka kluczowych ele- scu rejestrujemy metodę fieldTouched, tować z utworzoną aplikacją. A jeżeli uda
mentów. . która posłuży do ich obsługi. Jej działanie się stworzyć coś ciekawego, nie pozosta-
Klasa GameScene zawiera tylko dwa po- jest dosyć oczywiste - dokonuje ona za- je nic innego jak pochwalenie się naszymi
la. Pierwsze z nich opatrzone nazwą fields znaczenia dotkniętego pola, a następnie umiejętnościami poprzez umieszczenie gry
przechowuje w tablicy wszystkie obiek- sprawdza, czy użytkownik zapewnił sobie w AppStore.
ty reprezentujące pojedyncze pola gry. tym ruchem zwycięstwo lub remis. Jeżeli
NSMutableArray jest kontenerem udostęp- nie, wykonywany jest ruch przeciwnika. Podsumowanie
nianym przez bibliotekę Cocoa i pozwala na Jak wspomniałem we wstępie, nie będzie- Niestety zarówno sam temat tworzenia
przechowywanie obiektów dowolnego typu. my zajmować się opracowaniem algorytmu gier, jak i zakres możliwości oferowanych
Drugie pole będzie wykorzystywane w celu sztucznej inteligencji. Dlatego też przeciw- przez bibliotekę cocos2d stanowczo wy-
śledzenia liczby zaznaczonych pól. Informa- nik gracza zachowuje się dosyć nieprzewi- kracza poza zakres jednego artykułu. Mam
cja ta pozwoli na wykrycie zakończenia gry w dywanie, a wynika to z prostego faktu za- jednak nadzieję, że udało mi się przybli-
przypadku remisu. znaczania losowego pola gry. żyć podstawowe zagadnienia związane z
Przegląd silnika gry rozpoczniemy od Przy okazji metody markField odpowie- tym jakże emocjonującym zajęciem. Osoby
jego inicjalizacji, która odbywa się w meto- dzialnej za załadowanie odpowiedniej tek- chcące rozwinąć swoją wiedzę odsyłam do
dzie init. Pierwszą czynnością, jaką należy stury i zaznaczenie pola kółkiem lub krzy- ramki zawierającej adresy najważniejszych
wykonać, jest załadowanie tekstury pustego żykiem, warto zwrócić uwagę na wykorzy- stron internetowych.
pola gry. W dalszej części metody wykorzy- stanie mechanizmu akcji. Jest on udostęp- Na sam koniec warto wspomnieć, że bi-
stana ona jest podczas tworzenia obiektów niany przez bibliotekę cocos2d i pozwa- blioteka cocos2d-iphone rozpowszechniana
klasy BoardField i ich rozmieszczania na la na odtwarzanie prostych animacji. Aby jest na stosunkowo liberalnej licencji GNU
zapewnić płynne pojawienie się zaznacze- Lesser General Public License, co pozwala na
nia na dotkniętym polu, użyta została ak- bezpieczne wykorzystywanie jej w komercyj-
cja FadeIn. Jednak możliwości udostępnia- nych projektach.
ne przez ten mechanizm są znacznie więk-
sze. Warto spojrzeć do dokumentacji, aby
zapoznać się ze wszystkimi dostępnymi ak-
cjami. Zapewniam, że samo eksperymento-
wanie z nimi może przynieść dużo satys-
fakcji, a otrzymane efekty często przerasta- JAKUB WĘGRZYN
ją oczekiwania. Pracuje na stanowisku Starszego Programi-
Na koniec każdej gry należy poinformować sty Gier Natywnych w firmie Gamelion, wcho-
gracza o jego rezultatach. W przypadku na- dzącej w skład Grupy BLStream. Jakub specja-
szej gry może to być zwycięstwo, przegrana lizuje się w technologiach związanych z pro-
lub remis. W tym celu wykorzystany zosta- dukcją oprogramowania na platformy mobil-
nie natywny interfejs użytkownika systemu, ne, ze szczególnym naciskiem na tworzenie
a dokładniej okienko UIAlertView (Rysunek gier. Grupa BLStream powstała, by efektyw-
6). Metoda displayMessage prezentuje spo- niej wykorzystywać potencjał dwóch szybko
sób jego inicjalizacji w kilku linijkach kodu, rozwijających się producentów oprogramowa-
które można streścić jako utwórz, nazwij, do- nia – BLStream i Gamelion. Firmy wchodzące
daj przyciski i pokaż. w skład grupy specjalizują się w wytwarzaniu
Na tym kończy się proces tworzenia gry. oprogramowania dla klientów korporacyjnych,
Zainteresowane osoby odsyłam do płyty w rozwiązaniach mobilnych oraz produkcji i te-
dołączonej do numeru, na której znajdu- stowaniu gier.
Rysunek 6. Widok gry ją się kompletne źródła gry wraz z plikiem Kontakt z autorem: jakub.wegrzyn@game-lion.com

W Sieci
• http://www.cocos2d-iphone.org/ – cocos2d for iPhone;
• http://lethain.com/entry/2008/oct/03/notes-on-cocos2d-iphone-development/ – Notes on Cocos2d iPhone Development;
• http://www.cocoadevcentral.com/d/learn_objectivec/ – Cocoa Dev Central: Learn Objective-C;
• http://developer.apple.com/iphone/ – iPhone Dev Center.

Literatura
• Programming in Objective-C 2.0, Stephen G. Kochan, Addison Wesley;
• iPhone Games Projects, PJ Cabrera, Apress;
• Beginning iPhone Development: Exploring the iPhone SDK, Dave Mark, Jeff LaMarche, Apress.

16 02/2010
Opis DVD

Kurs Video Programowanie w języku Java słonie zademonstrować przekazywanie parametrów i generowanie
odpowiedzi z ich użyciem.
Od Witaj świecie do aplikacji korporacyjnych. Cz.V Jednym z podstawowych mechanizmów, który umożliwia prze-
Aplikacje internetowe - Serwlety chowywanie stanu w aplikacjach internetowych jest sesja, która
jest dostępna w serwletach. Dowiemy się, jak z użyciem Java EE
Piąty odcinek serii to krok w kierunku tworzenia aplikacji kor- zarządzać sesją w środowisku serwletów i jak generować odpowie-
poracyjnych. Tym razem zajmować się będziemy podstawowym dzi posługując się nią.
mechanizmem, stojącym u podstaw współczesnych narzędzie Ostatni element, który poznamy w tym odcinku to będzie przetwa-
do tworzenia aplikacji internetowych na platformie Java – serw- rzanie stron JSP. Dowiemy się, czemu służą strony JSP i w jakiej są
letami. relacji do serwletów oraz poznamy podstawy używania stron JSP.
Na początku dowiemy się jak wygląda typowa komunikacja z
użyciem protokołu HTTP oraz w jaki sposób serwery serwletów Kurs Video Flex – Papervision3D
czyli kontenery serwletów wpasowują się w ten model. Odc. 7 - Przez dwa odcinki zajmiemy się grafiką 3D oraz biblioteką
W kolejnych krokach dowiemy się jak przygotować środowisko, Papervision3D. Na początku stworzymy pierwszą scenę wraz z jej
które umożliwi stworzenie pierwszego serwletu. Pobierzemy i elementami oraz poznamy podstawy pv3D.
przygotujemy jeden z najpopularniejszych kontenerów – Apache Odc. 8 - Kontynuując eksperymenty z Papervision3D, zacznie-
Tomcat oraz zainstalujemy odpowiednią wersję środowiska Eclip- my ładować bardziej skomplikowane modele oraz dodamy interak-
se, przeznaczonego do tworzenia aplikacji korporacyjnych. tywność do naszej aplikacji.
Następnie stworzymy pierwszy serwlet, który dynamicznie
stworzy zawartość strony internetowej, po to by w kolejnej od- Video Kurs Quest3D - Prosta gra FPP

Jeśli nie możesz


odczytać zawartości
płyty DVD, a nie jest ona Redakcja
uszkodzona mechanicznie, nie udziela pomocy
sprawdź ją na co najmniej dwóch technicznej w instalowaniu
napędach DVD. i użytkowaniuprogramów
W razie problemów z płytą, prosimy pisać zamieszczonych na płytach DVD-ROM
pod adres: cd@software.com.pl dostarczonych razem z pismem.

17
Klub techniczny Progress Software

Technologie
Progress OpenEdge
Część 6. Obiekty ProDataSet
Progressowe obiekty typu Dataset (ProDataSet) rozszerzają możliwości
definiowania złożonych obiektów biznesowych oraz relacji między nimi.
Są bardzo ważnym elementem w procesie budowania nowoczesnych
aplikacji rozproszonych i wymiany danych z innymi aplikacjami lub ich
modułami poprzez XML.
• Obiekt ten może być automatycznie za-
Dowiesz się: Powinieneś wiedzieć: pełniany danymi, przy zachowaniu relacji
• Jakie są zastosowania obiektów ProDataSet; • Ogólne zasady manipulacji danymi. Znajo- między nimi.
• Jak się je tworzy i nimi zarządza; mość obiektów DataSet jest dodatkowym • Wszelkie modyfikacje danych w PDS, do-
• O obsłudze zdarzeń dedykowanych dla Pro- atutem. dawanie i usuwanie rekordów są automa-
DataSetu. tycznie wychwytywane.
• PDS może być przekazany jako pojedynczy
parametr między procedurami wewnątrz
Korzyści: sesji lub pomiędzy sesjami.
PDS pozwalają na zdefiniowanie struktury da- • Obsługa zdarzeń przez trygery (Callback
Poziom nych, reprezentującą wybrane tablice, niezależnie Procedures). Można dopasować obsługę
trudności od struktury zewnętrznych danych w bazie. Pod- standardowych zdarzeń lub napisać wła-
stawową korzyścią jest tutaj możliwość tworzenia sną w języku OpenEdge ABL.
logiki biznesowej i logiki interfejsu odnoszących • Obsługa mapowania danych PDS do/z pli-
się do formatu danych zawartych w strukturze ków XML.
PDS, dopasowanych do specyfiki aplikacji.

W
niniejszym odcinku zapoznamy Spośród wielu sposobów zastosowania PDS w
się z zagadnieniami definiowa- Inne korzyści to: aplikacjach, najczęściej stosowane to:
nia, zapełniania danymi, prze-
prowadzania operacji na danych dla obiek- • Dane pochodzące z różnych źródeł mogą • Zastosowanie PDS do reprezentacji złożo-
tów ProDataSet oraz ich wymianą z innymi być traktowane jako jeden obiekt. nych danych.
aplikacjami.
ProDataSet (PDS) jest obiektem utwo-
rzonym w pamięci, złożonym z tablic tym- ����������������������������������������������������������

czasowych. Dla tablic tych można opcjonal-


nie zdefiniować relacje. Ponadto PDS mo-
że być podłączony do zdefiniowanych źró-
����������������
deł danych, które odpowiadają za zapełnie-
nie obiektów informacjami. Zmiany danych �������
w ProDataSetach mogą być przesyłane z po- ��������
wrotem celem zapisania w źródłach danych.
Inaczej mówiąc, ProDataSet realizuje mapo- ����������������
wanie pomiędzy zbiorem tablic w bazie da- �����������
nych (lub innym typie źródeł danych) i ich re-
prezentacją w pamięci.
������������
Obiekty ProDataSet są definiowane nieza-
leżnie od struktury danych, którymi są zapeł-
nione. Z tego powodu przy ich pomocy moż-
na w łatwy i pewny sposób odseparować da-
ne aplikacji od specyfikacji oryginalnego źró-
dła danych. Rysunek 1. Dołączenie źródła danych do PDS

18 02/2010
Technologie Progress OpenEdge

• Tam i z powrotem, czyli przetwarzanie da- dyfikowanymi danymi (metoda GET-CHANGES). PDS umożliwia obsługę konfliktów, które mogą
nych pomiędzy sesją klienta i serwera. Zapis do bazy realizowany jest za pomocą me- wystąpić podczas zapisu realizowanego według
• Wstawienie tablic tymczasowych do PDS tody SAVE-ROW-CHANGES. Technologia zapisu strategii Optimistic Locking.
w celu wykorzystania jego zaimplemento-
wanych cech (np. obsługi zdarzeń). Listing 1. Kompletny przykład aplikacji. Pliki z definicjami

Tworzenie ProDataSetów /* Plik ttDefs.i, zawierający definicję tablic tymczasowych */


Definicja ProDataSetu (DATASET) musi być DEFINE TEMP-TABLE ttOrder NO-UNDO
poprzedzona zdefiniowaniem jednej lub kil- FIELD OrderNum AS INTEGER FORMAT "zzzzzzzzz9"
ku tablic tymczasowych (TEMP-TABLE). Na- FIELD OrderDate AS DATE FORMAT "99/99/99"
stępnym krokiem jest zdefiniowanie i podłą- FIELD ShipDate AS DATE FORMAT "99/99/99"
czenie obiektów źródeł danych (DATA-SOURCE FIELD PromiseDate AS DATE FORMAT "99/99/99"
– patrz Rysunek 1). Listing 1 pokazuje całą FIELD OrderTotal AS DECIMAL FORMAT "->,>>>,>>9.99"
aplikację, służącą do zapełnienia PDS (dsOr- INDEX OrderNum IS UNIQUE PRIMARY OrderNum.
derOrderline) złożonego z dwóch tablic tym- DEFINE TEMP-TABLE ttOrderLine NO-UNDO BEFORE-TABLE ttOrderLineBefore
czasowych (ttOrder, ttOrderLine) i relacji FIELD OrderNum AS INTEGER FORMAT "zzzzzzzzz9"
między nimi (drOrderOrderLine), do którego FIELD LineNum AS INTEGER FORMAT ">>9"
przyłączone są dwa źródła danych (srcOrder, FIELD ItemNum AS INTEGER FORMAT "zzzzzzzzz9"
srcOrderLine). Każdy bufor tablicy tymcza- FIELD Price AS DECIMAL FORMAT "->,>>>,>>9.99"
sowej może być podłączony do innego źródła FIELD Qty AS INTEGER FORMAT "->>>>9"
danych. Podczas ładowania danych brane są FIELD Discount AS INTEGER FORMAT ">>9%"
pod uwagę pola o identycznych nazwach (ta- FIELD ExtendedPrice AS DECIMAL FORMAT "->>>,>>9.99"
blica tymczasowa –> źródło danych) , a pozo- INDEX OrderNum_LineNum IS UNIQUE PRIMARY OrderNum LineNum.
stałe ignorowane. Można określić jednak wła- /* Plik dsDefs.i, zawierający definicję PDS */
sny sposób mapowania , jeśli pola mają różne DEFINE DATASET dsOrderOrderLine FOR ttOrder, ttOrderLine
nazwy, lecz odpowiadający typ i charakter da- DATA-RELATION drOrderOrderLine FOR ttOrder, ttOrderLine
nych (np.: BUFFER ttOrder:ATTACH-DATA- RELATION-FIELDS (OrderNum, OrderNum).
SOURCE(DATA-SOURCE srcOrder:HANDLE,”Cu /* Plik srcDefs.i, zawierający definicje źródeł danych*/
stomer.Name,CustName”)). DEFINE QUERY qOrder FOR Order.
Do zapełniania PDS służy metoda FILL, przy DEFINE DATA-SOURCE srcOrder FOR Order.
czym istnieje pięć trybów zapełniania. Domyśl- DEFINE DATA-SOURCE srcOrderLine FOR OrderLine.
nym MERGE polega na dodaniu rekordów do ist-
niejącego zestawu z pominięciem duplikatów.
Co ciekawe, można zapełnić nie cały PDS, lecz

wybrane tablice tymczasowe. Dopuszczalne jest

�����������������������
�������������������������
również zapełnianie z pominięciem relacji mię-
dzy tablicami. �������������
W języku Progress ABL można utworzyć Pro- ����������������������������������
DataSety także jako obiekty dynamiczne. Jest to
użyteczna technika, gdy struktura obiektu nie �������������
jest znana podczas kompilacji. Obiekty takie wy- �� � � ��

korzystuje się np. przy obsłudze WebSerwisów


lub przy realizacji zapisu zmian do bazy. Przy-
kład ilustrujący utworzenie dynamicznego PDS
�����������������������������
załączony jest na płycie CD.
��������������
Edycja �����������������������
� �� � � ��
Proces edytowania danych w PDS (patrz Rysu- � �� � � ��

nek 2) rozpoczyna się od dodania w definicji � �� � � ��

tablicy tymczasowej elementu BEFORE-TABLE � �� � � ��

(patrz Listing 1), który służy do przechowy- � �� � � ��

wania wartości przed edycją (oryginalna tabli- �����������


ca określana jest jako AFTER-TABLE). Każda ta-
blica tymczasowa posiada logiczny atrybut
TRACKING-CHANGES, którym włącza się proces Rysunek 2. Proces edycji danych
śledzenia zmian w tablicy BEFORE i AFTER.
W większości przypadków edytowane są tyl-
ko wybrane rekordy. Aby nie obciążać niepo- W Sieci
trzebnie sieci, powinno się przesyłać z powro-
• http://communities.progress.com/pcom/community/psdn/openedge – Progress Software Deve-
tem do serwera bazy tylko te zmodyfikowane
lopers Network, część ukierunkowana na zagadnienia techniczne związane z OpenEdge®;
dane. W tym celu tworzy się dynamiczny PDS • http://web.progress.com – strona Progress Software Corporation;
o strukturze identycznej jak oryginalny obiekt • http://www.progress.com/pl – strona Progress Software sp z o.o.
(metoda CREATE -LIKE) i zapełnia się go zmo-

www.sdjournal.org 19
Klub techniczny Progress Software

Obsługa zdarzeń • zapytanie: QUERY-OFF-END znaleźć pod podanymi poniżej odnośnikami.


Do obsługi zdarzeń służą procedury typu Cal- Niniejszym odcinkiem kończę serię sześciu ar-
lback Procedure, uruchamiane automatycznie, Aby zdefiniować obsługę, należy (patrz Li- tykułów poświęconych technologiom Progress
gdy zachodzi zdarzenie na wybranym obiekcie. sting 2): OpenEdge. Ciekawych tematów z tego zakresu
Niektóre zdarzenia mają zdefiniowaną domyśl- nie brakuje, toteż mam nadzieję, że w niedale-
ną obsługę, jednakże deweloper aplikacji ma • napisać kod procedury dla obsługi zdarzenia kiej przyszłości cykl ten będzie kontynuowany.
możliwość zdefiniowania własnej obsługi. Po- • skojarzyć procedurę przy pomocy metody Dziękuję i do zobaczenia.
niżej przedstawiam typy obiektów i zdarzenia, SET-CALLBACK-PROCEDURE.
które można dla nich zdefiniować: PIOTR TUCHOLSKI
Dla osób, które chciałyby pogłębić wiedzę z te- Autor jest od 12 lat związany z technologiami Pro-
• PDS, tablica tymczasowa, bufor: BEFORE- go tematu o np. obsługę błędów i transakcji, gress Software. Wieloletni konsultant i Kierownik
FILL , AFTER-FILL mapowanie do/z plików XML (ten temat był Działu Szkoleń Progress Software sp. z o.o., specja-
• tablica tymczasowa: ROW-CREATE, ROW- poruszany w poprzednim odcinku), polecam lizujący się w technologii OpenEdge.
DELETE, ROW-UPDATE skorzystać chociażby z informacji, które można Kontakt z autorem: piotr.tt@gmail.com

Listing 1. Kompletny przykład aplikacji c.d. Procedura AllInOne.p

/* Definicje zmiennych */ ttOrder.OrderTotal WITH FRAME ttOrderFrame


DEFINE VARIABLE iCustNum AS INTEGER FORMAT ">>>>9" 1 COL TITLE "Order".
LABEL "Customer Number". FOR EACH ttOrderLine OF ttOrder:
DEFINE VARIABLE cCustName AS CHARACTER FORMAT DISPLAY ttOrderLine.OrderNum
"x(30)" LABEL "Name". ttOrderLine.LineNum
DEFINE VARIABLE hChangeDataSet AS HANDLE NO-UNDO. ttOrderLine.ItemNum
DEFINE VARIABLE hdsOrderOrderLine AS HANDLE NO-UNDO. ttOrderLine.Price
/* Pliki include z definicjami */ ttOrderLine.Qty
{ttDefs.i} ttOrderLine.Discount
{dsDefs.i} ttOrderLine.ExtendedPrice WITH FRAME
UPDATE iCustNum WITH FRAME CustFrame TITLE "Customer Lookup". ttOrderLineFrame
{srcDefs.i} 1 COL
/* Przyłączenie źródeł danych */ TITLE "Order Lines".
BUFFER ttOrder:ATTACH-DATA-SOURCE(DATA-SOURCE srcOrder: UPDATE
HANDLE,?,?). ttOrderLine.Qty
BUFFER ttOrderLine:ATTACH-DATA-SOURCE(DATA-SOURCE ttOrderLine.Discount
srcOrderLine:HANDLE,?,?). WITH FRAME ttOrderLineFrame 1 COL.
/* Przygotowanie zapytania */ END.
QUERY qOrder:QUERY-PREPARE("FOR EACH Order WHERE END.
Order.CustNum = " + STRING(iCustNum)). /* Utworzenie dynamicznego PDS: hChangeDataSet o takiej
/* Zapełnienie ProDataSetu danymi */ samej strukturze jak
DATASET dsOrderOrderLine:FILL(). dsOrderOrderLine */
/* Wyszukanie rekordu i wyświetlenie danych */ hdsOrderOrderLine = DATASET dsOrderOrderLine:HANDLE.
FIND Customer WHERE Customer.Custnum = iCustNum NO-LOCK. CREATE DATASET hChangeDataSet.
ASSIGN cCustName = Customer.NAME. hChangeDataSet:CREATE-LIKE( hdsOrderOrderLine , "cds" ).
DISPLAY cCustName WITH FRAME CustFrame. /* Process Get-Changes to extract Changes at DataSet Level */
/* Włączenie śledzenia zmian dla ttOrderLine */ hChangeDataSet:GET-CHANGES(hdsOrderOrderLine).
TEMP-TABLE ttOrderLine:TRACKING-CHANGES = TRUE. /* Wyłączenie śledzenia zmian */
/* Użytkownik może zmienić wartości Qty i Discount */ TEMP-TABLE ttOrderLine:TRACKING-CHANGES = FALSE.
FOR EACH ttOrder: /* Zapis zmian do bazy */
DISPLAY ttOrder.OrderNum FOR EACH ttOrderLineBefore TRANSACTION:
ttOrder.OrderDate BUFFER ttOrderLineBEfore:SAVE-ROW-CHANGES().
ttOrder.ShipDate END.
ttOrder.PromiseDate

Listing 2. Obsługa zdarzenia

/* Przypisanie procedury Callback do zdarzenia After-Fill DEFINE VARIABLE dOrderTotal AS DECIMAL INITIAL 0 NO-UNDO.
obiektu OrderLine */ FOR EACH ttOrderLine WHERE ttOrderline.OrderNum =
BUFFER ttOrderLine:SET-CALLBACK-PROCEDURE ttOrder.OrderNum:
("AFTER-FILL", "postOrderLineFill", THIS-PROCEDURE). dOrderTotal = dOrderTotal + ttOrderLine.ExtendedPrice.
/* Kod procedury */ END.
PROCEDURE postOrderLineFill: ttOrder.OrderTotal = dOrderTotal.
DEFINE INPUT PARAMETER DATASET FOR dsOrderOrderLine. END.

20 02/2010
Klub techniczny Adobe

Co nowego w Flex 4
Flex jest jedną z najbardziej zaawansowanych technologii do
budowania aplikacji typu RIA w bezpośrednim tłumaczeniu bogatych
aplikacji internetowych. Silnikiem wyświetlającym aplikacje Flex’owe
jest technologia Adobe Flash, która pozwala na osiągnięcie jednolitego
wyglądu uruchamianej aplikacji, niezależnie od wykorzystywanej
przeglądarki czy systemu operacyjnego.

Spark
Dowiesz się: Powinieneś wiedzieć: Flex 4 został zaprojektowany w oparciu o ideę
• Jakie są różnice pomiędzy Flex 3 a Flex 4; • Co to Flex; „Design in Mind”, której celem jest zapewnienie
• Co to FXG; • Co to architektura Halo. szybkiej i bezproblemowej współpracy progra-
• Co to Spark. misty i grafika. Aby umożliwić realizację tego
pomysłu , wprowadzono całkiem nową archi-
tekturę komponentów Spark, bazującą na do-
brze nam znanej z Flex'a 3 architekturze Halo.
Oddzielono w przejrzysty sposób wygląd kom-
tymi w pakiecie mx.*. Aby uniknąć konflik- ponentów od ich logiki, gdzie w starej architek-
tów pomiędzy tymi klasami, rozszerzono turze granica ta była często mało czytelna. Za-
Poziom przestrzenie nazw do: MXML 2006, MXML dbano również o lekkość komponentów, któ-
trudności 2009, Spark, Halo. re aktualnie nie zawierają już wszystkich zbęd-
nych elementów jak suwaki czy wirtualizację.
• MXML 2006: Przestrzeń nazw używa- Przyśpieszyło to w dużym stopniu inicjalizację
na w poprzedniej wersji. aplikacji, jak i zmniejszyło jej rozmiar.

W
niniejszym artykule postaram się • URI: http://www.adobe.com/2006/mxml
wyjaśnić najważniejsze zmiany, ja- • Domyślny prefix: mx Layout
kie zaszły w najnowszej wersji Fle- • MXML 2009: Nowa przestrzeń nazw Dużym usprawnieniem w stosunku do Ha-
x'a. Przesiadając się z Flex'a 3 na Flex'a 4 , mu- MXML-a. Nie zawiera tagów kompo- lo jest nowy sposób definiowania układu roz-
simy pamiętać przede wszystkim, że nowa bi- nentów. mieszczenia komponentów. Dla programi-
blioteka wymaga wsparcia FlashPlayer'a 10, tu- • URI: http://ns.adobe.com/mxml/2009 stów piszących w MXML-u niewiele uległo
dzież wszystkie aplikacje powinny być kompi- • Domyślny prefix: fx zmianie. Podstawowe właściwości takie jak
lowane pod najnowszą wersję FlashPlayer'a. • Spark: width, height, minWidth, explicitWidth,
Osobom , które znają poprzednią wersję Flex'a, • URI: library://ns.adobe.com/flex/spark percentWidth dalej mają to samo znacze-
nie powinna sprawić trudności migracja na 4- • Domyślny prefix: s nie. Działanie LayoutManagera, jak i pod-
tą wersję biblioteki. Doświadczymy co prawda • Halo: stawowy cykl życia komponentu także nie
mnogości zmian architektonicznych, pojawiają • URI: library://ns.adobe.com/flex/halo uległ zmianie. Metody commitProperties(),
się nowe przestrzenie nazw i odmłodzono dużą • Domyślny prefix: mx measure() i updateDisplayList() są wy-
część komponentów, jednak w większości przy- woływane przez LayoutManagera w tej sa-
padków ich interfejs udostępniony programi- Dodano również wsparcie przestrzeni nazw mej kolejności i reguły unieważniania pozo-
ście nie odbiega znacznie od interfejsu znane- dla selektorów CSS (przykład na Listingu 2). stały te same.
go z architektury Halo.
Tabela 1. Kombinacje komponentów Spark i odpowiadające im klasy z Halo
Przestrzenie nazw i pakiety Kontenery Halo Kombinacje układów z kontenerami Spark
Flex 3 wszystkie klasy biblioteki trzymał w
Canvas Group + BasicLayout
jednym pakiecie mx.*, natomiast we Flex 4
wprowadzono nowy pakiet spark.* zawiera- HBox Group + HorizontalLayout
jący komponenty, klasy bazowe, efekty, filtry, VBox Group + VerticalLayout
układy widoku, podstawowe kształty geome- Tile Group + TileLayout
tryczne, skórki i narzędzia.
List List + VerticalLayout
Wiele klas zawartych w pakiecie spark.*
współdzieli swoje nazwy z klasami zawar- TileList List + TileLayout

22 02/2010
Co nowego w Flex 4

Zasadniczymi zmianami w stosunku do kie stany w odróżnieniu od poprzedniej wersji są Component skinning
Flex 3 są: umieszczone w tablicy. Każdy komponent defi- We Flex 4 zostało mocno uproszczone tworze-
niuje własne zachowanie na zmianę stanu przy nie własnych skórek komponentów. Na Listin-
• Odseparowanie układu od kontenera po- pomocy metod includeIn oraz excludeFrom. gu 7 przedstawiono sposób tworzenia przykła-
zwoliło na zmianę rozmieszczenia kompo- Dla przypomnienia sposób deklaracji stanu we dowej skórki dla przycisku. Przede wszystkim
nentów w trakcie działania aplikacji. Zmi- Flex 3 został przestawiony na Listingu 5, nato- musimy zwrócić uwagę na deklarację czterech
nimalizowano tym samym liczbę kontene- miast nowy zapis przedstawiony na Listingu 6. stanów przycisku: up, over, down, disabled.
rów wymaganych do stworzenia zaawanso-
wanego układu rozmieszczenia i pozwoliło Listing 1. Przykład użycia przestrzeni nazw w aplikacji
na wielokrotne użycie tego samego kodu.
• Znacznie przyśpieszono i uproszczono <s:Application
tworzenie własnych układów rozmiesz- xmlns:fx="http://ns.adobe.com/mxml/2009"
czenia, odseparowując je od logiki kon- xmlns:s="library://ns.adobe.com/flex/spark"
tenerów. xmlns:mx="library://ns.adobe.com/flex/halo">
• Definiowania arbitralnych transformacji <mx:DateChooser id="main_calendar" x="20" y="20"/>
2D. <s:Button label="wyślij" x="220" y="20"/>
• Przewijanie zawartości kontenera w do- </s:Application>
wolnym kierunku piksel po pikselu.
• Transformacje 3D udostępnione przez Listing 2. Przykład użycia przestrzeni nazw z selektorami CSS
Flash Playera. <fx:Style>
• Definiowanie głębokości każdego potomka @namespace s "library://ns.adobe.com/flex/spark";
kontenera, do którego przypisano układ. @namespace mx "library://ns.adobe.com/flex/halo";
• Przypisywanie transformacji bez wpływu s|Button {
na układ komponentów. Możemy dzięki color: #FF0000;
temu animować dowolny obiekt, nie wy- }
wołując zmiany układu komponentów. mx|DateChooser {
• Wszystkie właściwości określające wy- color: #FF0000;
miary nie zmieniają się w trakcie cy- }
klu życia komponentu. Wyeliminowa- </fx:Style>
no tym samym wprawiające w zakłopo-
tanie reprezentowanie wymiarów nie- Listing 3. Przykład użycia HorizontalLayout
przeskalowanych w trakcie measure(), <s:List id="list">
natomiast już przeskalowanych w trak- <s:layout>
cie etapu updateDisplayList(); <s:HorizontalLayout gap="0" verticalAlign="justify" />
</s:layout>
Ponieważ układ rozmieszczenia odseparowano ...
od kontenera, został zmieniony sposób pracy z </s:List>
tym elementem. Przykładowo możemy użyć
HorizontalLayout w połączeniu z komponen- Listing 4. Dodanie suwaków do grupy komponentów
tem List. Ustawimy również odstępy pomię- <s:Scroller width="200">
dzy elementami na 0px i wyjustujemy. Przykła- <s:Group>
dowy kod przedstawiono na Listingu 3. <s:layout>
Tworząc kombinację grup i układów, w <s:HorizontalLayout gap="0" verticalAlign="justify" />
łatwy sposób możemy uzyskać zachowa- </s:layout>
nia kontenerów znanych z architektury Ha- <s:Button label="jeden" />
lo. Przykładowe kombinacje umieszczono w <s:Button label="dwa" />
Tabeli 1. <s:Button label="trzy" />
<s:Button label="cztery" />
Scrollbars </s:Group>
Jak już wspomniałem, architektura Spark zo- </s:Scroller>
stała mocno odchudzona. Oznacza to, że su-
waki nie są domyślnie dołączone do kontene- Listing 5. Stany we Flex 3
rów, jak to miało miejsce w Halo. Programista <mx:states>
musi sam zadecydować, czy będą one wyma- <mx:State name="submitState" basedOn="">
gane dla danej grupy obiektów, czy też kon- <mx:AddChild relativeTo="{loginForm}" >
tenera. Aby zapewnić wyświetlenie suwaków <mx:Button label="Wyślij" bottom="10" right="10"/>
dla kontenera, gdy będą potrzebne, należy </mx:AddChild>
opakować daną grupę komponentów tagiem <mx:RemoveChild target="{firstTextInput}"/>
Scroller, co przedstawiono na Listingu 4. </mx:State>
</mx:states>
States <mx:TextInput id="firstTextInput" />
Flex 4 oferuje całkiem nowe zarządzanie stana- <mx:Canvas id="loginForm" />
mi aplikacji. Dzięki nowej składni zapisu wszyst-

www.sdjournal.org 23
Klub techniczny Adobe

Przykładowo zapis alpha.disabled=".5" przejściu w stan over. Zapis jest intuicyjny. używając atrybut skinClass, co zaprezento-
oznacza, że gdy przycisk będzie w stanie disa- Analogicznie możemy zdefiniować odrębne wano na Listningu 8.
bled, jego przezroczystość zostanie ustawiona właściwości dla każdego z atrybutów w zależ-
na 50%. Natomiast color.over=”0x33CC22” ności od wybranego stanu. Tak przygotowaną Flash XML Graphics (FXG)
definiuje zmianę koloru wypełnienia tła po skórkę podpinamy pod komponent Button, Ponieważ było duże zapotrzebowanie na przy-
jazny i wydajny system zapisu obiektów graficz-
Listing 6. Stany we Flex 4 nych, postanowiono wykorzystać format SVG.
Istnieją jednak pewne różnice pomiędzy możli-
<s:states> wościami graficznymi Flash Playera a formatem
<s:State name="submitState" /> SVG, co nie pozwoliło na bezpośrednią imple-
</s:states> mentację we Flash Playerze. Starano się utrzy-
<s:TextInput id="firstTextInput" excludeFrom="submitState" /> mać jak najwięcej zgodności ze specyfikacją
<s:Group id="loginForm" > SVG, czego wynikiem jest jego niestandardowa
<s:Button label="Wyślij" bottom="10" right="10" includeIn="submitState"/> implementacja w postaci formatu FXG.
</s:Group> FXG jest mocno zoptymalizowany pod
kątem Flash Playera. Umożliwia z poziomu
Listing 7. Skórka przycisku zadeklarowana w pliku MySkin.mxml xml-a za pomocą następujących tagów two-
<?xml version="1.0" encoding="utf-8"?> rzyć złożone obiekty graficzne:
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/
flex/spark" alpha.disabled=".5"> • BitmapFill;
<!-- stany --> • BitmapGraphic;
<s:states> • Ellipse;
<s:State name="up" /> • GradientEntry;
<s:State name="over" /> • Graphic;
<s:State name="down" /> • Group;
<s:State name="disabled" /> • Library;
</s:states> • Line;
<!-- obramowanie i wypełnienie --> • LinearGradient;
<s:Rect id="rect" radiusX="4" radiusY="4" top="0" right="0" bottom="0" left="0"> • LinearGradientStroke;
<s:fill> • Matrix;
<s:SolidColor color="0x77CC22" color.over="0x33CC22" color.down="0xBB9911" /> • Path;
</s:fill> • RadialGradient;
<s:stroke> • RadialGradientStroke;
<s:SolidColorStroke color="0x131313" weight="2"/> • Rect;
</s:stroke> • SolidColor;
</s:Rect> • SolidColorStroke;
<!-- tekst --> • TextGraphic;
<s:Label text="Button!" color="0x131313" • Transform.
textAlign="center" verticalAlign="middle"
horizontalCenter="0" verticalCenter="1" Wiązanie obustronne
left="12" right="12" top="6" bottom="6" Wiązanie obustronne (ang. Two Way Binding)
/> pozwala na stworzenie wiązania znanego z Flex
</s:Skin> 3, jednak działającego w obie strony. Na Listin-
gu 9 przedstawiono implementację wiązania
Listing 8. Wiązanie obustronne w Flex 3 obustronnego we Flex 3, natomiast na Listingu
<?xml version="1.0" encoding="utf-8"?> 10 jego nową, skróconą wersję udostępnioną we
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library:// Flex 4. W obu wersjach aplikacji wprowadzając
ns.adobe.com/flex/spark"> zmiany do jednego z pól tekstowych, zmiany bę-
<s:Button verticalCenter="0" horizontalCenter="0" skinClass="MySkin" /> dą widoczne również w 2 z pól tekstowych.
</s:Application>
RAFAŁ NAGRODZKI
Listing 9. Wiązanie obustronne we Flex 3 Freelancer i student Katolickiego Uniwersytetu
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> Lubelskiego. Z technologią Flash/Flex zaprzyjaź-
<mx:TextInput id="t1" text="{t2.text}"/> niony od 2004r.
<mx:TextInput id="t2" text="{t1.text}"/> Kontakt z autorem: kontakt@burzaone.net
</mx:Application>

Listing 10. Wiązanie obustronne we Flex 4 W Sieci


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
• http://www.adobe.com/devnet/flex/
<mx:TextInput id="t1" text="@{t2.text}"/>
articles/flex3and4_differences.html;
<mx:TextInput id="t2"/> • http://www.adobe.com/devnet/flex/
</mx:Application> videotraining/flex4beta/.

24 02/2010
Cloud computing

Enterprise
Private Clouds
Cloud computing robi od pewnego czasu zawrotną karierę medialną.
Tematem zajmują się nie tylko tytuły poświęcone branży IT, ale także
biznesowe i popularno-naukowe. Nawet Dilbert wspomina już o cloud
computing. Warto zatem zastanowić się czym jest, a czym nie jest cloud
computing i jak wpłynie na tworzenie i zarządzanie oprogramowaniem.
rynku technologii. O Software as a Service,
Dowiesz się: Powinieneś wiedzieć: ostatnim wariancie cloud computing, mó-
• Idea i zastosowanie cloud computing • Podstawowa znajomość procesu produkcji wi się dużo już od dłuższego czasu. Jest to
• Czym jest Platform as a Service oprogramowania po prostu udostępnianie aplikacji bizneso-
• Wirtualizacja zasobów IT wych w formie usługi, a nie licencji. Dzię-
ki temu klient nie ponosi kosztów począt-
kowych, nie musi utrzymywać swojego śro-
dowiska, ani zatrudniać specjalistów do za-
rządzania nim. W tym wypadku podsta-
Różne rodzaje wą rozliczenia jest zazwyczaj ogólna ilość
cloud computingu użytkowników lub ilość równolegle otwar-
Poziom Ze względu na olbrzymią pojemność poję- tych sesji.
trudności cia cloud computingu, należy wyróżnić kil- Przykładem oprogramowania dostarcza-
ka jego rodzajów. Po pierwsze, usługodaw- nego wyłącznie w modelu SaaS jest Google
cą może być firma zewnętrzna lub dział IT Apps, zaś dostępnego zarówno w modelu tra-
klienta. Mówimy wówczas o chmurze pu- dycyjnym (licencyjnym), jak i w modelu Sa-

D
efinicja dopiero się krystalizuje, ale blicznej (public cloud) lub prywatnej (pri- aS jest Oracle CRM i jego wersja SaaS – CRM
najważniejszym jej wyróżnikiem vate cloud). On Demand.
jest udostępnianie zasobów IT za Po drugie, usługi świadczone w tym mo-
pośrednictwem sieci i pobieranie opłat za delu mogą dotyczyć jednej z trzech warstw Enterprise private clouds
stopień ich wykorzystania. Klient nie pono- – infrastruktury, platformy programi- Enterprise private cloud, to nic innego jak
si nakładów inwestycyjnych z góry i nie musi stycznej lub aplikacji biznesowych. Nazy- prywatny cloud danego przedsiębiorstwa,
obawiać się niedoszacowania ani przeszaco- wamy je odpowiednio Infrastructure as a udostępniający usługi IT działom bizneso-
wania swoich potrzeb. Jednocześnie specja- Service (IaaS), Platform as a Service (Pa- wym i partnerom (spółkom zależnym, itp).
lizacja usługodawcy oraz efekt skali powodu- aS) lub Software as a Service (SaaS). Przy- Z punktu widzenia programistów, najciekaw-
je, że usługi takie powinny być wyższej jako- kładem IaaS jest Amazon EC2 – możemy szym wariantem takiej chmury, jest Platform
ści, a koszty dla klienta niższe, niż gdyby sam tu wykupić potrzebny nam czas proceso- as a Service.
utrzymywał środowisko IT. Czy cloud com- rów, miejsce na dyskach i przepustowość Korzystanie z prywatnego PaaS oznacza
puting jest zatem czymś nowym? I tak i nie. sieci. Usługodawca nie wnika w jaki spo- dla programistów kilka zmian, w porówna-
Tak, ponieważ do niedawna nie było takich sób korzystamy z tej infrastruktury, ale od- niu do tradycyjnego modelu. Wspomnia-
platform jak Google App Engine czy Ama- powiada za jej gotowość do pracy. Google łem już, że w modelu PaaS programista jest
zon EC2. Są to bez wątpienia rozwiązania App Engine jest już przykładem usługi Pa- ograniczony do narzędzi i technologii do-
innowacyjne, dające nowe możliwości. Czy aS, gdyż usługodawca daje nam konkretne stępnych na platformie. Może to budzić
jednak stary, poczciwy, hosting stron WWW narzędzia, z których możemy korzystać do niechęć ze względu na osobiste preferen-
nie pasuje do podanej definicji? Pasuje. Po- stworzenia potrzebnej nam aplikacji. Co cje, ale daje wymierne korzyści biznesowe
dobnie jak odpłatne konta pocztowe w ser- prawda w dalszym ciągu płacimy za zaso- firmie, dla której przecież pracujemy. Stan-
wisach internetowych, czy aplikacje bizne- by fizyczne (procesor/pamięć/sieć/dysk), daryzacja i konsolidacja środowisk pozwala
sowe dostępne przez internet. Cloud com- ale jednak dostajemy już nie tylko infra- wyraźnie obniżyć koszty sprzętu, licencji,
puting nie jest zatem koncepcją rewolucyjną, strukturę, ale kompletne, ustandaryzowa- pomocy technicznej oraz personelu. Oczy-
a jedynie kolejnym krokiem w ewolucji bran- ne, środowisko do rozwoju i działania apli- wiście powinna istnieć możliwość dodania
ży IT. Usługi IT stają się dobrem powszech- kacji – możemy co prawda wybrać jeden z określonej technologii do zestawu narzę-
nym, co pociąga za sobą zmiany w sposobie dwóch języków (Java, Python), ale nie mo- dzi dostępnych na platformie, ale nie ma
ich świadczenia. żemy zastosować dowolnej dostępnej na co liczyć na pełną dowolność, jak w przy-

26 02/2010
Enterprise Private Clouds

padku zupełnie niezależnych projektów i kacji, ze względu na poufność przetwa- dowisk, co zniweczy korzyści wynikające z
środowisk. W zamian programista otrzy- rzanych danych lub inne uwarunkowania, konsolidacji.
muje jednak wiele korzyści. Po pierwsze nie może być uruchomiona na publicz-
dostaje możliwość prostego tworzenia do- nych środowiskach, dlatego korzystanie z Wirtualizacja
datkowych środowisk na żądanie. Z zało- nich decyzją oddolną powinno być zgod- Można stworzyć środowisko bez problemu
żenia chmura powinna być łatwa w rozbu- ne z polityką bezpieczeństwa firmy, a bu- spełniające definicję PaaS nie korzystając
dowie i powinna pomieścić dodatkowe in- dowa prywatnej platformy może być nie- z żadnego rozwiązania wirtualizacyjnego,
stancje, jeśli ich potrzebujemy. Co więcej, zbędna. Na czas budowy takiego środowi- ale zastosowanie takiej technologii pozwala
tworzenie środowisk powinno być zauto- ska można z kolei skorzystać z publiczne- osiągnąć znacznie większe korzyści z wdro-
matyzowane, a zarządzanie nimi oddane w go IaaS, w którym od ręki będziemy mo- żenia platformy PaaS. Wirtualizacja pozwala
ręce użytkowników. Programista może za- gli wynająć sprzęt potrzebny do rozpoczę- zwiększyć utylizację zasobów sprzętowych,
tem zażądać utworzenia nowego środowi- cia projektu. zachować ciągłość pracy w czasie prac kon-
ska, czy to z jakiegoś wzorca (np. czyste śro- serwacyjnych (np. wymiana sprzętu) oraz
dowisko z aplikacją w wersji X), czy też po- Techniczna realizacja PaaS pomaga zarządzać środowiskami. Pozwala
przez skopiowanie innego środowiska (po- Udostępnianie platformy aplikacyjnej ja- tworzyć wzorcowe instalacje dostępnych
trzebuję identycznego środowiska jak Y, żeby ko usługi oznacza przede wszystkim zmia- na platformie komponentów, np. kompo-
zdiagnozować problem, który występuje tyl- nę modelu sprzedaży/współpracy między nent baza danych zawierający odpowiednio
ko tam). Środowisko takie powinno zostać działem utrzymania systemów, a działami skonfigurowany system operacyjny z podłą-
utworzone w czasie minut lub godzin, a rozwoju i utrzymania aplikacji. Niemniej czeniem do przestrzeni dyskowych, bazę da-
nie dni czy tygodni, jak to często bywa, gdy jednak, aby zapewnić sprawne działanie ta- nych w odpowiedniej wersji i ze wszystkimi
utworzenie środowiska wymaga akceptacji kiej platformy, co jest warunkiem koniecz- poprawkami, narzędzia diagnostyczne i tak
przełożonych, zamówienia sprzętu i ręcz- nym osiągnięcia sukcesu, przydatne są od- dalej. Po przygotowaniu odpowiednich kom-
nej pracy. Idąc tym tropem, możemy tak- powiednie rozwiązania techniczne. Jeśli ponentów, gdy będziemy zaczynać nowy
że przenieść środowiska testowe ze stacji tworzenie środowisk potrzebnych do roz- projekt, programista będzie mógł zażądać
roboczych na platformę PaaS, dzięki cze- woju aplikacji będzie trwało zbyt długo nowego środowiska ze wszystkimi potrzeb-
mu nie musimy sami nimi zarządzać, mo- lub utworzone środowiska będą wymagały nymi komponentami, a po wprowadzeniu
żemy przywracać je do poprawnego stanu, ręcznych poprawek, programiści powrócą niezbędnych zmian wymaganych dla danej
gdy coś pójdzie nie tak, a wszystkie zmiany do rozwijania kodu na własnych kompute- aplikacji (np. schematy bazy danych, połą-
konfiguracyjne (np. podłączenia do baz da- rach. Jeśli wzrost obciążenia w jednej apli- czenie z odpowiednim modułem repozy-
nych, adresy serwerów aplikacji czy web se- kacji będzie powodował spadek wydajno- torium kodu), zachować obraz jako wzor-
rvices) są centralnie zarządzane i nie musi- ści całej platformy, menedżerowie poszcze- cowy dla innych osób pracujących nad tym
my się tym zajmować. Warto także zazna- gólnych aplikacji będą żądać separacji śro- projektem.
czyć, że prywatny PaaS nie ogranicza moż-
liwości debugowania systemu – o ile pu-
bliczny dostawca niekoniecznie udostępni
nam wszelkie możliwości diagnostyczne, o
tyle prywatny PaaS daje możliwość włącze-
nia odpowiednich opcji i podłączenia się z
narzędziami diagnostycznymi.
����������� ����������� �����������

Zmiany organizacyjne ���������������������������� �����������


Cloud computing, zwłaszcza prywatny,
wymaga przede wszystkim zmiany sposo- ��������������� ������
bu myślenia o zasobach IT. Tak jak SOA nie ���������������
jest technologią opartą na web services, tyl- ���
�������
��������������
������������
��������� ��������� �����������
ko architekturą wymagającą zmiany sposo- ��������
bu i szerszego spojrzenia na tworzenie i po- ������������������ ����������
nowne wykorzystanie aplikacji, tak cloud
����������
computing nie wymaga żadnej szczególnej ��������������
����������
technologii, ale przede wszystkim zmiany
���������������������������������� �����������
w procesie zarządzania zasobami. Techno-
�����������
logia jest rzeczą wtórną, która usprawnia �����������������
ten proces i umożliwia zapewnienie do- ������������� �������������
stępności, wydajności i bezpieczeństwa w �������
��������
tych nowych warunkach. O ile korzystanie �������
z usług publicznych dostawców cloud com-
puting może być (i często jest) decyzją od-
dolną, o tyle projekt budowy wewnętrznej
platformy PaaS w firmie, wymaga konkret-
nych nakładów początkowych, zmiany pro-
cesu zakupów sprzętu i licencji oraz roz-
liczania innych działów za korzystanie z
nich. Należy zwrócić uwagę, że wiele apli- Rysunek 1. Schemat koncepcyjny architektury IaaS/PaaS

www.sdjournal.org 27
Cloud computing

Sprawnie działająca platforma PaaS po- sce na urządzeniach backupowych i skró- trzebują, są odpowiedzialni za odpowied-
winna pozwolić na stworzenie środowisk cić czas migracji maszyny wirtualnej mię- nie ich kategoryzowanie (test/produkcja),
dla wszystkich zainteresowanych w ciągu dzy fizycznymi serwerami. żądają dodatkowych zasobów, jeśli wiedzą,
kilku godzin. Poza samym kontenerem, warto rów- że będą potrzebne (w sytuacjach nieprze-
nież zastosować technologię in-memory da- widzianych za taką rozbudowę odpowiada
Warstwa middleware ta grid. Pozwala ona przechowywać duże ilo- już dostawca platformy) i wyłączają instan-
W warstwie oprogramowania middlewa- ści danych obiektowych (w tym obiekty se- cje, których dłużej nie potrzebują. Dostawca
re, przydatnych może być kilka funkcji. Po sji HTTP) w pamięci operacyjnej, dzięki cze- chmury PaaS, także prywatnej, musi zatem
pierwsze klastrowanie z synchronizacją se- mu odciąża kontener JEE. Rozwiązania wy- zapewnić interfejs do zarządzania środowi-
sji użytkowników, jako podstawowy me- raźnie przyspieszają działanie aplikacji i po- skami klienta.
chanizm skalowania i zapewniania ciągło- zwalają skalować aplikacje praktycznie w nie-
ści pracy tej warstwy. Po drugie, możliwość skończoność. Rozliczanie
jednoczesnego korzystania z różnych wer- wykorzystania zasobów
sji tych samych bibliotek, bowiem nasza Warstwa bazy danych Zgodnie z definicją, rozliczanie klientów
aplikacja niekoniecznie będzie działać na Podobnie jak w przypadku serwerów apli- jest oparte o zużycie określonych zasobów.
zupełnie niezależnym środowisku. Insta- kacji, w warstwie baz danych zastosowanie Czynnikami wpływającymi na koszt korzy-
lacja nowej aplikacji wraz z zależnościami klastrów również pozwala zachować cią- stania z clouda mogą być zarówno warto-
nie może powodować zmiany wersji biblio- głość pracy i umożliwia skalowanie syste- ści techniczne (czas procesora, zużycie sie-
teki używanej przez już działającą aplika- mów w razie takiej potrzeby. Kluczowe sta- ci, etc), jak i biznesowe – na przykład ilość
cję. Kolejna sprawa, to możliwość testowe- je się także zarządzanie przestrzenią dys- kampanii marketingowych przeprowadzo-
go uruchomienia aplikacji na platformie. kową. Zastosowana technologia powinna nych przy użyciu danej aplikacji. Moż-
Dopóki całe środowisko nowej aplikacji nie tylko umożliwiać łatwą rozbudowę, ale na sobie łatwo wyobrazić sytuację, w któ-
jest niezależne – możemy testować aplika- również równomiernie rozkładać obciąże- rej dostępne są również różne taryfy, po-
cję do woli bez udostępniania jej użytkow- nie między dostępne dyski. W przeciw- dobnie jak to jest u operatorów telefonicz-
nikom. Jeśli jednak chcemy przeprowadzić nym wypadku, w krótkim czasie mieliby- nych. Opłata składa się zwykle z części sta-
ostateczne testy przed upublicznieniem śmy analogiczną sytuację jak z serwerami łej (abonamentu) oraz zmiennej – zależnej
aplikacji na platformie PaaS, musimy mieć bez wirtualizacji – gdy do aplikacji przy- od wykorzystanych zasobów. W celu mi-
możliwość uruchomienia nowej aplikacji pisane są na stałe określone zasoby sprzę- nimalizacji kosztów zmiennych, koniecz-
tylko dla wybranych użytkowników (te- towe, to prawie zawsze część z nich jest na może się okazać optymalizacja aplikacji
sterów). Kolejna kwestia bardzo ułatwia- przeciążona, a część niedociążona. Podob- – czynność, o której niestety wiele osób za-
jąca zarządzanie tak dynamiczną platfor- nie jak w przypadku serwerów, aby w pełni pomniało w dobie wydajnych i często prze-
mą, z wieloma środowiskami i aplikacja- czerpać korzyści z konsolidacji, potrzebu- szacowanych serwerów (analizy pokazu-
mi, to mechanizm skryptowy pozwalający jemy zatem warstwy wirtualizacji dla zaso- ją, że średnie obciążenie serwerów rzadko
zautomatyzować czynności administracyj- bów dyskowych. przekracza 20%).
ne. Nawet jeśli korzystamy z wirtualizacji i
możemy tworzyć obrazy wzorcowe, to po Zarządzanie zasobami Podsumowanie
każdym skorzystaniu z takiego wzorca, po- W praktycznie każdym systemie, także nie Budowa prywatnej chmury Platform as a
trzebujemy zmienić kilka parametrów (ad- korzystającym z platformy PaaS, warto ko- Service pozwala osiągnąć cele, do których
resy, porty i tym podobne). Do tego należy rzystać z mechanizmów ograniczania do- dąży praktycznie każde przedsiębiorstwo
doliczyć późniejsze zmiany, które trzeba w stępu do zasobów pojedynczym użytkow- – skrócenie czasu od pomysłu do realizacji
powtarzalny sposób wykonywać na wszyst- nikom, czy aplikacjom. Użytkownicy nie (time to market), a co za tym idzie wzrost
kich środowiskach (np. dodanie nowego powinni odczuwać wyraźnego spadku wy- przychodów. Konsolidacja sprzętu i licen-
data source). Ręczne wykonywanie zmian dajności w sytuacji, gdy jeden z nich ge- cji oraz łatwa dynamiczna rozbudowa za-
mogłoby spowodować niespójność środo- neruje skomplikowany raport. W tym wy- pewnia jednocześnie niższe koszty utrzy-
wisk i tym samym zniwelować korzyści padku baza danych powinna odpowied- mania, oraz brak konieczności ponoszenia
wdrożenia PaaS. nio ograniczyć zasoby dostępne dla sesji dużych kosztów na początku każdego pro-
Bardzo ciekawym rozwiązaniem, dopie- tego użytkownika, umożliwiając normal- jektu. Z punktu widzenia programisty, to
ro wchodzącym na rynek, są serwery apli- ną pracę pozostałym. Zarządzanie zasoba- przede wszystkim likwidacja barier orga-
kacji działające bezpośrednio na hyperviso- mi staje się jeszcze ważniejsze, gdy na jed- nizacyjnych i większa swoboda w korzysta-
rze – bez klasycznego systemu operacyjne- nym fizycznym komputerze mogą działać niu z zasobów firmy, a jednocześnie mniej
go. Takie podejście pozwala nie tylko pod- na przykład dwie maszyny wirtualne, każ- czasu straconego na zarządzaniu środowi-
nieść wydajność, dzięki lepszemu zarzą- da ze swoim systemem operacyjnym i ba- skami i mniej problemów wynikających z
dzania pamięcią (normalnie system opera- zą danych, a każda z baz danych obsługuje różnic między nimi. Dobrze zrealizowana
cyjny i JVM częściowo pokrywają się funk- kilka różnych aplikacji. Jeśli nie zdefiniuje- platforma powinna zatem przynieść korzy-
cjonalnością w tym zakresie), ale również my odpowiedniej polityki przydziału zaso- ści wszystkim zainteresowanym.
pozwala wyraźnie uprościć całe środowisko bów, nie będziemy w stanie zapewnić wy-
(skoro nie ma systemu operacyjnego, to nie maganego poziomu świadczenia usług dla
trzeba go konfigurować, optymalizować, poszczególnych aplikacji.
ani aktualizować). Dodatkowo uzyskuje-
my mniejsze obrazy maszyn wirtualnych, Cykl życia “chmury”
gdyż nie zawierają one binariów systemu Jednym z głównych założeń cloud compu-
operacyjnego. Pozwala to obniżyć koszty ting jest samoobsługa użytkowników. To MICHAŁ KURATCZYK
przestrzeni dyskowych, zaoszczędzić miej- oni tworzą kolejne środowiska, gdy ich po- Principal solution architect, Oracle Polska

28 02/2010
Programowanie C++

Fabryki obiektów
Techniki opisane w tym artykule pozwalają tworzyć obiekty na
podstawie identyfikatorów dostarczanych w czasie działania programu,
co jest wygodniejsze niż podawanie typów w formie zrozumiałej dla
kompilatora.

tworzyć obiekty na podstawie identyfikato-


Dowiesz się: Powinieneś wiedzieć: ra, rolę tę pełni funkcja createObj. Po utwo-
• Jak tworzyć obiekty w C++; • Jak pisać proste programy w C++; rzeniu obiektu możemy wczytać składowe,
• Co to jest wzorzec fabryki. • Co to jest dziedziczenie i funkcje wirtualne. wykorzystując mechanizm funkcji wirtual-
nych, wołając metodę read dla utworzone-
go obiektu.
Przy zapisie obiektu do strumienia wyj-
ściowego (na przykład do pliku) nie potrze-
bujemy dodatkowych mechanizmów, któ-
Funkcje fabryczne re dostarczą identyfikator dla danego typu,
Przykład wykorzystania fabryki obiektów ponieważ możemy wykorzystać mechanizm
Poziom został pokazany na Listingu 2, gdzie poka- funkcji wirtualnych. Posiadając wskaźnik lub
trudności zano funkcję create tworzącą obiekty klas referencję na klasę bazową, wołamy meto-
na podstawie danych zapisanych w strumie- dę write, która zapisuje identyfikator klasy
niu wejściowym, na przykład w pliku. Funk- konkretnej oraz jej składowe. Odczyt obiek-
cja ta dostarcza obiekt odpowiedniego typu tu jest o wiele bardziej złożony niż zapis ze

F
abryka obiektów jest klasą, której konkretnego dla hierarchii Figure. Metody względu na to, że zapis posługuje się istnie-
obiekty pośredniczą przy tworze- zapisu (write) oraz odczytu (read) są do- jącymi obiektami, natomiast odczyt musi je
niu innych obiektów. Dostarcza- starczane przez każdą z klas konkretnych. tworzyć.
na informacja jednoznacznie identyfiku- Jeżeli chcemy obiekt utworzyć (odczytać),
je konkretny typ, znany w momencie kom- to typ obiektu jest dostarczany w czasie dzia- Fabryka skalowalna
pilacji, ale nie jest to literał, więc informa- łania, jest on wyznaczany przez identyfika- Funkcja createObj jest prostą fabryką obiek-
cja o typie jest nieodpowiednia dla kom- tor dostarczany przez strumień. Ponieważ tów, pozwala ona tworzyć obiekty na podsta-
pilatora, na przykład jest to napis lub inny tak dostarczany identyfikator nie jest ak- wie informacji, która jest dostarczana w cza-
identyfikator. Fabryka ukrywa przed użyt- ceptowany jako argument dla operacji new, sie działania, ale ma wiele wad: mapowanie
kownikiem mechanizm zamiany identyfi- należy wykorzystać fabrykę, która pozwoli identyfikatora na typ za pomocą instrukcji
katora na literał dostarczany do operato-
ra new, upraszczając tworzenie obiektów Listing 1. Podczas tworzenia obiektu należy podać typ w odpowiedniej formie
(patrz Rysunek 1).
W języku C++ podczas tworzenia obiektu class Bazowa { /* ... */ }; //przykładowa definicja typu
należy podać konkretny typ w formie zrozu- class KonkretnaA : public Bazowa { /* ... */ };
miałej dla kompilatora (patrz Listing 1). Nie Bazowa* p = new KonkretnaA; //przy tworzeniu trzeba podać konkretny typ
możemy posłużyć się mechanizmem funkcji //nazwa typu musi być zrozumiała dla kompilatora
wirtualnych, nie możemy także przekazać
identyfikatora typu w czasie działania, argu-
mentem operatora new może być tylko literał
oznaczający typ znany w momencie kompila- Szybki start
cji. Po utworzeniu obiektu można się do nie- Aby uruchomić przedstawione przykłady, należy mieć dostęp do kompilatora C++ oraz
go odwoływać poprzez wskaźnik lub referen- edytora tekstu. Niektóre przykłady korzystają z udogodnień dostarczanych przez bi-
cję na klasę bazową, ale przy tworzeniu nale- bliotekę boost::mpl, warunkiem ich uruchomienia jest instalacja bibliotek boost (w wer-
sji 1.36 lub nowszej) Na wydrukach pominięto dołączanie odpowiednich nagłówków
ży podać rzeczywisty typ obiektu, nie można oraz udostępnianie przestrzeni nazw, pełne źródła dołączono jako materiały pomoc-
użyć mechanizmu późnego wiązania (funk- nicze.
cji wirtualnych).

30 02/2010
Fabryki obiektów

switch sprawia, że funkcja ta jest zależna od nie moduł ten może zawierać kod rejestrują- zanie bezpośrednie (wybór typu w zależno-
wszystkich klas w hierarchii, jeżeli będzie cy dany typ w fabryce, tak jak pokazano na ści od identyfikatora za pomocą switch lub
dodawana lub usuwana jakaś klasa, to mody- Listingu 4. łańcucha if ... else), ponieważ wymaga prze-
fikacji będzie musiał podlegać także kod fa- Fabryka skalowalna jest bardziej elastycz- chowywania kolekcji wiążącej identyfikator z
bryki; brak kontroli przy wiązaniu identyfi- na, ale też bardziej kosztowna niż rozwią- funkcją tworzącą. Obiekt jest tworzony za po-
katora z typem sprawia, że musimy zapew-
nić, aby przy odczycie obiektu korzystać z Listing 2. Przykład, w którym uzasadnione jest wykorzystanie fabryki
tego samego identyfikatora co przy zapisie.
Poza tym, zestaw identyfikatorów jest zaso- class Figure { //klasa bazowa
bem globalnym, przy modyfikowaniu zbio- public:
ru klas w danej hierarchii musi on podlegać enum Type { SQUARE, CIRCLE, /* ... */ };//identyfikatory klas konkretnych
modyfikacjom. virtual bool write(ostream& os) const = 0;//zapisuje obiekt
Fabryka skalowalna, przedstawiona na virtual bool read(istream& is) = 0;//odczytuje obiekt
Listingu 3, umożliwia tworzenie obiektów };
na podstawie identyfikatorów, wprowadza class Square : public Figure {//jedna z klas konkretnych
mniejszą liczbę zależności w porównaniu public:
z poprzednio omówionym rozwiązaniem, bool zapisz(ostream& os) {//zapisuje kwadraty
ponieważ jest ona zależna tylko od klasy os << KWADRAT;//zapisuje identyfikator typu
bazowej, a nie od wszystkich klas konkret- //zapisuje poszczególne składowe
nych. Mniejsza liczba zależności wynika z }
zastosowania wskaźnika na funkcję two- bool read(istream& is) {//odczytuje obiekt, zakładając, że jest to kwadrat
rzącą obiekty danej klasy konkretnej oraz //odczytuje poszczególne składowe
przez użycie dynamicznej struktury prze- }
chowującej mapowanie pomiędzy identy- };
fikatorem a typem. //pozostałe klasy konkretne także dostarczają metody odczytu i zapisu
Klasa konkretna woła metodę registerFig, //...
przekazując swój identyfikator oraz funkcję Figure* createObj(istream& is) {//funkcja pełni rolę fabryki
tworzącą obiekty danej klasy. Metoda ta doda- Figure::Type type;
je element do kolekcji, można więc elastycznie is >> type; //odczytuje identyfikator typu
modyfikować zestaw klas, których obiekty bę- Figure* obj;
dą tworzone przez fabrykę. Jeżeli chcemy usu- switch(type) { //zapewnia mapowanie pomiędzy identyfikatorem a typem
wać wpisy, to należy zaimplementować meto- case SQUARE://w formie zrozumiałej dla kompilatora
dę unregister, która będzie usuwała elemen- return new Square(); //tworzy odpowiedni obiekt
ty z kolekcji. case CIRCLE: /* ... */
Tworzenie obiektów odbywa się w meto- }
dzie create, która wyszukuje funkcję two- }
rzącą dla danego identyfikatora. Jeżeli taka //tworzy obiekt na podstawie identyfikatora i odczytuje jego składowe
funkcja zostanie znaleziona, to jest ona woła- Figure* create(istream& is) {
na (patrz Listing 3), a obiekt utworzonej kla- Figure* obj = createObj(is); //tworzy obiekt odpowiedniego typu
sy jest zwracany. obj->read(is);//obiekt istnieje, może wykorzystać funkcje wirtualne
Klasa konkretna musi dostarczyć funkcję }
tworzącą obiekty, funkcja ta (patrz Listing 4)
może być umieszczona w module zawierają- Listing 3. Fabryka skalowalna
cym implementację klasy konkretnej, podob- class FigFactory {
public:
typedef Figure* (*CreateFig)(); //wskaźnik na funkcję tworzącą obiekt
//rejestruje nowy typ
void registerFig(int id, CreateFig fun) {
creators_.insert( value_type(id, fun) ); //dodaje do kolekcji
}
������ ������� //tworzy obiekt na podstawie identyfikatora
Figure* create(int id) { //tworzy obiekt danego typu
Creators::const_iterator i = creators_.find(id);
��������������������� if(i ! = creators_.end() ) //jeżeli znalazł odpowiedni wpis
������ return (i->second)(); //woła metodę fabryczną
return 0L; //zwraca pusty wskaźnik, gdy nieznany identyfikator
}
private:
typedef std::map<int, CreateFig> Creators;
Creators creators_;//przechowuje powiązania pomiędzy identyfikatorem a funkcją
tworzącą
};
Rysunek 1. Tworzenie obiektów przez fabrykę

www.sdjournal.org 31
Programowanie C++

średnictwem tej funkcji, więc tworzenie trwa Aby zaimplementować w pełni funkcjo- sze, problem dostarczania odpowiedniego
dłużej (jeden skok więcej w porównaniu z nalną fabrykę obiektów, należy uwzględ- obiektu fabryki wymaganego przy rejestra-
metodą bezpośrednią). nić dodatkowe zagadnienia. Po pierw- cji klas (na wydruku 4 została użyta funk-
cja getFactory). Często stosowanym roz-
Listing 4. Przykład funkcji tworzącej i rejestracji typu w fabryce wiązaniem jest singleton. Po drugie, należy
zarządzać czasem życia powołanych obiek-
Figure* CreateSquare() { //funkcja tworząca dla typu konkretnego tów, fabryka tworzy obiekty na stercie, ale
return new Square(); kto ma je zwalniać? W tym celu warto po-
}; służyć się sprytnymi wskaźnikami (patrz
FigFactory& factory = getFactory();//pobiera obiekt fabryki SDJ 11/2009). Kolejnym zadaniem jest
factory.registerFig(SQUARE, CreateSquare); //rejestruje się w fabryce wiązanie identyfikatora z typem, aby wy-
kluczyć możliwości pomyłek. Można od-
Listing 5. Fabryka skalowalna zarządzająca identyfikatorami powiedzialność dostarczania identyfika-
typedef shared_ptr<Figure> PFigure; //sprytny wskaźnik torów przenieść na fabrykę, obiekt ten ma
class FigFactory { może tworzyć unikalne identyfikatory, zaś
public: klasy, które są rejestrowane w fabryce, mo-
gą ten identyfikator przechowywać w skła-
typedef PFigure (*CreateFig)(); //wskaźnik na funkcję tworzącą obiekt dowej statycznej (patrz Listing 5). Obiekty
int registerFig(CreateFig fun) {//zwraca id zarejestrowanego typu klas będą wykorzystywały ten identyfika-
creators_.insert( value_type( currentId_, fun) ); tor podczas zapisu, natomiast fabryka wy-
return currentId_++; //zwraca identyfikator korzystuje go podczas odczytu.
} Inną możliwością jest generowanie identy-
PFigure create(int id); //tworzy obiekt danego typu (patrz Listing 3) fikatora przez mechanizmy kompilatora, na
przykład używając struktury type_id, wtedy
private: nie trzeba zarządzać nim w fabryce.
int currentId_; //kolejny wolny identyfikator Inicjacja fabryki skalowalnej (rejestracja
//składowe związane z funkcjami tworzącymi typów) może być uproszczona, jeżeli będzie
}; wykorzystywana kolekcja typów z biblioteki
FigFactory& factory = FigFactory::getInstance();//singleton boost::mpl (patrz SDJ 12/2009) oraz algoryt-
Square::id_ = factory.registerFig(CreateSquare); //ustawia identyfikator my, które na kolekcji operują( patrz Listing
6). Funkcja tworząca może być metodą sta-
Listing 6. Rejestracja klas w fabryce skalowalnej przez algorytm biblioteki boost::mpl tyczną klasy konkretnej, wtedy nie musi za-
class Square : public Figure { wierać nazwy tworzonej klasy. Takie rozwią-
public: zanie prezentuje Listing 6.

//każda klasa konkretna dostarcza metodę statyczną create Podsumowanie


static Figure* create() { return new Square; } Opisany sposób tworzenia obiektów na pod-
}; stawie identyfikatora dostarczanego pod-
czas działania programu jest jednym z wzor-
struct RegisterFigure { //szablon użyty do rejestracji ców kreacyjnych, termin został zapropono-
template<typename T> void operator()(T) { wany przez bandę czworga (Gamma, Helm,
T::id_ = Factory::getInstance().registerFig( T::create ); Johnson, Vlissides) w książce Wzorce projek-
} towe. Inne udogodnienia dotyczące tworze-
}; nia obiektów, takie jak fabryki prototypów
typedef mpl::vector<Square, Circle> Types; //kolekcja typów dla klas konkretnych i fabryki abstrakcyjne, są tematem jednego z
mpl::for_each< Types > ( RegisterFigure() ); //woła w czasie wykonania operację dla kolejnych artykułów.
każdego typu

W Sieci
• http://www.boost.org – dokumentacja bibliotek boost;
• http://www.open-std.org – dokumenty opisujące nowy standard C++.

ROBERT NOWAK
Więcej w książce Adiunkt w Zakładzie Sztucznej Inteligencji Insty-
Zagadnienia dotyczące współcześnie stosowanych technik w języku C++, wzorce projekto- tutu Systemów Elektronicznych Politechniki War-
we, programowanie generyczne, prawidłowe zarządzanie zasobami przy stosowaniu wy-
szawskiej, zainteresowany tworzeniem aplika-
jątków, programowanie wielowątkowe, ilustrowane przykładami stosowanymi w bibliotece
standardowej i bibliotekach boost, zostały opisane w książce Średnio zaawansowane progra- cji dla biologii i medycyny, programuje w C++ od
mowanie w C++, która ukaże się niebawem. ponad 10 lat.
Kontakt z autorem:rno@o2.pl

32 02/2010
Programowanie gier

Jak napisać pierwszą


grę komputerową
Czyli najtrudniejszy pierwszy krok
Prawdopodobnie każdy gracz ma w głowie co najmniej jeden pomysł na
rewelacyjną grę. Niektórzy idą dalej i zakładają zeszyty w kratkę, których
strony zapełniają pomysłami i szkicami. Niestety w tym szczególnym
przypadku sam pomysł to zbyt mało i – bez konkretnych kroków – jest
niewiele wart.
bazy danych, to możemy przyciąć nasz pro-
Dowiesz się: Powinieneś wiedzieć: jekt tak, by dało się go zrealizować na bazie
• Z jakich technologii możesz korzystać two- • co to gra komputerowa; danych lub tylko formularzu. Przykładem
rząc pierwszą grę; • … i jaką grę chcesz zrobić. bardzo wciągającej gry wykonanej napraw-
• Czym jest prototyp; dę prostą metodą jest Drug Wars lub jej pol-
• Jak zorganizować sobie pracę. ski odpowiednik MaXDila 2000. Kilka pól
tekstowych i zabawa murowana na wiele go-
dzin.
Co możemy zrobić, gdy nie mamy żadne-
Na potrzeby niniejszego artykułu założy- go doświadczenia w tworzeniu graficznych
my, że nasz pomysł na grę to gra platformo- interfejsów użytkownika i jedyne, co potra-
Poziom wa, której bohaterem jest wściekła małpa. fimy, to wyświetlanie znaków ASCII? Może-
trudności Małpa zbiegła z miejskiego ZOO i teraz ści- my zrobić grę oczywiście. Jest cały gatunek
ga po mieście biznesmanów w garniturach, gier Roguelike, czyli tak zwanych rogalików.
aby zatłuc ich wielkim bananem. Grę robo- Są to gry naśladujące kultową grę Rogue (stąd
czo nazywamy Monkey Business ich nazwa). Cała grafika reprezentowana jest

T
rudno jest zainteresować poważną tu za pomocą znaków ASCII. Prostota repre-
firmę inwestycją w grę , przysyła- Plan B, czyli „Wystarczy chcieć” zentacji wizualnej może być myląca – gry te
jąc im zeszyt z pomysłem. Na pa- Plan B sprowadza się do tego, że musimy grę są często przerażająco złożone. Przykładem
pierze każda gra – choćby była oryginalna wykonać sami. Pierwszym krokiem powin- może być ADOM lub Dwarf Fortress. Stwo-
i rewolucyjna – wygląda podobnie i, nie- na być ocena naszych umiejętności i moż- rzenie gry w tak ubogiej oprawie graficznej
stety, zazwyczaj nieciekawie. Dzisiaj pro- liwości. Jeśli jesteśmy akurat John’em Car- może przy okazji ujawnić słabe punkty sce-
dukcja gry komputerowej to duży budżet mack’iem lub mamy szafę pełną pieniędzy, nariusza lub mechaniki. Gdy nie ma nic, co
i wiele zaangażowanych osób. Mówimy tu to sprawa jest dosyć prosta. W innym przy- by nas rozpraszało, to właśnie fabuła i game-
o co najmniej dziesiątkach tysięcy złotych padku musimy usiąść i zastanowić się, co play trzymają nas przy klawiaturze (lub kon-
w przypadku małych gier, a milionach do- właściwie potrafimy. trolerze).
larów w przypadku produkcji większych, Spisujemy wszystkie nasze umiejętno- W takim razie co robić, jeśli umiemy tyl-
nie ma więc co się dziwić, że mało kto wy- ści takie jak rysowanie, modelowanie gra- ko rysować lub tworzyć modele trójwymia-
łoży pieniądze na realizację pomysłu jakie- fiki trójwymiarowej, projektowanie baz da- rowe? Paradoksalnie możemy się odprę-
goś gościa z zeszytem. Zwłaszcza pamięta- nych, interfejsów baz danych, projektowanie żyć, jesteśmy w dosyć komfortowej sytu-
jąc, że gry to kapryśne produkty i czasem stron WWW, programowanie (w czymkol- acji. Sieć jest pełna zdesperowanych progra-
nawet bardzo dobra produkcja może prze- wiek) lub dowolną inną umiejętność powią- mistów szukających grafików, którzy po-
paść na rynku w wyniku niesprzyjających zaną z szeroko pojętą informatyką. Nawet je- mogliby skończyć ich projekt. Pozostaje tyl-
okoliczności lub pecha (przykładowo Vam- śli lista jest bardzo krótka, nadal jest nadzie- ko przekonać ich, że to właśnie nasz projekt
pire: The Masquerade – Bloodlines czy choć- ja, nie poddajemy się. Kolejny krok to próba jest ciekawszy.
by Psychonauts). dopasowania naszych umiejętności do kon- Oczywiście może się też zdarzyć, że kart-
Skoro widoki na to, że dyrektor znanej fir- kretnego projektu. ka pozostaje pusta, ponieważ nie posiada-
my podsłucha nasz pomysł w autobusie i od Jeśli planujemy grę handlową lub nawet my żadnych umiejętności, które pomogły-
ręki nas zatrudni, są marne, trzeba przejść MMORPG (Massive Multiplayer Online Ro- by nam w stworzeniu gry. W takiej sytu-
do planu B. le Playing Game), a potrafimy tylko tworzyć acji nadal nie wszystko jest stracone – wy-

34 02/2010
Jak napisać swoją pierwszą grę komputerową

starczy bliżej zainteresować się narzędzia- ne jest ręczne rysowanie kolejnych klatek, Podstawowymi elementami, znajdujący-
mi do tworzenia gier. Nie zawsze oferują co jest dosyć uciążliwe. mi się w większości gier, są:
swobodę, jakiej oczekujemy. Nie zawsze są Pewnym ułatwieniem może być tworze-
wydajne. Mają jednak jedną ogromną zale- nie grafiki wektorowej – rozwiązuje to pro- • silnik graficzny odpowiedzialny za wy-
tę, a mianowicie są proste w obsłudze i czę- blem niewprawnej drżącej ręki, pozwala wy- świetlanie gry;
sto darmowe lub bardzo tanie. Dzięki temu pełniać kształty gradientami i ułatwia ani- • biblioteki odpowiedzialne za odgry-
skupiają wokół siebie spore społeczności. To mowanie. Co prawda powstaje grafika fla- wanie efektów dźwiękowych oraz mu-
z kolei oznacza, że dostępne jest bardzo du- szowa, ale lepszy rydz niż nic. zyki;
żo gotowych przykładów i poradników, jak Taka grafika nie musi być grafiką docelo- • silnik symulacji fizycznej;
stworzyć własne gry, bazując na danym na- wą – może służyć tylko do przygotowania • skrypty;
rzędziu. Przykładem takiego narzędzia mo- prototypu gry, który będziemy chcieli – ce-
że być Game Maker. lem zachęcenia do współpracy – pokazać Jeśli planujemy stworzenie gry dwuwy-
Gdy umiemy trochę programować, po- wydawcy lub kolegom potrafiącym rysować. miarowej , warto zainteresować się PopCap
winniśmy rozważyć wykorzystanie istnie- Jednak w przypadku trzech wymiarów Games Framework. Framework ten jest
jącego silnika lub framework’a. Zawsze pa- sprawa się komplikuje. Żeby nasza gra za- bardzo kiepsko udokumentowany (garść
miętajcie, że gra to olbrzymie przedsięwzię- częła dobrze wyglądać, musimy stworzyć dokumentów opisujących ogólne zasady
cie i trzeba ułatwiać sobie życie jak się tyl- model w jakimś programie do modelowa- działania), jednak jego prostota rekompen-
ko da. Częstym błędem jest zabieranie się do nia, takim jak darmowy Blender. Jednak suje wszelkie wady. Nawet niewprawny
pisania własnego silnika, żeby potem na nim sam model to nie wszystko – raczej dopie- programista po przejrzeniu przykładów
stworzyć grę. Przypomina to trochę wywa- ro początek. Jeśli będzie to obiekt animo- dostarczonych wraz z kodem źródłowym
żanie drzwi otwartych na oścież – jest wie- wany, musimy przygotować animację. Ten może napisać prototyp gry platformowej
le darmowych rozwiązań, które zaoszczędzą krok jest łatwiejszy niż animowanie ra- (lub dowolnej innej) w dosłownie kilka go-
nam miesięcy żmudnej dłubaniny. No chy- strowych obiektów dwuwymiarowych ze dzin. Framework zapewnia wszystko, cze-
ba że właśnie ta dłubanina wciąga was naj- względu na wektorowy charakter modeli go potrzeba do stworzenia gry dwuwymia-
bardziej – wtedy twórzcie silniki i dzielcie trójwymiarowych (zakładając, że nie po- rowej. Znajdziemy tu parser XML’a, obsłu-
się nimi z innymi. Kto wie, może zostanie- rywamy się na nic niestandardowego jak gę rejestru, dźwięku oraz animacji. Two-
cie zauważeni. voxele). rzenie interfejsu użytkownika jest stosun-
W naszym przypadku lista jest krótka Kolejna sprawa to pokrycie naszego kowo proste i już na starcie dysponujemy
– trochę doświadczenia z C++ i PHP. Po- obiektu barwą, czyli stworzenie tekstu- praktycznie wszystkimi potrzebnymi kon-
trafimy coś narysować w Gimp’ie, ale na ry. Musimy namalować obraz dwuwymia- trolkami. Nic, tylko siadać i pisać. Oczy-
tym nasze zdolności artystyczne się, nieste- rowy, który zostanie zmapowany na po- wiście im głębiej w las, tym więcej drzew
ty, kończą. wierzchnię obiektu trójwymiarowego. – framework nie jest pozbawiony wad. Nie
Na tym etapie trzeba zdecydować, czy pi- Można więc powiedzieć, że i tak musi- powinny one jednak przeszkadzać w two-
szemy grę dwuwymiarową, czy trójwymia- my wykonać pracę, której wymagałaby na- rzeniu pierwszej gry. Nie musimy ograni-
rową. Większość z nas w pierwszym odru- sza gra, gdybyśmy zdecydowali się na gra- czać się do PopCap’a – jest wiele innych
chu powie, że oczywiście trójwymiarową. fikę dwuwymiarową. W zależności od te- bardzo dobrych bibliotek i framework’ów
W tym przypadku jednak więcej nie za- go, na jak złożone efekty specjalne i oświe- wspomagających tworzenie gier dwuwy-
wsze znaczy lepiej. Jak powiedział Anto- tlenie się decydujemy na tym etapie, może- miarowych – chociażby SDL, Allegro czy
ine de Saint-Exupéry „wiesz, że osiągnąłeś my skończyć prace nad modelem lub jesz- Blitz2D.
perfekcję w projekcie, nie, gdy nie masz już cze wygenerować mapy normalnych, ma- W przypadku gdy decydujemy się reali-
nic do dodania, lecz gdy nie możesz już nic py nierówności, mapy odbić i co tylko nam zować nasz projekt w trzech wymiarach,
uprościć”. Zastanówmy się , czy ten trzeci przyjdzie do głowy. wybór jest jeszcze większy. Możemy zdecy-
wymiar jest rzeczywiście konieczny. Czy Oczywiście możemy znaleźć darmowe dować się na silniki graficzne takie jak Irr-
bez niego gra nie będzie ciekawa? Czy me- modele trójwymiarowe w sieci. Jednak licht lub Ogre. Jako że są to silniki graficz-
chanika nie może działać w dwóch wymia- doświadczenie uczy, że dużo trudniej jest ne same w sobie nie oferują żadnej funkcjo-
rach? Jeśli zdecydujemy się na realizowa- znaleźć odpowiadający nam model trójwy- nalności poza wyświetlaniem sceny. Tu z po-
nie gry w trzech wymiarach, musimy li- miarowy niż bitmapę dwuwymiarową. Na- mocą przychodzą społeczności powstałe wo-
czyć się ze znaczącym wzrostem nakładu wet gdy znajdziemy odpowiedni obiekt, kół tych projektów. Z łatwością znajdziemy
pracy i złożoności zadania. W przypadku może okazać się, że nie posiada on wszyst- dodatkowe narzędzia ułatwiające budowa-
gry dwuwymiarowej do stworzenia grafi- kich map, których potrzebujemy lub jest nie silnika gry.
ki wystarczy usiąść do przysłowiowego „pa- wykonany w sposób uniemożliwiający wy- Ponieważ zdecydowaliśmy się na reali-
inta” na kilka minut i naszkicować sprite’a. korzystanie z naszymi metodami wyświe- zację naszej gry w dwóch wymiarach, wy-
Może być nawet paskudnie brzydki – pro- tlania. bieramy framework PopCap. Pozwoli to
grammers art’y też mają swój urok i przede W naszym konkretnym przykładzie naj- nam bardzo szybko stworzyć pierwszą wer-
wszystkim pozwalają zaprezentować pro- rozsądniejszym rozwiązaniem wydaje się sję gry.
jekt innym osobom. Oczywiście może- być grafika dwuwymiarowa. Gry platfor- Do obsługi dźwięku możemy wykorzy-
my także skorzystać z ogromnej ilości gra- mowe jako gatunek kojarzone są z dwuwy- stać gotowe biblioteki, takie jak FMOD lub
fik dostępnych za darmo w sieci. Przykła- miarowymi planszami. Dzięki uproszcze- OpenAL (Open Audio Library). Pierwsza
dem może być Reiner`s Tilesets – zbiór do- niu świata gry będziemy mogli szybciej za- z nich jest biblioteką komercyjną. Jeśli bę-
stępnych za darmo obiektów i tile’i do gier implementować zasady rozgrywki i skupić dziemy chcieli sprzedawać naszą grę, musi-
w rzucie izometrycznym. Pewnym proble- się na dodawaniu ekstra funkcjonalności my liczyć się z kupnem kosztownej licen-
mem jest tworzenie przyzwoicie wyglądają- takiej, jak rzucanie bananem w odległych cji – nawet do kilku tysięcy dolarów. Jeśli
cych animacji dwuwymiarowych. Koniecz- przeciwników. jednak nasza gra ma być produktem dar-

www.sdjournal.org 35
Programowanie gier

mowym, możemy korzystać z FMOD bez- rych często dochodzi do interakcji z oto- będzie strzelanką, w prototypie powinni-
płatnie. czeniem w trudny do przewidzenia spo- śmy móc strzelać i niszczyć wrogów. Ce-
Tym, którzy od komercyjnych bibliotek sób, takie jak różnego rodzaju strzelanki lem może być dotarcie żywym do określo-
dostają wysypki, na pewno przypadnie do lub symulatory wyścigów, prawdopodob- nych drzwi.
gustu OpenAL. Jest to biblioteka w peł- nie skorzystają na zaimplementowaniu Generalnie prototyp powinien powstać
ni open source, rozwijana przez społecz- symulacji fizycznej. Do wyboru jest bar- w kilka dni, a w idealnej sytuacji godzin.
ność na wzór OpenGL (choć nie w tak sko- dzo dużo zarówno komercyjnych, jak i dar- Jeśli w ciągu tygodnia nie jesteśmy w sta-
ordynowany sposób). Dzięki temu nazew- mowych rozwiązań. Popularniejsze biblio- nie ukończyć prototypu ,może być to ważna
nictwo i konwencje nazw przypominają teki open source to Open Dynamics Engi- wskazówka, że nasz projekt jest zbyt obszer-
OpenGL. ne (ODE), Bullet, Tokamak. Spośród po- ny jak na nasze możliwości i trzeba zrewido-
Wybrany przez nas framework PopCap zostałych rozwiązań warto wymienić Ha- wać plany. Może na początek warto stwo-
posiada moduły odgrywające dźwięk, jed- vok, PhysX oraz Newton Game Dynamics. rzyć prostszą grę, którą będziemy potem
nak decydujemy się na zaimplementowa- Praktycznie wszystkie te silniki pozwolą rozszerzać o nową funkcjonalność? Tak czy
nie własnego modułu wykorzystującego bi- nam zaimplementować realistycznie za- inaczej bardzo ważne jest , abyśmy jak naj-
bliotekę OpenAL. Jest darmowa i oferu- chowujące się bryły sztywne, efekty czą- szybciej mogli zobaczyć efekty swojej pracy
je dźwięk przestrzenny, co jest dla nas bar- steczkowe oraz efekt rag-doll (wykorzysty- w postaci działającej gry. Da nam to siłę i mo-
dzo ważne. Przecież chcemy, żeby odgłos wany do symulowania realistycznie padają- tywację do dalszej pracy!
banana uderzającego w biznesmana dobie- cych bezwładnych ciał). Dzięki prototypowi stosunkowo wcze-
gał dokładnie z miejsca, w którym znajdu- W naszej grze zdecydowaliśmy się wyko- śnie możemy stwierdzić , czy nasza gra jest
je się małpa i brzmiał inaczej w zależności rzystać silnik ODE. Użyjemy go, by zasymu- interesująca i czy nasze pomysły faktycznie
od otoczenia. lować realistyczne upadki postaci trafionych sprawdzają się. Jeśli nie – oszczędziliśmy
Kolejnym ważnym elementem naszej bananem oraz różne przedmioty, które mał- właśnie sporo czasu. Jeśli tak – możemy od
gry mogą, lecz nie muszą, być skrypty. pa może przewrócić. Takie smaczki nie bę- razu sprawdzić, czy wymyślone sterowa-
Zaimplementowanie silnika skryptowego dą miały wpływu na rozgrywkę, jednak bę- nie sprawdza się, czy interfejs jest czytelny
może nam pozwolić na przeniesienie czę- dą dawały graczowi dużo satysfakcji z poko- i tak dalej. Możemy też pokazywać proto-
ści logiki poza kod. W szczególności po- nania wroga i sprawią, że plansza będzie bar- typ ewentualnemu inwestorowi lub współ-
zwoli to na modyfikowanie parametrów i dziej interaktywna. pracownikom (na przykład grafikowi ,któ-
zachowań obiektów w świecie gry bez ko- Możemy także zdecydować się na kom- ry zachwycony wciągającą rozgrywką przy-
nieczności rekompilacji silnika. Nie każda pleksowe rozwiązanie i wykorzystać gotowy gotuje nam profesjonalną oprawę wizual-
gra wymaga implementowania skryptów silnik gry. Tu wybór jest bardzo duży. Więk- ną). Taki prototyp możemy pokazać w sieci
– na pewno nie będą potrzebne w prostej szość silników dostarczana jest wraz z narzę- i próbować ewentualnie zwerbować pomoc
platformówce czy grze logicznej. General- dziami i edytorami pozwalającymi w wy- do naszego projektu. Jeśli nie możemy po-
nie wszędzie tam, gdzie mechanika gry jest godny sposób projektować gry. Minusem za- chwalić się działającą wersją gry, zostanie-
powtarzalna i nie występują nieprzewidzia- stosowania gotowego silnika będzie oczywi- my potraktowani w najlepszym razie jak
ne zdarzenia, skrypty są zbędne. Będą za ście utrata elastyczności , jaką daje nam na- marzyciele i zachęceni do dalszych prac.
to niezastąpione w grach role-playing lub pisanie własnego silnika dopasowanego do Takimi miejscami w sieci ,gdzie możemy
przygodówkach. naszych potrzeb. Może się jednak okazać, podzielić się naszymi doświadczeniami
Dwa języki, które można polecić, to z że znajdziemy silnik doskonale pasujący do lub skorzystać z wiedzy i doświadczenia
pewnością Lua oraz Python. Prawdopodob- wizji naszej gry. Warte uwagi pozycje to To- innych przy pisaniu gier, jest na przykład
nie lepszym rozwiązaniem (przynajmniej na rque Game Engine, Blitz3D, Unity i id Tech GameDev.net lub nasz rodzimy Warsztat
początek) będzie wykorzystanie Lua. Jest to od 1 do 3 (silniki , na których powstał Do- (www.gamedev.pl).
język skryptowy projektowany z myślą o in- om, Quake 2 oraz 3), Virtools czy Blender W naszym idealnym przypadku wokół
tegracji z C lub C++. Jest bardzo lekka, szyb- Game Engine. Niektóre z wymienionych naszego projektu powstaje prężna społecz-
ka i prosta do opanowania. Te cechy spra- silników pozwalają na tworzenie gier prak- ność zdolnych ludzi nienawidzących biz-
wiają , że jest bardzo popularna wśród twór- tycznie bez pisania kodu – w VirTools mo- nesmenów w garniturach, ale lubiących
ców gier. żemy dosłownie składać grę z klocków meto- rzucać bananami. Szybko powstaje fanta-
Nasz projekt nie wymaga silnika skrypto- dą drag and drop. styczna komiksowa oprawa graficzna i gra
wego. Co prawda rozważaliśmy dodanie nie- podbija serca graczy. A druga część także
standardowych zachowań planszy takich jak Prototyp portfele.
walące się budynki czy załamujące się pod Bez względu na to, jaki silnik zdecyduje- Pozostaje życzyć powodzenia w zmaga-
małpą kładki dla pieszych. Jednak po do- my się wykorzystać, pierwszą rzeczą, któ- niach z pierwszą grą!
kładnej analizie doszliśmy do wniosku, że rą stworzymy, powinien być prototyp na-
takich zdarzeń będzie niewiele i szybciej bę- szej gry. Prototyp jest to bardzo prosta wer-
dzie zaprogramować je na twardo niż imple- sja gry pozwalająca zapoznać się z mecha-
mentować skrypty. Nie ma sensu wytaczać niką rozgrywki i ją przetestować. Najczę-
artylerii na muchę. ściej opiera się na bardzo prostych elemen-
Ostatnim wartym rozważenia elemen- tach graficznych i powinien pozwalać gra-
tem jest wykorzystanie biblioteki symula- czowi na zagranie w grę i jej wygranie (lub
cji fizycznej. Nie powinniśmy dać się po- przegranie). Jeśli piszemy grę przygodową,
nieść modzie na symulowanie wszystkie- prototyp powinien być jedynym zadaniem, KONSTANTY KALICKI
go. Musimy się zastanowić , czy nasza gra które postać musi wykonać – na przykład Opiekun specjalizacji Programowanie Gier Kom-
potrzebuje symulacji fizycznej. Jeśli to wydostać się z celi, wykorzystując znale- puterowych na PJWSTK
przygodówka, to pewnie nie. Gry, w któ- ziony pod pryczą widelec. Jeśli nasza gra epg@pjwstk.edu.pl

36 02/2010
������������������

��������������������
������������
�������������������������������������������������������������������
�������������������������������������������������������������������
����������������������������������������������������������������������������
��� ��������� �������� �� �������� ������������ ������ ��� ��� ��������
����������������������������������������������������������
�������� ���� ������������� �������� �� �����
������������ �������������������� �������������������������������������������
��� ��������������������������������� ��� ���������������������������������������� ���������� ��������� ��� ��� ���������������
��� ����������������������������������������� ����������������������� ��������� ����� ������ ��������� �����������
����� ��������������������������������������
��� �������������������������� ��������������������������������������������
������ ������� ��� �� ��������� ����������
�������� ���������� ������������ ���� ������
�������������������������������������������
������������������������������������������ ��� ���������� ���������� �� ���� ������� ���� �����
�������������������������������������������� ��������� ���� �������� ���������� �� ����������
������� ���������������������������������������� �������������� �������� ������ ���������� ���
��������� �������������������� ���� ������� ��� ����������� ��� ����������� ����
�����������������������������������
��� ������ �������� ������ ����� ��������� ��� �� ��������� ������������� ��������� ��� ������
���������������������������������������� �����������������������������������������������


��� ������� ����� ��� ������ ������� ��� ������ �������� ������ ����� ������������ ��� ����� �������������������������������������������
������������� �������� ������ ������ ������� ���������� �������� ���� ������ ��� ����� �������� �������� �� ��������� �����������
������ ������ ������������� ����� ���������������� �������� �� ��������� ������ ��������������������������������������������
���������������������������������������������� ����������������������������������������� ���������� �� ������� ������� �� ����������������
������������������������������������������ �������������������������������������������� ������������������������������������������
�������������������������������������������� ������������������������������������� ��������������������������������������������
������������ ��� ��� ��� ���������� �������� ���� ��� ������� �� �������������� ���� ���������
����� ������� �� ����� ����� ����������� ���� ����� ������������������������������������������ ��������������������������������������������
�������������� ��������� �������� �������� ������������������������������������������ ���������������������������������������������
����������������������������������������� ����������������������������������������������� ��������� ���������������������� �� ������������
������������������������������������������� ����������� �� ����������� ��������������� ���� �������������������������������������������
������������������������������������������� ����� ������� ��� �������� ������� ��������� ��� ������������������������������������������
��������� ��� �� ���� ������� ��� ��������� ����� ���� ������������ �� ���������� �������� ��������������������������������������������
���������� ����� ������������ ����������� ��������������������������������������������� ���������������������������������������������
����� ������� ����� ������������ ��� ���������� �� ������� ����������� ������ ��������� ��������� ���������������������������������������������
����������������������������������������������� ��������� ��� �� ��������� ��� ������� ������
���������������������������������������� �����������������������������������������
�������������������������������� ������� ����������� ����� �� ������� �������
��������� ����������� ����������� ����� �����������������
���� ���������� �� ������� ������������ ������� ������������ ������ ��������� ��� ��������
��� ���������� ������ ���������� ������ ������ �������������������������������������������
������ ����������� ��� ������� ������� ������� �������������������������������������������
����� ��� �������� ��� ������ ����� ����������� ���� ��������� ���������� �� ����������� �� ��
����� ����� ���������� �� ������� ��������� ���� ��������������� ����������� ���� ���������
��� �������� ����������� �� ������� ��� ������� �����������������������������
���������������������������������������� ��������� �������������� ��������� ��� ���
��� ��������� ��� �������� ��� �������������� ����������� ���� ����� ���������� ������ ������ �������������������������������������

�� �������
���������������������������������������������� ����������������������
��������������������������������������������� ����������������������������
����������������������������������������������� ����������������������������������������
������������������������������������������� ���������������������������������������������
��� ������ ��������� ��� ����������� �� ������ �� �������������������������������������������
��������������������������������������������� �������������������������������������������
���������������������������������������������� ���������������������������������������������
������������������������������������������ �������������������������
������������ ���������� ��������� �������������
��������������������������������� ��� ������ ��������� ������������ �������� �����
��������������������������������������� ������� ���������� ����� ���������������
������������������������������������������� ��������� ��� ������� ������� ��� ������ �����
������������������������������������������� ���������������������������������������
������������������������������������������ ��������������������������������������
����������������������������������������������� ����
�������������������������������������������� ��� ����������������������������������������������
��������������������������������������� �������������� ����������� �� �����������
����������������� �������������������������������������
������� ������ ��������� ����� ��������� ��� ������� ����� �������������������
������������ ���������������������������������������
�����
���������������
������ �������������������������������������������
���������������������������������������� ����������� ������� ��� ������� �������� ���
������������� ���������� ����� ���������� �������� �������
�������������������������������������� ������ ������ ������� ����������� �� ������
��� ����� �� ���������� ���� �������� ������������

���������������������

�������� ��������������������� �������������


��� ����� �� ������������������ ��
�����������������������������
�� ������������� �� ������ ����
�������������������������
����
���������������������������� �������������
���
���
���

���������������������

�������� ������������������������������������ �������������


��� ���� ������������� �� ���������� ��
�� ������������� �� ������� ����
����������������������������������
���
���
�������� �������� �� ������������ ��
��� ����� �� ������������������ ��
�����������������������������
�� ������������� �� ����������� ������������������������������
�������������� ����
����������������������������������������
�����
���
���
���
���

����������������� ��
������������������

��������������������������������������������� ��������� �� ���������� ���� ��������� ������ ��� ������� �� ������� ������� �����������
��������� ������ ��������� ������ �������� ���� ������������������������������������ �������� �� ���� ����������� ��� ��������� ����
����������������������������������������� ��� ����������������������������������������� �������� ������� �������� ������ ����������
��� ��� ��������� ����������� ������������ ����� ���������������������������������������� ��������������
����������������������������������������� ����������� ��������� ��� ���������� ����
�������������������������������������������� �������������� ������������� ������������� ������������ ���� ���������� ���������� �����
����� �� �������� ������� ����� �������� ������ ���������� ��� ������������ ��������� �� �������������������������������������������
������������������������������������������� ����������������������������������������� ����� ����� ����� �������� ��� ��������� ����� ����������
�������������������������������������������� ���������� ���� ��������� ���� �������� ����� ����������������� �����������������������������
������������������������������������������ ������������������������������� �����������������������������������������������
������������������������������������������� ������������������������������������
����������������������������������������� ������������� ���� ������ ����� ��������� ��� �� ���������� ���������� �������� ��������
������������������������������������������� �������� ��������� ���� ����� ������� ����������� ������� ���������� ����� ������� ������������ ���
����������������������������������� ��������� ����� ������ ����������� ��������� ��������������������������������������������
�� ����������� ����� ����� ��� ���������� ���������������������������������������� ��������������������������������������������������
��������������������������������������������� ��� �������� ��� ������ ��������� ��� �����������
���������������������������������������������� ��� ��������� �� ����� ������� ����� �� ����� ��� ����������������������������������������������
����� ��������� ������ ��� ������� ������ �������� ����������� ���������� ������������ �� ���� ����������������������������������������������
�������������������������������������������� ���� ����� ���� ������ ��������� �������� �� ��� ������������������ �������� ��������� �����
��� ������������ ��������� ���� ��������� ����� ������������������������������������� �������������������������������������������������
��������������������������������������������� �������������������������� ����������������������������������������
������������������������������������������� ��� ������ �� ������ ������� ��� �������� ����� �������������������������������������
�������������������������������������������� ���������������� ������ ����� �� ������� ��� �������������������������������������������
��������������������������������������������� ���������������������������������������� ����������������������������������������������
����������� ������������� ������� ��������� �� ��������� �������� ��������� �������� ������������������������������������������������
�������������������������������������������� ��������������������������������� ������������������������������������������������
���� ��������� �������� ����������� ��� �������� ������������������������������������������������
������������ ���������� ���� ���������� �������� ����������������������������������������� ��������������������������������������������
��������������������������������������������� ������������������������������������������� �������������������������������������������������
��������������������������������������������� ��� ������ �������� ��������� ����� ���������� �����������������������������
������������������������ ����� ������������ ��������� ��������������� ��������������������������������������������
����������������������������������������� ������������ �������� ��������� ��������� ���
��� ������ ������������ ��� �������� ��� ������ ����������������������������� ������ ������ �������� �� ����������� �����������
������������ �������� ����� ����������� ���� ������������������������������������������������
�������� ������ ����������� �������� ����� ������������������������� ��������� ������� ���� ���������� ��������������
�������� ����� ���������� ������������� ������������������������������������������� ��� ���� ��� ��������� �������������� �������
����������������������������������������� ��������������������������������������������� ����� ����� ������� �������� ���� ��� �������������
�������� �� �������� ��������� ����� ���������� ���� ������������� ������� ��� �� �������� ����������
���� �� ������ ��������� ���� ������ ����������� ��������� ������������� ����� �� ������������ ���
�������������������� �������� ���� ���� �� ���������� ����������� ���
������������������������������������
�������������� ����� �� ��������� ��������� ����������
������������������������������ ���������� ���� ������� ��� ��������� ������ ���
� �������������������������������������������
��������������������������������������������
���������� ������ ��������� ��� �������� ������ ���� �������� ������� ����� ��������������� ����
�������������� ���������� ������������ �� �������� ��������
��������������
������������������������������������� ����������������
���������
� ���������������������
����� ������������� ��������������� ��������
��������������������������������������� ����� ����������� ������� ���������� ����� ��������
������� ��� ���������� ��������� �� ��������� �� ����
��� ����������� ������� ������� ����������� ����������������������������������������������
�������������� ��� ����������� ������������ �� ������ ��������
��� ��������� �� ������� ������� ����������� ���������������������������������������������
��������������� ������ ��������������� ���������� ���������� ���
��� �������� �� ��������� ������� ��������� ��������������� ������� ������ ����� ������������
�������������������������������������� ���������������������������������������������������
��� �������� �������� ����� ���������� ����� �������������������������������������������������
����������������������������������������������� ���������������������������������������� ����� �������� �� ������� ������ ����������� �������� ����
���������� ���������������������������� ���������������������������������������

�� �������
������������������������
Programowanie gier

Mapy kafelków
w grach 2D
Wstęp i rysowanie
Marzysz o stworzeniu swojej wymarzonej dwuwymiarowej platformówki
albo klasycznego RTSa? Od czego zacząć? Oczywiście od map kafelków
(ang. tiled maps). Dzięki temu artykułowi poznasz podstawy tej techniki
– dowiesz się, jak mapy kafelków zaprogramować i jak je rysować.
W skrajnej formie wersji rastrowej może-
Dowiesz się: Powinieneś wiedzieć: my narysować cały świat jako jeden ogrom-
• W jaki sposób działają mapy kafelków (ang. • Podstawowa znajomość C++ i biblioteki SDL ny obrazek. W wersji wektorowej cały świat
tiled maps); lub podstawowa znajomość Javy. reprezentowany jest przez np. zbiór wielo-
• Jak rysować mapy kafelków; kątów. Oba podejścia różnią się m.in. zuży-
• Jak zastosować kilka sztuczek optymaliza- ciem pamięci, mocą obliczeniową potrzeb-
cyjnych. ną do rysowania, złożonością algorytmów,
dokładnością, z jaką możemy tworzyć ele-
menty świata, czy łatwością ich tworzenia i
jące zobrazować pewne zagadnienia. Jako modyfikowania.
że kompletny, przykładowy kod też jest do- Podejście typu wielki obrazek pociąga za so-
Poziom brym źródłem informacji, do artykułu do- bą ogromne zużycie pamięci, ale za to ryso-
trudności łączona jest prosta implementacja opisywa- wanie w tym przypadku jest szybkie i pro-
nego materiału. Jest ona stworzona w Javie ste. Wystarczy narysować na ekranie widocz-
(Micro Edition, projekt w NetBeans) oraz ny fragment obrazu-świata. W każdej chwili
C++ (SDL, projekt w Visual C++ Express możemy dodać (dorysować) nowy element

A
rtykuł ten poświęcony jest jednej 2008). Wszystkie narzędzia potrzebne do lub szczegół. Z drugiej strony, jeśli naraz chce-
z podstawowych technik używa- uruchomienia dołączonego kodu dostępne my zmienić wygląd dużej części świata, trze-
nych do tworzenia dwuwymia- są za darmo. ba go mozolnie przerysować. Trzeba także wy-
rowych gier – mapom kafelków (ang. tiled myślić sposób przypisania różnych cech róż-
maps). Metoda ta używana jest z powodze- Wykafelkuj sobie świat nym obszarom świata.
niem od bardzo dawna, a z jej użyciem po- Wyobraźmy sobie, że chcemy stworzyć pro- Wersja geometryczna to najczęściej mniej-
wstało dużo świetnych gier. Mimo iż w dzi- gram, powiedzmy grę, w którym będzie wy- sze zużycie pamięci, ale wymaga znacznie
siejszych czasach może wydawać się trochę stępował pewien dwuwymiarowy świat. większej mocy obliczeniowej przy rysowa-
archaiczna, to stanowi świetny punkt wyjścia Chcemy, by po tym świecie mogła poruszać niu, a samo rysowanie trudniej jest zaim-
w nauce programowania gier, a także ciągle się postać sterowana przez gracza. Oczy- plementować. Dodanie nowych elementów
doskonałą i stosowaną technikę w programo- wiście świat musi być widoczny, więc bę- świata wymaga dodania nowych wielokątów
waniu na urządzenia o ograniczonych zaso- dziemy go rysować na ekranie. Świat powi- lub edycji istniejących. Wraz ze wzrostem
bach, np. telefony komórkowe. nien być dość duży, na pewno większy niż złożoności i ilości geometrii coraz trudniej
Artykuł wprowadza w świat map kafel- ekran. Oglądać go będziemy z boku (al'a Ma- połapać się w edycji świata. Plusem tego po-
ków, a następnie przedstawia sposoby ich rio Bros) bądź z góry (al'a klasyczne RTSy). dejścia jest łatwość nadawania cech obsza-
implementacji. Kolejnym zagadnieniem bę- Chcemy, żeby różne fragmenty świata mia- rom świata – możemy na przykład przypi-
dą układy współrzędnych używane w ma- ły różny wygląd i różne właściwości (np. że sać cechy wielokątom lub stworzyć specjal-
pach oraz prosta metoda ich rysowania. coś jest z cegieł albo z trawy, że po czymś ne kształty, które nie będą rysowane, a bę-
Temat rysowania zostanie następnie roz- gracz może się poruszać, a po czymś nie itp.) dą służyć jedynie do opisywania cech wybra-
szerzony o rysowanie z buforem. W artyku- A do tego chcemy takich światów mieć kil- nych obszarów.
le znajdzie się też kilka sztuczek optymali- kanaście, np. jako różne plansze w grze. Jak Istnieje jednak technika, która wpasowu-
zacyjnych. to zrobić? je się gdzieś pomiędzy te skrajne podejścia.
Tekstowi będą towarzyszyć Rysunki i Istnieje wiele różnych technik. Podzielo- Z jednej strony opiera się na rysowaniu przy
Listingi. Listingi pełnią rolę koncepcyj- ny jest ogólnie na dwie grupy – rastrowe i użyciu obrazków, ale jednocześnie pozwala
ną – będą to fragmenty pseudokodu ma- wektorowe (pikselowe i geometryczne). na wyodrębnienie poszczególnych fragmen-

42 02/2010
Mapy kafelków

tów świata, operowania na nich i nadawania pewnych obiektów. Mogą to być przeciwni- Tak naprawdę, przedstawiony powyżej po-
im cech. Do tego dochodzi małe zużycie pa- cy czy przedmioty, które gracz może zbie- dział jest dość umowny, niektóre informacje
mięci oraz łatwość i szybkość rysowania. Z rać. Mogą to też być obiekty niewidoczne, można zaliczyć do kilku grup. Najważniej-
drugiej jednak strony odbywa się to kosztem np. punkt startowy planszy czy punkt na- sze jest, aby pamiętać, że kafelek może prze-
dokładności i szczegółowości, z jaką może- wigacyjny dla algorytmów sztucznej inteli- chowywać dowolne informacje dotyczące je-
my tworzyć świat. Technika ta opiera się na gencji. go obszaru.
przedstawieniu świata za pomocą mapy kafel-
ków (ang. tiled maps).
Idea jest prosta – nakładamy na świat
siatkę (jak w zeszycie w kratkę) i dokonu-
jemy podziału na prostokątne lub kwadra-
towe fragmenty, zgodnie z liniami siatki.
Fragmenty będące wynikiem podziału bę-
dziemy nazywać kafelkami. Wszystkie ka-
felki mają te same rozmiary i sąsiadując ze
sobą, pokrywają całą powierzchnię świa-
ta. Każdy kafelek ma przypisany obrazek
(wszystkie kafelki używają obrazków o ta-
kich samych rozmiarach) oraz dowolne pa-
rametry opisujące obszar zajmowany przez
tafelkę. Nadając wygląd i cechy fragmen-
tom świata, możemy zmieniać tylko po-
szczególne kafelki.
Rysunek 1 pokazuje dwuwymiarowy bar-
dzo szczegółowy świat oraz jego wersję ska-
felkowaną.

Informacje
umieszczone w kafelku
Kafelek stanowi podstawowy element ma-
py. Jest on prostokątem (często kwadratem,
ale nie jest to reguła) zawierającym informa-
cje na temat fragmentu powierzchni świata,
który pokrywa. Są to całkowicie dowolne in-
formacje, sami musimy określić, co jest nam
potrzebne. Można wyróżnić kilka grup ta-
kich informacji: wizualne, fizyczne, rozgryw-
kowe, obiektowe.
Informacje wizualne opisują wygląd ka-
felka i są używane przez algorytmy rysujące.
Może to być obrazek do wyświetlenia w miej-
scu, gdzie znajduje się kafelek, może to być
informacja, że kafelek jest niewidoczny, mo-
że to być kolor (np. jeśli chcemy, aby kafelek
był jednolicie wypełniony kolorem).
Informacje fizyczne zawierają cechy uży- Rysunek 1. Dwuwymiarowy świat i jego reprezentacja z użyciem kafelków. Zaledwie dziesięć kafelków
wane w procesie symulacji świata gry. Na pozwoliło na dość wierne odwzorowanie
przykład, czy gracz może przejść przez kafel-
ka, czy może go zniszczyć, jego wytrzymałość
na uderzenia, śliskość jego powierzchni (może
wpływać na ruch gracza), wartość i kierunek
siły grawitacji itp.
Informacje rozgrywkowe to wszelkie in-
formacje specyficzne dla mechaniki i zasad
naszej gry. Na przykład, ilość życia, jaką tra-
ci gracz wchodząc na kafelka, dozwolony czas
przebywania na kafelku (powiedzmy, że po
tym czasie gracz ginie), czy kafelek został od-
wiedzony (np. jeśli chcemy, żeby gracz musiał
dotrzeć do pewnych wyznaczonych miejsc w
świecie).
Informacje obiektowe najczęściej dotyczą Rysunek 2. Mapa (z lewej) i ekran (z prawej). Na czerwono zaznaczony jest viewport; znajduje się on
występowania w miejscu położenia kafelka zarówno w mapie, jak i na ekranie

www.sdjournal.org 43
Programowanie gier

Warto też zauważyć, że cechy kafelka nie


Listing 1. Reprezentacja przykładowego kafelka przez klasę; pseudokod muszą być liczbami. Na przykład zamiast
class Tile trzymać ogólną informację, czy przez kafel-
{ ka można przejść, można przechowywać ob-
short imageId; // id of an image used to draw a tile szar kolizyjny (np. w postaci wielokąta). W
boolean isSolid; // if true – tile collides with a player przykład kierunku i siły grawitacji w kafel-
byte lifeMod; // life modifier ku przechowywać będziemy odpowiedni
} wektor. Może to nawet być tekst, np. wiado-
mość wyświetlana na ekranie, gdy gracz wej-
void foo() dzie na kafelka.
{
Tile myTile = new Tile(); // create new tile Kafelek w pamięci
myTile.lifeMod = SOME_VALUE; // change tile's property W tym momencie mamy w głowie ideę map
short lifeMod = myTile.lifeMod; // read tile's property kafelków i tworzenia świata za ich pomocą.
} Kolejnym krokiem jest przeniesienie idei do
programu – do naszej gry.
Listing 2. Reprezentacja przykładowego kafelka przez pole bitowe wraz z funkcjami dostępu do Zaczniemy od stworzenia reprezentacji ka-
informacji; pseudokod
felka. Wiemy, że kafelki są kontenerami zawie-
int TILE_SHIFT_imageId = 0; rającymi różne informacje na temat pewnego
int TILE_MASK_imageId = 0xffff; miejsca w świecie. Potrzebujemy zatem struk-
tury danych, która będzie te różnorodne in-
int TILE_SHIFT_lifeMod = 16; formacje przechowywać. Mamy co najmniej
int TILE_MASK_lifeMod = 0xff; dwie opcje:

int TILE_SHIFT_solid = 24; • obiekty – informacje zapisane są jako po-


int TILE_MASK_solid = 0x1; la klasy;
• liczby całkowite traktowane jak pola bi-
void set_tile_lifeMod( int tile, short value ) towe – informacje zapisane są na kolej-
{ nych bitach liczby całkowitej.
value =<< TILE_SHIFT_lifeMod;
tile &= value; Jak to wygląda w praktyce? Powiedzmy, że
return tile; chcemy, aby nasze kafelki przechowywały
} następujące informacje:

short get_tile_lifeMod( int tile ) • identyfikator obrazka używanego do ry-


{ sowania kafelek;
short lifeMod = tile >> TILE_SHIFT_lifeMod; • flagę mówiącą o tym, czy kafelek jest pu-
lifeMod &= TILE_MASK_lifeMod; sty (gracz może po nim przejść), czy nie
return lifeMod; (gracz koliduje z kafelkiem);
} • ilość życia, którą gracz straci (wartości
ujemne) lub zyska (wartości dodatnie),
void foo() stykając się z kafelkiem.
{
int myTile = 0; // create new tile Listingi 1 i 2 zawierają przykładowe spo-
myTile = set_tile_lifeMod( myTile, SOME_VALUE ); // change tile's property soby implementacji takiego kafelka wraz z
short lifeMod = get_tile_lifeMod( myTile ); // read tile's property prostym przykładem użycia – stworzenie
nowego kafelka oraz odczyt i zmiana jed-
ASSERT( lifeMod == SOME_VALUE ); // we've set tile's life modifier nej z informacji przez niego przechowy-
// to SOME_VALE, so getting it back wanych. Listingi są napisane w pseudo ko-
// from tile must give the same value dzie, ale można je łatwo dostosować do C++
lub Javy.
Listing 3. Kafelek jako mapa cech: implementacja w języku C++ Listingi 1 i 2 zawierają przykładowe spo-
// empty tile soby implementacji takiego kafelka wraz
std::map< std::string, boost::any > m_tile; z prostym przykładem użycia – stworze-
nie nowego kafelka oraz odczyt i zmiana
// let's add gravity vector property to the tile jednej z informacji przez niego przecho-
m_tile["gravity"] = Vector2( 0, -3 ); wywanych. Listingi są napisane w pseudo
kodzie, ale można je łatwo dostosować do
// read the gravity vector property C++ lub Javy.
Vector2f& gravity = boost::any_cast<T&>( m_tile[„gravity"] ); Listing 1 to wersja, w której używamy kla-
sy. Zaletą tego rozwiązania jest łatwość i oczy-
wistość kodu – po prostu odnosimy się do po-
la klasy.

44 02/2010
Mapy kafelków

Listing 2 to wersja, w której informacje o tem pierwszym rozwiązaniem, jakie nasu- tać, że tablice w C++ i Javie są indeksowa-
kafelku są zapisane na bitach liczby całkowi- wa się na myśl, jest użycie dwuwymiarowej ne od zero, czyli pierwsza kolumna i pierw-
tej. Ta wersja jest trochę bardziej zagmatwa- tablicy zawierającej kafelki, obojętnie, czy szy rząd to 0,0.
na od wersji z klasą. Nie mamy bezpośred- są one reprezentowane jako obiekty, czy
niego dostępu do składowych kafelka – mu- pola bitowe. Jest to rozwiązanie proste i in- Mapa w pamięci
simy stworzyć sobie pewien mechanizm do- tuicyjne, gdyż bardzo łatwo i bezpośrednio – tablica jednowymiarowa
stępu do nich. W tym przykładzie są to funk- możemy określić rozmiar mapy i odwołać Na niektórych platformach występują różne
cje set_tile_lifeMod i get_tile_lifeMod. się do interesującego nas kafelka. problemy z tablicami wielowymiarowymi.
Zaletą tego podejścia jest łatwość kopiowania Listingi 5 i 6 przedstawiają przykłady Czasami rozwiązanie takie może być niedo-
kafelków oraz łatwość zapisu i odczytu mapy w Javie i C++. Jest tam reprezentacja ma- stępne, czasami może działać wolno.
do/z pliku. py, jej tworzenie (o zadanym rozmiarze) i Z takich czy innych powodów zamiast
odwoływanie się do konkretnego kafelka tablic dwuwymiarowych można użyć ta-
Kafelek jako mapa cech (znajdującego się w czwartej kolumnie i blic jednowymiarowych. W tym przypad-
Istnieje jeszcze inna, ciekawa, aczkolwiek trzecim wierszu). Na listingach widać, jak ku mapa w pamięci stanowi długi pasek ka-
rzadko stosowana metoda – możemy kafel- łatwo wykonuje się te czynności; po pro- felków, a kolejne rzędy są doklejane do sie-
ka zaimplementować jako prawdziwy kon- stu podajemy ilość kafelków w poziomie bie z boku.
tener na różnorodne informacje. Wyko- (szerokość mapy) i pionie (wysokość ma- Jednak pojawia się tutaj pytanie – jak okre-
rzystamy do tego asocjacyjne struktury da- py) oraz rząd i kolumnę kafelka, do którego ślić rozmiar mapy i jak odnieść się do kon-
nych przechowujące elementy dowolnego chcemy się odwołać (3 i 2). Należy pamię- kretnego kafelka? Tablica musi przechowy-
typu – czyli zadajemy pewien klucz i otrzy-
mujemy pewną wartość dowolnego typu. W Listing 4. Kafelek jako mapa cech: implementacja w języku Java
naszym przypadku klucz niech będzie tek-
stem (string). Takie rozwiązanie często na- // empty tile
zywa się property map, czyli mapa cech lub Hashtable m_tile = new Hashtable();
właściwości.
Przykładowa implementacja tej techni- // let's add gravity vector property to the tile
ki w języku C++ (zakładam, że mamy swo- m_tile.put( "gravity", new Vector2( 0, -3 ) );
ją klasę Vector2) przedstawiona jest na Li-
stingu 3. // read the gravity vector property
Podobną strukturę możemy zaimplemen- Vector2 gravity = (Vector2)m_tile.get( "gravity" );
tować w Javie ME (patrz Listing 4).
Jest to podejście bardzo elastyczne i szcze- Listing 5. Mapa jako tablica dwuwymiarowa; Java
gólnie przydatne, gdy tworzymy grę stero- Tile[][] tiledMap;
waną danymi. Możemy określać i dodawać
dowolne cechy kafelków w locie – nie musi- public void CreateMap( int width, int height )
my określać na sztywno w kodzie, jakie po- {
la będzie miała klasa, a możemy np. wczy- tiledMap = new Tile[width][height]; // create empty map
tać definicję kafelka z pliku (czyli możemy
tworzyć różne kafelki bez ponownej kompi- for( int u=0; u<width; ++u ) { // create tiles
lacji programu). Ponadto, kafelki mogą się for( int v=0; v<height; ++v ) {
różnić między sobą cechami, jakie posiada- tiledMap[u][v] = new Tile();
ją, np. niektóre kafelki mogą mieć wartość }
dla gravity, a niektóre nie. W podejściu kla- }
sycznym wszystkie kafelki mają ten sam ze-
staw cech. // make tile in 4th column and 3rd row solid
W praktyce jednak, podejście to nie jest tiledMap[3][2].isSolid = true;
często stosowane ze względu na duży narzut }
pamięciowy (trzeba stworzyć obiekt konte-
nera, który będzie trzymał informacje o sta- Listing 6. Mapa jako tablica dwuwymiarowa; C++
nie zawartości, do tego dużo pamięci zajmu- Tile** tiledMap;
ją klucze w postaci tekstu) i wydajnościowy
(odwołanie się do elementu za pomocą klu- void CreateMap( int width, int height )
cza trwa dłużej niż zwykłe odwołanie się do {
pola klasy). tiledMap = new Tile*[width];
Jeśli jednak narzuty nie stanowią dla nas
problemu, a chcemy stworzyć uniwersalny for( int i=0; i<width; ++i ) {
i elastyczny system, jest to rozwiązanie god- tiledMap[i] = new Tile[height];
ne polecenia. }

Mapa w pamięci // make tile in 4th column and 3rd row solid
Teraz musimy zająć się przeniesieniem do tiledMap[3][2].isSolid = true;
programu całej mapy. Mapa to dwuwymia- }
rowy uporządkowany zbiór kafelków. Za-

www.sdjournal.org 45
Programowanie gier

wać wszystkie kafelki, więc jej rozmiar jest mechanizmy łatwego tworzenia map o za- pewne problemy, używaj tablic jednowy-
iloczynem rozmiaru mapy (w kafelkach) w danym rozmiarze i łatwego dostępu do ka- miarowych.
pionie i w poziomie. Natomiast aby odnieść felka za pomocą jego położenia w siatce ma-
się do konkretnego kafelka, musimy prze- py (kolumna i wiersz). Jeśli nasz kod będzie Przyspieszenie – tablica
liczyć wiersz i kolumnę na indeks w tabli- używał tych mechanizmów, a nie odnosił się indeksów początków wierszy
cy: indeks = wiersz * szerokość mapy w bezpośrednio do tablicy z kafelkami, jeste- Jeśli zdecydujemy się na użycie tablicy jed-
kafelkach + kolumna. śmy zawsze w stanie zmienić reprezentację nowymiarowej do przechowywania mapy,
Listingi 7 i 8 przedstawiają przykłady ana- mapy na inną, bez konieczności zmiany ko- bardzo często będziemy obliczać indeks
logiczne do tych, które były pokazane na Li- du odwołującego się do niej. kafelka na podstawie jego wiersza i kolum-
stingach 5 i 6, ale z użyciem tablicy jednowy- Jeśli wygodnie jest Ci z tablicami dwu- ny w mapie. Dla przypomnienia: indeks =
miarowej. wymiarowymi, to używaj właśnie ich. Jeśli wiersz * szerokość mapy w kafelkach
wolisz mieć pełniejszą kontrolę nad spo- + kolumna. Zatem przy każdym odwoła-
Czego używać? sobem odwoływania się do konkretnego niu się do kafelka wykonywane jest mno-
Suma summarum, sposób reprezentacji ma- kafelka lub na platformie, na którą progra- żenie. Istnieje sposób na pozbycie się tego
py nie jest aż tak ważny, jak to, żeby mieć mujesz tablice wielowymiarowe sprawiają mnożenia.
Zauważmy, że działanie: wiersz * szerokość
mapy w kafelkach daje nam w wyniku indeks
Listing 7. Mapa jako tablica jednowymiarowa; Java pierwszego kafelka w zadanym wierszu. Może-
Tile[] tiledMap; my zatem raz obliczyć indeksy pierwszych ka-
felków dla wszystkich wierszy i przechowywać
public Tile GetTile( int u, int v) je w tablicy. Wtedy operacja obliczania indek-
{ su wygląda następująco: indeks = pierwsze_
return tiledMap[v * mapWidth + u]; kafelki[wiersz] + kolumna. Pozbyliśmy się
} mnożenia przy odwołaniu do kafelka.
Wartości tablicy pierwsze_kafelki łatwo
public void CreateMap( int width, int height ) obliczyć w pętli:
{
tiledMap = new Tile[width * height]; // create empty map for( int i=0; i < ilość_wierszy; ++i )
pierwsze_kafelki[i] = i * szerokość_
for( int i=0; i < width*height; ++i ) mapy;
{
tiledMap[i] = new Tile(); Zmniejszenie zużycia pamięci
} – mapa indeksów do kafelków
Jeśli nie potrzebujemy możliwości modyfika-
// make tile in 4th column and 3rd row solid cji właściwości pojedynczych kafelków w ma-
tiledMap[2*mapWidth + 3].isSolid = true; pie, to można zmodyfikować jej implementa-
cję tak, by zamiast trzymać kafelki trzymała
// the same as above but using convenience function: tylko typ kafelka, a same kafelki przechowy-
GetTile(3,2).isSolid = true; wać gdzieś z boku. W praktyce z boku może
} oznaczać tablicę (taka jakby biblioteka kafel-
ków), a mapa może zawierać indeksy do tej
Listing 8. Mapa jako tablica jednowymiarowa; C++ tablicy.
Tile* tiledMap; Jeśli kafelki zawierają dużo informa-
int mapWidth; cji, można w ten sposób zyskać na pamię-
ci. Ale nie można zmieniać właściwości po-
Tile& GetTile( int u, int v ) jedynczych kafelków. Można jedynie global-
{ nie zmieniać właściwości wszystkich kafel-
return tiledMap[v * mapWidth + u]; ków danego typu (przez zmianę kafelka w
} bibliotece).
Przykład: mapę indeksów to kafelków
void CreateMap( int width, int height ) możemy trzymać jako tablicę short'ów (2
{ bajty na kafelek), daje to nam możliwość
mapWidth = width; posiadania kilkudziesięciu tysięcy różnych
tiledMap = new Tile[width * height]; kafelków (prawie na pewno wystarczy),
a ilość zużytej pamięci = szerokość
// make tile in 3rd column and 2nd row solid mapy * wysokość mapy * 2 + n*ilość
tiledMap[2*mapWidth + 3].isSolid = true; typów kafelków (gdzie n to rozmiar ka-
felka w pamięci). W wersji klasycznej
// the same as above but using convenience function: zużycie = szerokość mapy * wysokość
GetTile(3,2).isSolid = true; mapy * n.
} Dla mapy, powiedzmy, 60x30 kafelków z
kafelkiem zajmującym 10 bajtów i 100 róż-
nymi kafelkami wygląda to następująco:

46 02/2010
Mapy kafelków

• wersja klasyczna = 60*30*10 = 18000 układ ekranu, ma swój początek w górnym le- wiersza w mapie. Służy on do wskazywania
• wersja indeksowa = 60*30*2 + 100*10 = wym rogu ekranu. konkretnego kafelka, np. (1, 4) oznacza kafe-
3600+1000 = 4600 Występuje jeszcze jeden układ współrzęd- lek w drugiej kolumnie i piątym wierszu ma-
nych, który ma inne jednostki. Nazwijmy go py (pamiętajmy o numerowaniu od zera).
Im większa mapa, tym większy zysk na pa- kaflowy układ współrzędnych – jest to układ, Rysunek 3 pokazuje wzajemne zależności
mięci w wersji indeksowej. Technika ta mo- w którym współrzędne to numer kolumny i między układami.
że być bardzo przydatna na platformach z
ograniczoną ilością pamięci, np. na telefo- Listing 9. Klasa Viewport; pseudokod
nach komórkowych.
public class Viewport
Okno na świat {
Mamy przygotowane struktury danych /* size of viewport in pixels */
przechowujące kafelki i mapę. Powoli zbli- int width;
żamy się w kierunku rysowania. Zanim jed- int height;
nak tego dokonamy, musimy określić dwie
rzeczy: /* position of top-left corner of viewport in the world */
int worldX;
• co chcemy rysować – jaki wycinek mapy; int worldY;
• gdzie chcemy rysować – w którym miej-
scu ekranu. /* position of top-left corner of viewport in the screen */
int screenX;
Mapy są najczęściej większe od obszaru, w int screenY;
którym będą wyświetlane. Z tego powodu }
musimy określić, jaki wycinek mapy chcemy
narysować. Sam obszar wyświetlania też nie Listing 10. Prosty algorytm rysowania mapy; pseudokod
jest rzeczą oczywistą – najczęściej będzie to void DrawMap()
cały ekran, ale tak być nie musi – prostokąt- {
ny wycinek świata możemy narysować w do- // determine visible tiles bounds:
wolnym miejscu ekranu i nadać mu dowol- int left = viewport.worldX / tileWidth;
ny rozmiar. int right = viewport.worldY / tileHeight;
To swoiste okno na świat nazywać będzie- int top = left + (viewport.width / tileWidth) + 1;
my dalej viewport – czyli prostokątna widocz- int bottom = top + (viewport.height / tileHeight) + 1;
na część mapy plus informacja, gdzie ma być
umieszczona na ekranie. Listing 9 zawiera // make sure we draw only within viewport, so set clipping:
przykład klasy Viewport, a Rysunek 2 poka- setClip( viewport.screenX, viewport.screenY, viewport.width, viewport.height );
zuje wzajemne relacje między mapą, view-
portem a ekranem. // draw tiles:
W niektórych systemach graficznych view- for( int v=top; v <= bottom; ++v )
port zawiera dodatkowo informacje na temat {
skalowania, tzn. jeśli widoczny wycinek świa- for( int u=left; u <= right; ++u )
ta, mimo iż jest to tylko wycinek, jest więk- {
szy od obszaru, na którym ma być narysowa- // calculate tile's position on screen:
ny, można go pomniejszyć, aby go dopasować. int x = u * tileWidth - viewport.worldX + viewport.screenX;
Jednak w przypadku naszej prostej mapy ka- int y = v * tileHeight - viewport.worldY + viewport.screenY;
felków skala równa się jeden – czyli wycinek
mapy ma ten sam rozmiar co obszar, na któ- // get tile and draw it:
rym go rysujemy. Tile tile = map.getTile( u, v );
DrawTile( tile, x, y );
Układy współrzędnych }
W tym miejscu, gdy mówimy o świecie, view- }
porcie i ekranie, pojawia się zagadnienie ukła- }
dów współrzędnych. W naszym zagadnie-
niu występują układy: świata, viewportu i Listing 11. Fragment prostej klasy TileSet; Java
ekranu. public class ImagesTileSet
Układy te mają te same jednostki – pikse- {
le – oraz kierunki i zwroty osi (przyjmijmy, private Image[] tileImages; // array of tile-images
że oś X rośnie w prawo, Y w dół). Jedyna róż-
nica to inne początki – układy są przesunięte public void DrawTile(Graphics g, int tileIdx, int x, int y)
względem siebie. {
Układ świata ma swój początek w górnym g.drawImage( tileImages[tileIdx], x, y, Graphics.LEFT | Graphics.TOP );
lewym rogu pierwszego kafelka mapy. Układ }
viewportu zaczyna się w górnym lewym ro- }
gu okna na świat. Układ ekranu to po prostu

www.sdjournal.org 47
Programowanie gier

Żeby nie pogubić się we współrzędnych i duje się punkt (x,y). Działania wyglądają na- Przyspieszenie – rozmiar
układach, w dalszej części artykułu będę uży- stępująco: kafelka wielokrotnością liczby 2
wał następujących oznaczeń: Operacje przechodzenia między układami to
(world x,y) → (u,v) ciągłe mnożenie lub dzielenie przez rozmiar
• układ świata: (world x,y); u = world_x / tile_width kafelka. Na niektórych platformach operacje
• układ viewportu: (view x,y); v = world_y / tile_height te (zwłaszcza dzielenie) są powolne. Na po-
• układ ekranu: (screen x,y); moc przychodzą jednak operacje bitowe na
• układ kaflowy: (u,v). Znając położenie kafelka w świecie, musimy liczbach całkowitych.
przenieść je do współrzędnych viewportu, a Mnożenie i dzielenie przez liczbę, która
Przechodzenie między układami następnie do współrzędnych ekranu. jest potęgą liczby 2, można zastąpić przesu-
Wszystkie funkcje rysujące obrazy operują nięciami bitowymi. Przesuwamy o tyle bi-
w układzie ekranu. Natomiast kafelki ułożo- (world x,y) → (view x,y) → (screen x,y) tów, do której potęgi jest podniesiona liczba
ne są w mapie i znamy ich współrzędne ka- screen_x = world_x - viewport_world_x + 2. Jeśli chcemy pomnożyć, przesuwamy bity
flowe. Dlatego żeby narysować mapę, będzie- viewport_screen_x; w lewo, jeśli podzielić – w prawo.
my musieli przenosić współrzędne pomiędzy screen_y = world_y - viewport_world_y + Przykładowo, jeśli chcemy pomnożyć przez
układami. viewport_screen_y; 8 (2 do potęgi 3), możemy liczbę przesunąć o
Pierwszym krokiem jest obliczenie poło- 3 bity w lewo. Analogicznie, jeśli chcemy po-
żenie kafelka w świecie (tzn. współrzędnych Na koniec możemy złożyć w całość oblicza- dzielić przez 64 (2 do potęgi 5), możemy licz-
górnego lewego rogu kafelka). Aby to zrobić, nie położenia kafelka na ekranie. bę przesunąć o 5 bitów w prawo.
wykonujemy następujące działania: Zatem jeżeli znamy rozmiar kafelka w na-
(u,v) → (screen x,y) szym programie i wiemy, że nie będzie się
(u,v) → (world x,y) screen_x = u * tile_width - viewport_ zmieniał, możemy przyspieszyć operacje na
world_x = u * tile_width world_x + viewport_ kafelkach, używając przesunięć bitowych.
world_y = v * tile_width screen_x; Należy jednak uważać, gdyż w czasie trwania
screen_y = v * tile_height - viewport_ projektu założenia mogą się zmienić. Może
Czasami potrzebna jest operacja odwrot- world_y + viewport_ się okazać, że jednak musimy użyć rozmiaru
na, tzn. stwierdzenie, w jakim kafelku znaj- screen_y; kafelka innego niż potęga dwójki. Lub może
się okazać, że musimy obsługiwać kilka roz-
Listing 12. Fragment prostej klasy TileSet; C++/SDL miarów kafelków (w czasie działania aplika-
class TileSet cji, np. różne mapy o różnych rozmiarach
{ kafelka; bądź w czasie kompilacji, np. gdy
private: tworzymy różne wersje gry z różnymi roz-
SDL_Surface** m_tileImages; // array of pointers to tile-images miarami kafelków w zależności od rozmiaru
SDL_Rect m_tileRect; // (0, 0, tile width, tile height) ekranu urządzenia docelowego, często dzieje
się tak przy tworzeniu gier na telefony).
public: Dobrze jest posiadać mechanizm pozwa-
void DrawTile( SDL_Surface* target, int tileIdx, int x, int y ) lający na łatwe przełączanie implementacji
{ między wersjami obsługującymi mnożenie/
SDL_Rect dstRect; dzielenie i przesunięcia bitowe.
dstRect.x = x;
dstRect.y = y; Proste rysowanie
Wreszcie jesteśmy gotowi, aby narysować ma-
SDL_BlitSurface( m_tileImages[tileIdx], &m_tileRect, target, &dstRect ); pę. Najprostszy sposób rysowania mapy ka-
} felków, w dużym uproszczeniu, jest nastę-
}; pujący:

• określamy, które kafelki są widoczne w


viewporcie – musimy wyznaczyć ko-

Rysunek 3. Układy współrzędnych. Niebieski – układ ekranu. Czerwony – układ viewportu. Zielony Rysunek 4. Macierz kafelków. Zamiast trzymać
– układ świata i układ kafelkowy (mają te same osie i początek, ale różne jednostki; ich jednostki to obrazki kafelków w oddzielnych plikach można je
odpowiednio piksele i „kratki”). Czarne strzałki pokazują pozycję viewportu w świecie i na ekranie umieścić w jednym dużym obrazie

48 02/2010
Mapy kafelków

lumny najbardziej z lewej i z prawej stro- określa się mianem tile set. Stwórzmy więc Przyspieszenie
ny viewportu, oraz rzędy u góry i u dołu klasę TileSet. – pozbycie się mnożeń
viewportu. Klasa TileSet musi być w stanie zwrócić W tym miejscu chciałbym jeszcze wrócić do
• następnie rysujemy kafelki po kolei, lub narysować żądany obrazek. Obrazki bę- algorytmu rysowania kafelków. Kod z Listin-
rzędami lub kolumnami – dla każde- dziemy identyfikować przez ich numer w gu 10 rysuje kolejne wiersze mapy, zaczynając
go kafelka obliczamy jego położenie we zbiorze (przez indeks, numerujemy od ze- od góry viewportu, schodząc w dół. W każ-
współrzędnych ekranu; transformacja ra). Przyjmijmy zatem, że obrazki kafelków dym wierszu kafelki rysowane są od lewej do
(u,v) –> (screen x, screen y); a następnie będą przechowywane w klasie TileSet w prawej. Dla każdego kafelka obliczane są jego
rysujemy obrazek odpowiadający kafel- tablicy. Listingi 11 i 12 przedstawiają frag- położenie na ekranie i indeks w mapie.
kowi menty przykładów takiej klasy wraz z kon- Można zauważyć, że w obrębie wiersza po-
kretnym kodem rysującym pojedynczego zycje kolejnych kafelków zwiększają się za-
Spójrzmy na na Listing 10 i prześledźmy, co kafelka. wsze o szerokość kafelka. Można więc, za-
się tam dzieje. Czasami tileset składa się z kilkudziesię- miast obliczać współrzędną x dla każde-
Najpierw obliczamy skrajne wiersze i ko- ciu lub nawet kilkuset kafelków. Przechowy- go kafelka, obliczyć ją dla pierwszego kafel-
lumny widoczne w viewporcie. Aby wyzna- wanie tak dużej ilości obrazków w oddziel- ka w rzędzie, a następnie zwiększać o szero-
czyć lewą kolumnę i górny wiersz, używa- nych plikach może być niewygodne. Dlate- kość kafelka.
my położenia viewportu w świecie i przeno- go, wykorzystując fakt, że wszystkie kafelki Analogicznie można postąpić z wiersza-
simy go do współrzędnych kaflowych (dzie- mają takie same rozmiary, można umieścić mi. Współrzędna y kolejnych wierszy zwięk-
lenie przez rozmiar kafelka). Prawą kolum- obrazki w jednym dużym obrazie, obok sie- sza się zawsze o wysokość kafelka. Można
nę i dolny wiersz wyznaczamy przez dodat- bie, w rzędach, tworząc macierz kafelków. więc obliczyć współrzędną y tylko pierwsze-
nie do lewej kolumny/górnego wiersza roz- Rysunek 4 przedstawia przykład takiej ma- go wiersza, a dla kolejnych zwiększać ją o wy-
miaru viewportu w kafelkach (zaokrąglając cierzy. sokość kafelka.
do góry). Następnie przy ładowaniu można kafel- Składając to razem, okazuje się, że wystar-
Następnie należy ustawić przycinanie (clip- ki wyciąć z macierzy i umieścić w oddziel- czy obliczyć położenie tylko jednego kafel-
ping), żeby rysowane kafelki nie wyszły poza nych obrazkach, a te umieścić w tablicy (jak ka – położonego najbardziej u góry z lewej
obszar viewportu. Jeśli rysujemy na całym na Listingach 11 i 12). Można też trzymać w w viewporcie – a następnie odpowiednio
ekranie, operację tę można pominąć. pamięci cały duży obrazek z macierzą kafel- zwiększać współrzędne x i y rysowania.
Kolejnym krokiem jest samo rysowanie ków, a rysując pojedynczego kafelka, użyć od- Podobnie można postąpić z indeksem ka-
– w podwójnej pętli przechodzimy po kolej- powiedniej funkcji rysującej tylko fragment felka w mapie. W danym wierszu, indek-
nych kafelkach (poruszamy się w układzie ka- obrazu. sy kolejnych kafelków zwiększają się o 1, a z
flowym, zmienne u,v). Dla każdego kafelka
obliczamy jego współrzędne na ekranie, po-
bieramy go z mapy i rysujemy go.

Rysowanie
pojedynczego kafelka, „tilesety”
Wszystko niby już jasne, wiemy jak ryso-
wać mapę, ale w Listingu 10 zamiast ko-
du, który rysuje konkretne kafelki, jest ma-
giczna funkcja DrawTile. Specjalnie jej nie
opisywałem, gdyż można ją zrealizować na Rysunek 5. Rysowanie mapy z buforem – na ekran rysujemy fragment bufora zawarty wewnątrz
viewportu. Pierwszy rysunek od lewej przedstawia stan początkowy – mapa narysowana na buforze,
różne sposoby. Przyjrzyjmy się, jak można
viewport umieszczony pośrodku bufora. Jeśli viewport porusza się po mapie, ale mieści się w buforze
to zrobić. (rysunek drugi od lewej), nie trzeba przerysować bufora. Natomiast jeśli viewport wyjdzie poza bufor
Do tej pory zakładaliśmy, że kafelek za- (rysunek trzeci), należy wycentrować viewport w buforze i przerysować bufor kafelkami (rysunek
wiera w sobie jakąś informację na temat czwarty)
tego, jak ma wyglądać. W przykładach by-
ło to pole imageId określające, jaki obrazek
ma być użyty. Równie dobrze może to być
wskaźnik lub referencja do konkretnego
obrazka, a samo rysowanie w najprostszej
wersji może być odwołaniem do funkcji w
stylu drawImage/SDL_BlitSurface, której
przekazujemy obrazek i współrzędne. W
takim wypadku musimy wcześniej wczy-
tać interesujące nas obrazki i umieścić re-
ferencje do nich w kafelkach. Możemy rów-
nież wczytać obrazki, umieścić je w tablicy,
a w kafelkach trzymać indeksy, np. w polu
imageId. Rysunek 6. Dorysowywanie kafelków na cyklicznym buforze. Kratkowany prostokąt to bufor. Na
początku rysujemy kafelki, aby wypełnić obszar viewportu. W drugim kroku viewport przesunął się w
Bardzo często postępuje się właśnie w ta-
prawo i należało dorysować dwie kolumny kafelków (zaznaczone na żółto). W trzecim kroku viewport
ki sposób. Określamy pewien zbiór obraz- przesunął się jeszcze bardziej w prawo – należy dorysować kolumnę z prawej strony. Jednak bufor
ków, które będziemy używać jako reprezen- skończył się, więc przenosimy dorysowywaną kolumnę na drugą stronę (na żółto zaznaczono miejsce,
tacje graficzne kafelków. Taki zbiór obrazków gdzie ostatecznie dorysowano kolumnę), a viewport zostaje „zawinięty”

www.sdjournal.org 49
Programowanie gier

każdym kolejnym wierszem indeks wraca do niektórych platformach (np. powolne telefo- dzie źródłowym (funkcja drawMapOpti-
skrajnie lewej kolumny widocznej w viewpor- ny komórkowe) może to owocować pewnym mized).
cie, a następnie zwiększa się o szerokość całej przyspieszeniem, zwłaszcza gdy rysujemy du-
mapy w kafelkach. żo kafelków. Rysowanie z buforem
Używając opisanych operacji, pozbywa- Implementację tej optymalizacji moż- W prostym rysowaniu mapy kafelków wy-
my się kilku mnożeń dla każdego kafelka. Na na znaleźć w załączonym do artykułu ko- wołujemy funkcję rysującą pojedynczy kafe-
lek (a co za tym idzie rysującą obrazek) tyle
Listing 13. Rysowanie zawiniętego viewportu razy, ile jest kafelków widocznych na ekranie.
Ilość ta zależy od wielkości kafelka i ekranu
// get viewport bounds (left, right, top, bottom) in pixels i czasem może być całkiem spora (mały kafe-
int left = viewport.bufferX; lek, duży ekran).
int right = viewport.bufferX + viewport.width; Różne platformy bardzo różnie realizują ry-
if( right > bufferWidth ) // wrap sowanie pojedynczych obrazków. Dla niektó-
{ rych obojętne jest, czy rysujemy dużo małych
right -= bufferWidth; obrazków, czy mało dużych, ale dla niektórych
} ma to istotne znaczenie. Przykładem mogą być
Javowe telefony komórkowe – w wielu z nich
int top = viewport.bufferY; narzut wywołania funkcji rysujących obrazek
int bottom = viewport.bufferY + viewport.height; jest znaczny i trzeba się z nim liczyć, i warto
if( bottom > bufferHeight ) { // wrap rysować mniej, ale większych obrazków. Z te-
{ go powodu powstała koncepcja rysowania ma-
bottom -= bufferHeight; py kafelków z buforem.
} Idea jest następująca. Zamiast na ekran ry-
sujemy mapę na buforze. Bufor jest większy
// determine case od rozmiaru ekranu. Na początku umieszcza
if( left < right && top < bottom ) { się viewport w środku bufora i rysuje kafel-
// case #1: whole viewport fits inside buffer ki na całej powierzchni bufora. Na ekran ry-
drawBufferRegionToScreen( ... ); sujemy tylko część bufora zawartą wewnątrz
} viewportu.
else if( left > right && top < bottom ) { Jeśli vieport nie przemieszcza się po mapie,
// case #2: y in bounds, split x to nie ma potrzeby przerysowywania kafel-
ków w buforze, wystarczy tylko rysować bu-
// rectangle 1 for na ekran. Dzięki temu w każdej klatce gry
drawBufferRegionToScreen( ... ); rysujemy tylko jeden duży obraz.
Jeśli viewport porusza się po mapie, to prze-
// rectangle 2 suwamy go także w buforze i sprawdzamy,
drawBufferRegionToScreen( ... ); czy ciągle się w nim mieści. Jeśli tak, to nie
} musimy przerysowywać kafelków i rysujemy
else if( left < right && top > bottom ) { bufor na ekran. Pamiętajmy, że rysujemy tyl-
// case #3: x in bounds, split y ko część bufora zawartą wewnątrz viewpor-
tu – dzięki przemieszczaniu viewportu we-
// rectangle 1 wnątrz bufora na ekranie mamy wrażenie po-
drawBufferRegionToScreen( ... ); ruszania się po mapie.
Przerysowanie kafelków odbywa się dopie-
// rectangle 2 ro w momencie, gdy viewport wyszedł poza
drawBufferRegionToScreen( ... ); obszar bufora. Należy wtedy ponownie na-
} rysować kafelki na całej powierzchni bufora
else { i wycentrować w nim viewport.
// case #4: x split, y split Rysunek 5 przedstawia sposób działania
rysowania z buforem.
// rectangle 1 Nie jest to rozwiązanie idealne – ciągle
drawBufferRegionToScreen( ... ); musimy co jakiś czas przerysować wszyst-
kie widoczne kafelki, przez co co pewien
// rectangle 2 czas mogą występować zwolnienia. Zda-
drawBufferRegionToScreen( ... ); rza się to, gdy viewport dochodzi do krawę-
dzi bufora. Jednak pomiędzy przerysowa-
// rectangle 3 niami rysowanie na ogół odbywa się szyb-
drawBufferRegionToScreen( ... ); ciej. Warto więc technikę tę przetestować
w swojej aplikacji.
// rectangle 4
drawBufferRegionToScreen( ... ); Rysowanie – cykliczny bufor
} Rysowanie do bufora cyklicznego to modyfi-
kacja i rozwinięcie techniki rysowania do bu-

50 02/2010
Mapy kafelków

fora. Metoda ta rozwiązuje problem przery-


sowywania wszystkich widocznych kafelków
co pewien czas – dorysowujemy tylko kafel-
ki, które znalazły się w viewporcie, a nie było
ich tam wcześniej.
Na początku rysujemy kafelki tak, żeby
zapełnić obszar viewportu. Jeśli viewport
przesuwa się wewnątrz bufora, dorysowu-
jemy tylko brakujące kafelki (np. jeśli bufor
porusza się w prawo, będziemy dorysowy-
wać kolejne kolumny z prawej strony). Te-
raz bardzo ważna informacja – dokładnie
tak samo postępujemy (tzn. rysujemy bra-
kujące kafelki), gdy bufor przekroczy kra-
wędź ekranu (w tym momencie w meto-
dzie z buforem trzeba było przerysować ca-
ły bufor). Jednakże pojawia się pytanie Rysunek 7. Rysowanie zawiniętego viewportu na ekranie. U góry znajdują się cztery możliwe
– gdzie narysować brakujące kafelki, jeśli przypadki ułożenia viewportu w buforze. Na dole przedstawiony jest, dla każdego przypadku, sposób
viewport wychodzi poza bufor? Odpowiedź rysowania viewportu na ekranie. Niebieska kropka to współrzędne viewportu na ekranie
znajduje się na Rysunku 6 – dorysowujemy
z drugiej strony bufora, a viewport zawija- Listing 14. Sprowadzanie viewportu do obszaru bufora
my. Dzięki zawijaniu viewportu i rysowa-
niu kafelków cyklicznie na buforze nie mu- void wrapToBuffer()
simy dokonywać całkowitego przerysowa- {
nia bufora (chyba że viewport w całości wyj- // bufferX/Y is current position of viewport within buffer
dzie poza bufor). int newX = m_bufferX;
int newY = m_bufferY;
Zawijany viewport
Co to w praktyce znaczy, że viewport jest za- // keep X in bounds:
winięty? Jak narysować na ekranie obszar if( m_bufferX > m_bufferWidth ) {
bufora zawarty w viewporcie, jeśli nie jest newX = m_bufferX % m_bufferWidth;
on prostokątem, tylko dwoma prostokąta- }
mi przyległymi do prawej i lewej krawędzi else if( m_bufferX < 0 ) {
ekranu? A jeśli bufor zamiast prawo-lewo // keep in mind that modulo of negative value gives negative result
będzie poruszał się góra-dół? Wtedy view- // so actually newX is calculated by substracting from bufferWidth
port po zawinięciu stanie się dwoma prosto- newX = m_bufferWidth + ( m_bufferX % m_bufferWidth );
kątami przyległymi do górnej i dolnej krawę- }
dzi bufora. A co, jeśli viewport będzie poru-
szał się jednocześnie w prawo-lewo i w gó- // keep Y in bounds:
rę-dół? Wtedy po zawinięciu stanie się czte- if( m_bufferY > m_bufferHeight ) {
rema prostokątami. newY = m_bufferY % m_bufferHeight;
Jak to wszystko narysować na ekranie? }
Każdy prostokąt składowy viewportu rysu- else if( m_bufferY < 0 ) {
jemy oddzielnie, ale wszystkie prostokąty newY = m_bufferHeight + ( m_bufferY % m_bufferHeight );
umieszczamy na ekranie sąsiadująco wzglę- }
dem siebie, tak aby składały się w jednoli-
tą całość. // set new position within buffer:
Rysunek 7 przedstawia ideę zawijania view- if( newX != m_bufferX || newY != m_bufferY ) {
portu i rysowania go na ekranie. Przeanalizuj- setPositionInBuffer( newX, newY );
my go dokładnie. Mamy cztery przypadki. }
Przypadek (1) jest najprostszy – viewport w }
całości mieści się w buforze; wystarczy nary-
sować prostokąt na ekranie. W przypadku (2) Listing 15. Rozszerzenie klasy Vieport na potrzeby implementacji rysowania mapy kafelków z
musimy narysować dwa prostokąty – prosto- buforem cyklicznym
kąt 1 rysujemy na ekranie we współrzędnych class CyclicViewport extends Viewport
viewportu, a prostokąt 2 sąsiadująco z prawej. {
Analogicznie postępujemy w przypadku (3), int previousWorldLeft;
z tą różnicą, że prostokąt 2 umieszczamy są- int previousWorldRight;
siadująco od dołu. W przypadku (4) musimy int previousWorldTop;
narysować aż cztery prostokąty; prostokąt 1 int previousWorldBottom;
umieszczamy we współrzędnych viewportu, }
a pozostałe trzy sąsiadują z prawej, z dołu i z
prawej-dołu. Listing 13 pokazuje zarys przy-

www.sdjournal.org 51
Programowanie gier

kładowego kodu realizującego rysowanie za- fora. W praktyce osiąga się to przez umiesz- ny bufor), wystarczy opracować sposób do-
winiętego viewportu. Konkretną implemen- czenie viewportu w buforze we współrzęd- rysowywania kafelków, które pojawiły się w
tację można znaleźć w dołączonym do arty- nych równych reszcie z dzielenia (modulo) viewporcie.
kułu kodzie źródłowym. położenia viewportu w świecie przez jego Wydaje się to oczywiste – dorysowujemy
Istnieje jeszcze jeden szczególny przypa- rozmiar. Listing 14 pokazuje to działanie kolumny lub wiersze – z prawej, lewej, góry
dek: viewport może w całości znaleźć się w praktyce. lub dołu. Jednak jeśli viewport przesunął się
poza buforem. Musimy temu zapobiegać zarówno w poziomie, jak i w pionie, sytuacja
– jeśli tylko viewport w całości wyskoczy po- Dorysowywanie komplikuje się.
za bufor, musimy sprawić, że od razu poja- brakujących kafelków Rysunek 8 przedstawia możliwe scena-
wi się z jego drugiej strony – w ten sposób Jeśli wiemy już, jak narysować na ekranie riusze. Musimy wziąć pod uwagę wszystkie
zawsze będzie znajdował się wewnątrz bu- zawijany viewport (lub jak kto woli cyklicz- przypadki. Żeby to zrobić, sprawdzimy kolej-
no wszystkie kafelki widoczne w aktualnym
położeniu viewportu – jeśli kafelek jest obec-
nie widoczny, a nie był widoczny w poprzed-
nim położeniu viewportu, oznacza to, że jest
o nowy i należy go dorysować do bufora.
Zatem pierwszym krokiem jest określe-
nie, które kafelki pojawiły się, a które były
już widoczne. W tym celu rozszerzymy kla-
sę Viewport, dodając informacje o skrajnych
wierszach i kolumnach ostatnio widocznych
w viewporcie (tzn. podczas poprzedniego
Rysunek 8. Możliwe przypadki dorysowywania nowych kafelków. Kartkowany prostokąt to wycinek rysowania). Na Listingu 15 pokazane jest,
świata. Prostokąt zielony to kafelki widoczne w poprzednim położeniu viewportu. Prostokąt niebieski jak można to zrobić.
to kafelki obecnie widoczne w viewporcie. Na różowo zaznaczono kafelki, które zostaną dorysowane Następnie musimy przejść w pętli po
wszystkich kafelkach widocznych w nowym
Listing 16. Obliczanie współrzędnych kafelka na buforze cyklicznym viewporcie (iterujemy po współrzędnych u,v)
i dla każdego sprawdzić, czy znajdował się w
int bufferU = u % bufferWidthInTiles; obszarze poprzednio rysowanych kafelków
int bufferV = v % bufferHeightInTiles; – sprawdzamy, czy (u,v) kafelki znajdują się
int x = buffU * tileWidth; wewnątrz poprzednich granic viewportu. Je-
int y = buffV * tileHeight; śli nie, tzn. kafelek jest nowy, musimy go na-
rysować.
Listing 17. Dorysowywanie kafelków do bufora cyklicznego Powstaje jednak pytanie – w jakim miejscu
int bufferWidthInTiles = m_bufferWidth / tileWidth; go narysować? Rysując kafelka na buforze cy-
int bufferHeightInTiles = m_bufferHeight / tileHeight; klicznym, musimy jego położenie w świecie
(world u,v) sprowadzić do położenia w bu-
// paint new tiles, but only ones that appeared in new viewport: forze (buffer u,v) i dopiero wtedy obliczyć
for( int v = currTop; v <= currBottom; ++v ) współrzędne (buffer x,y) rysowania. Pomocą
{ służy tu operacja reszty z dzielenia (modulo).
for( int u = currLeft; u <= currRight; ++u ) Dla każdego rysowanego kafelka wykonu-
{ jemy obliczenia przedstawione na Listingu
int buffU = u % bufferWidthInTiles; 16, przy czym (u,v) to współrzędne kaflowe
int buffV = v % bufferHeightInTiles; w świecie, (bufferU, bufferV) to współrzęd-
ne kaflowe w buforze, a (x,y) to współrzędne
// calculate (buffer x,y) używane do rysowania na buforze.
int x = buffU * tileWidth; Listing 17 przedstawia sposób dorysowy-
int y = buffV * tileHeight; wania kafelków. Przedstawiony kod zawiera
operacje modulo dla każdego kafelka, moż-
if (u >= 0 && v >= 0 && u < mapWidth && v < mapHeight) na je jednak zoptymalizować, aby wykony-
{ wać to działanie tylko raz. Optymalizacja ta
// get tile and draw it: jest użyta w dołączonym do artykułu kodzie
int tileIdx = v * mapWidth + u; // (!!) using (world u,v) here źródłowym.
int imageId = map.m_tiles[tileIdx].m_imageIdx;
Rozmiar bufora
if (imageId >= 0) Warto zauważyć, że rozmiar bufora musi być
{ co najmniej o jeden kafelek większy niż rozmiar
tileSet.DrawTile(g, imageId, x, y); viewportu. Jeśli nie spełnimy tego warunku,
} viewport zawinie się na samego siebie. W efek-
} cie, po narysowaniu, część wspólna nałożonych
} na siebie części viewportu znajdzie się na ekra-
} nie dwa razy. Do tego dorysowywane kafelki
narysują się na kafelkach obecnie widocznych

52 02/2010
Mapy kafelków

w viewporcie, zakrywając je. Ogólnie rzecz uj- fora widoczny w viewporcie na ekran ciętnym przypadku daje dobre wyniki, mi-
mując – mogą dziać się dziwne rzeczy. (jeden z czterech przypadków). mo iż w skrajnych sytuacjach trzeba przery-
Ponadto rozmiar bufora musi być wielo- sować cały bufor i do tego narysować go na
krotnością rozmiaru kafelka. Jest to bardzo Już wiemy, jak rysować z buforem cyklicz- ekranie.
ważne – bez spełnienia tego warunku ka- nym. A jak ta metoda ma się do wcześniej
felki dorysowywane w ostatnim wierszu/ omówionych metod rysowania mapy? Na dzisiaj koniec
kolumnie będą przycięte. W metodzie prostej rysujemy wszystkie Artykuł przedstawił podstawy zagadnienia
kafelki co klatkę (chcemy tego uniknąć, map kafelków. Droga do stworzenia swojej
Podsumowanie rysowania wolimy rysować jeden duży obraz). W po- wymarzonej gry na pewno się skróciła. Jed-
„z buforem cyklicznym” dejściu z buforem nie przerysowujemy ka- nakże był to zaledwie wstęp – w tej chwili
Dla czytelności przedstawię teraz wszystkie felków wcale (o to chodziło, rysujemy jeden możemy stworzyć mapę i ją narysować. Żeby
kroki rysowania „z buforem” w formie listy: duży obraz co klatka), robimy to dopiero stworzyć grę, trzeba zapoznać się z kolejnymi
w momencie, gdy trzeba przerysować cały zagadnieniami, takimi jak rysowanie obiek-
• przy inicjalizacji umieszczamy viewport bufor. Jednak może wystąpić wtedy chwi- tów na mapie (np. postać gracza), wykrywa-
w początku bufora (górny-lewy róg) i lowy zauważalny spadek płynności (musi- nie kolizji z kafelkami, tworzenie map w edy-
wypełniamy obszar viewportu kafelka- my przerysować cały bufor kafelkami + na- torach, ładowanie i zapisywanie ich z/do pli-
mi; rysować bufor na ekran). ków etc.
• jeśli viewport w całości znalazł się poza W rysowaniu z buforem cyklicznym jeste- Mam nadzieję, że lektura artykułu była do-
buforem, sprowadzamy go do wnętrza śmy pomiędzy dwoma poprzednimi meto- brym punktem wyjścia do dalszego poszerza-
bufora przez zawinięcie pozycji (pozycja dami – w przeciętnym scenariuszu musi- nia swojej wiedzy.
viewportu w świecie modulo rozmiar my dorysowywać pewną ilość kafelek co
bufora); klatkę (tylko nowe kafelki), ale za to nie JACEK ZAGRODZKI
• iterujemy po wszystkich kafelkach aktu- mamy sytuacji, gdy trzeba przerysować Pracuje na stanowisku Kierownika Działu Tech-
alnie widocznych w viewporcie; wszystko w jednym momencie (znikają nologicznego w firmie Gamelion, wchodzącej
• jeśli kafelek nie był widoczny w po- spadki płynności). w skład Grupy BLStream. Jacek specjalizuje się
przednim viewporcie, rysujemy go na Rozważmy jeszcze skrajne przypadki. Jeśli w programowaniu gier w oparciu o technolo-
buforze; viewport nie porusza się, nie musimy prze- gię JME. Grupa BLStream powstała, by efektyw-
• aby narysować kafelka, obliczamy jego rysowywać kafelków wcale. Jeśli viewport niej wykorzystywać potencjał dwóch szybko roz-
współrzędne (u,v) w buforze (pozycja co klatka zmienia diametralnie swoje poło- wijających się producentów oprogramowania –
kafelka w mapie modulo rozmiar bu- żenie, może zaistnieć potrzeba przerysowa- BLStream i Gamelion. Firmy wchodzące w skład
fora w kafelkach), a następnie oblicza- nia całego viewportu. Jednak statystycznie, grupy specjalizują się w wytwarzaniu oprogra-
my współrzędne rysowania (x,y) i rysu- w zwykłej grze, rzadko kiedy w viewporcie mowania dla klientów korporacyjnych, w roz-
jemy; pojawia się w kolejnej klatce więcej niż je- wiązaniach mobilnych oraz produkcji i testowa-
• gdy wszystkie nowe kafelki zostaną nary- den wiersz/kolumna nowych kafelków. W niu gier.
sowane, na buforze rysujemy obszar bu- tym właśnie tkwi zaleta tej metody, w prze- Kontakt z autorem: jacek.zagrodzki@game-lion.com

R E K L A M A

www.sdjournal.org 53
Programowanie gier

Efektywny blitter
Metody optymalizacji
Jak to jest, że jedne gry posiadają świetnie wyglądającą i płynną
grafikę, podczas gdy inne, mimo znacznie uboższego wyglądu, ledwo
sobie radzą z przerysowywaniem pola gry? Dlaczego u konkurencji na
ekranie może poruszać się całe mrowie przeciwników, podczas gdy u
nas już przy pięciu jest problem? Różnica tkwi w kunszcie programisty
odpowiedzialnego za niskopoziomową obsługę grafiki.
źródłowego i docelowego. Pierwszym zada-
Dowiesz się: Powinieneś wiedzieć: niem funkcji blitującej jest wyznaczenie prze-
• Jak znacznie przyspieszyć rysowanie grafiki; • Jak się robi gry. cięcia interesujących nas obszarów obu ob-
• Jak użytecznie posługiwać się kodem asem- razów, będzie to prostokąt, na którym prze-
blerowym; prowadzane będą zmiany. Czasami (przy-
• Że należy wierzyć pomiarom, a nie przeczu- padek numer 6) może się okazać, że część
ciom. wspólna nie występuje – wtedy nie pozostaje
nam nic innego jak wyjść z funkcji. W pozo-
stałych wypadkach musimy wyznaczyć sze-
funkcja prawie na pewno pozbawiona będzie reg zmiennych, które umożliwią nam potem
większości możliwych do zastosowania opty- szybkie przetwarzanie danych. Będą to na
Poziom malizacji. Optymalizacji, które wiążą się z po- przykład szerokość i wysokość obszaru prze-
trudności gorszeniem jakości wynikowej grafiki, a więc cięcia – używane jako liczniki wewnętrznej i
czegoś, co jest niedopuszczalne w uogólnio- zewnętrznej pętli rysowania, wskaźniki na le-
nym algorytmie blittera. Ale nie uprzedzaj- we górne (początkowe) piksele części wspól-
my faktów. nej obrazów, mapowane na ich współrzęd-

J
ak to? – ktoś może się oburzyć po prze- ne. Potrzebować będziemy również informa-
czytaniu takiego wstępu, przecież od cza- Blitter? cji o tym, ile bajtów należy przeskoczyć, aby
sów Windowsów 3.0 mamy akcelerację Blitter jest to specjalizowany sprzętowy z ostatniego piksela w linii przenieść się do
operacji graficznych!. Już Amiga miała sprzęto- układ, mający za zadanie przenosić duże blo- pierwszego piksela w następnej linii, w obu
wy blitter! – krzyknie ktoś inny. Jest to, oczy- ki danych z jednego obszaru pamięci do dru- obrazach, ale ta wartość obliczona zostanie
wiście, prawda, niemniej trzeba wziąć pod giego. Jego nazwa bierze się od skrótu BLIT później, zależy bowiem od szerokości piksela.
uwagę fakt, że nie wszystkie dzisiejsze plat- – BLock Image Transfer, co można tłuma- Wszystkie te zmienne zostały przedstawione
formy posiadają takie udogodnienia. Takie czyć jako blokowy transfer obrazu. Jak zo- na Rysunku 2.
na przykład telefony komórkowe. Widoczny stało wcześniej wyjaśnione, nas interesować
jest, co prawda, mniej lub bardziej raczkujący będzie programowa implementacja algoryt- Moje piksele mają
trend wprowadzania pełnoprawnych akcele- mów wykonywanych przez tenże układ. szerokość równą jeden!
ratorów grafiki trójwymiarowej, które można Funkcja realizująca zadanie blittera zawsze Na ekranie – prawdopodobnie tak, ale nas,
wykorzystać również do przyspieszania grafi- musi przyjmować obraz źródłowy i docelowy. jako programistów, bardziej interesuje szero-
ki 2D, ale po pierwsze, sprzęt ten jest dostęp- W dobrym tonie byłoby również umożliwienie kość bitowa. Czy też może – w szerszym zna-
ny tylko w modelach z najwyższej półki, a po wskazania miejsca, w którym na obrazie doce- czeniu – format piksela. Czym się różni jed-
drugie, korzystanie z niego wiąże się z pew- lowym ma się znaleźć obraz źródłowy, a zatem no od drugiego? Mówiąc o szerokości bitowej
nymi ograniczeniami. Hardware'owych roz- dodatkowo należy przekazać parę współrzęd- , myślimy o kolorze ośmio-, szesnasto-, dwu-
wiązań przyspieszających tylko i wyłącznie nych, które będą specyfikowały punkt zaczepie- dziestocztero- czy trzydziestodwu-bitowym.
grafikę dwuwymiarową na urządzeniach nia. Użyteczna jest również możliwość wyspe- Jednak powiedzenie, że jeden piksel zajmu-
przenośnych nie stwierdzono. No, może po- cyfikowania obszaru obrazu źródłowego, który je 32 bity, jest dla nas niewystarczające. Ja-
za obecnymi na Nintendo DS wynalazkami chcemy narysować. Dzięki temu będziemy mo- kie jest ułożenie kanałów w tych 32 bitach?
do obsługi duszków rodem z Atarynki. gli przechowywać, przykładowo, 10 klatek ani- RGBA? ARGB? ABGR? Każda z kombina-
Problem może być dla nas mało widocz- macji na jednym obrazie, a podczas blitowania cji jest poprawna, co więcej, na każdą z nich
ny, w sytuacji gdy używamy w naszej grze podamy, która klatka (tj. obszar obrazu, który ją można się natknąć przy różnych okazjach.
zewnętrznych bilbliotek. Taki na przykład zawiera) nas interesuje. Dlatego dopiero powiedzenie, że format pik-
SDL posiada implementację funkcji blitują- Rysunek 1 przedstawia niektóre możliwe sela to, od najmłodszych bitów, 8 bitów kana-
cych jeden obraz na drugi. Sęk w tym, że taka kombinacje wzajemnych położeń obrazów łu alfa, 8 bitów kanału niebieskiego, osiem bi-

54 02/2010
Efektywny blitter

tów kanału zielonego i osiem bitów kanału ki temu blitowanie można zaimplementować nym wywoływaniem funkcji, co nie może być
czerwonego, jest dla nas satysfakcjonujące. za pomocą prostej pętli kopiującej. Natomiast szybkie, w końcu muszą zostać przekazane pa-
Mogłoby się wydawać, że im więcej bitów gdyby obraz źródłowy miał format 888, dla rametry (przez stos), funkcja zwraca też pew-
mamy na każdy kanał, tym lepiej będzie wy- każdego piksela należałoby przeprowadzać ną wartość, która nie jest nam potrzebna, ale
glądała finalna grafika, prawda? W teorii tak, konwersję do formatu obrazu docelowego. Po zwrócona zostać musi... A jednak. Tylko i wy-
w praktyce nie bardzo. Przykładowo, Nokia wykonaniu testów okazało się, że blitowanie łącznie zbadanie rzeczywistej szybkości wy-
szczyci się, że niektóre jej telefony mają ekra- 565 –> 565 trwa 1,23 milisekund, a blito- konywania kodu na urządzeniu jest w stanie
ny zdolne wyświetlić 16 milionów kolorów wanie 888 –> 565 trwa 5 ms. Różnica chyba stwierdzić, czy zastosowana przez nas opty-
(kolor 24-bitowy). Dobry dowcip. Na 24 bi- całkiem spora. Tutaj coś, na co warto zwrócić malizacja nie jest tylko optymalizacją. Przykła-
tach (a raczej na 32, żeby dane były wyrów- uwagę: graficy, jak to artyści, zbyt dużej uwa- dowo, podczas prac nad przyspieszaniem pew-
nane do szerokości słowa) kolory, owszem, są gi do zagadnień technicznych nie przykłada- nego kawałka kodu udało się zastąpić opera-
trzymane. Ale podczas wyświetlania z każdej ją. Lepiej im patrzeć na ręce, żeby się potem cję mnożenia prostymi bitowymi operacjami
składowej obcinane są dwa najmłodsze bity, nie okazało, że całoekranowa bitmapa tła po- logicznymi. Mogłoby się wydawać, że prze-
przez co tak naprawdę otrzymujemy kolor 18- siada kanał alfa, przez co przelatuje niezmie- sunięcia bitowe są szybsze od powolnego ob-
bitowy (po 6 bitów na składową). Należy sobie niona przez nasz sprytny automatyczny kon- liczania iloczynu, że wyeliminowanie mno-
zadać pytanie – czy dla marnych dwóch bitów werter zamieniający wszystkie ładowane ob- żenia z pewnością przyspieszy działania algo-
opłaca się implementować wszystkie operacje razy mające format 888 (bez kanału alfa) na rytmu. Po przeprowadzeniu testów wydajno-
graficzne tak, by działały z kolorem 32-bito- format 565. W efekcie, zamiast prostego ko- ściowych okazało się, że wersja z mnożeniem
wym zamiast użyć po prostu koloru 16-bito- piowania pamięci musimy przeprowadzić jest szybsza. Morał jest prosty: nigdy nie należy
wego? Jakby nie patrzeć, oznacza to dwukrot- operację blendingu. ufać swojemu przeczuciu, zawsze należy opie-
ne zwiększenie liczby danych przesyłanych rać się na twardych pomiarach.
z/do pamięci, czego zignorować nie możemy. Optymalizacja kopiowania Załóżmy jednak, niech będzie to ekspery-
Udało nam się zatem dokonać pierwszej opty- Implementacją funkcji blitujących jako ta- ment myślowy, że funkcja memcpy nie istnieje,
malizacji blittera – zakładamy, że powierzch- kich zajmować się tu nie będziemy. Dość po- zmuszeni jesteśmy używać własnoręcznie na-
nia ekranowa (a więc ta, na której będziemy w wiedzieć, że są to pętle podobne do tej z Li- pisanej pętli kopiującej. Czy w takiej sytuacji
większości przypadków rysowali) zawsze bę- stingu 1. Na podstawie tej pętli, realizującej
dzie miała głębokość szesnastu bitów. kopiowanie 565 –> 565, można stworzyć Listing 1. Pętla blitująca
Bardzo ważną, a zarazem niezwykle ba- wszystkie inne, dodając tylko odpowiednie
nalną optymalizacją działania blittera jest konwersje formatów piksela. void Blit565To565( … )
zapewnienie odpowiedniego formatu pikse- Czy taką, optymalnie napisaną wydawało- {
la obrazów źródłowych. Przykładowo, jeżeli by się pętlę można jeszcze przyspieszyć? Oka- do
chcemy rysować na obrazie, który ma format zuje się, że zastąpienie wewnętrznej pętli sys- {
565 (po 5 bitów na składowe czerwoną i nie- temową funkcją memcpy przyspiesza wykona- int w = width;
bieską, 6 na składową zieloną), to należy spra- nie funkcji prawie trzykrotnie. Jest to rezultat do
wić, oczywiście w miarę możliwości, by ob- zdecydowanie nieintuicyjny, w końcu zastępu- {
raz źródłowy również miał format 565. Dzię- jemy banalne przepisywanie w pętli wielokrot- *dst++ = *src++;
}
while( --w );
dst += dstSkip;
�� �� �� src += srcSkip;
��������������
}
�������������� while( --height );
}

Listing 2. Wewnętrzna pętla programu z


�� �� �� Listingu 1

.L5:
ldrh r5, [r0], #2
subs ip, ip, #1
strh r5, [r1], #2 @ movhi
Rysunek 1. Niektóre z możliwych wzajemnych konfiguracji obrazów podczas blitowania
bne .L5

Listing 3. Odwinięcie pętli

��������� UInt32 w = width / 4;


do
��������

�������������������
������� ������������������� {
��������� ��������������������
����������������� *dst++ = *src++;
*dst++ = *src++;
���������������������������� ���������������������������� *dst++ = *src++;
����������������������������� �������������������������� *dst++ = *src++;
����������������������
}
while( --w );
Rysunek 2. Zmienne używane podczas blitowania

www.sdjournal.org 55
Programowanie gier

można w jakiś sposób przyspieszyć program z waczne przeplecenie instrukcji switch z pę- wi nas tych wartości. Podobnie, podczas skła-
Listingu 1? Spójrzmy, jak wygląda wewnętrz- tlą do .. while jest jak najbardziej legalną kon- dania finalnej wartości piksela nie ma sensu
na pętla po skompilowaniu (Listing 2). Mne- strukcją w języku C, co więcej, realizuje do- obcinanie najmłodszych trzech bitów ze skła-
moniki ldrh i strh odpowiednio ładują i kładnie taką funkcjonalność, jaką właśnie te- dowej niebieskiej, ponieważ i tak za chwi-
zapisują 16-bitową wartość z/do pamięci, raz potrzebujemy. Spójrzmy na Listing 5, któ- lę wykonywane jest przesunięcie bitowe. Po
zwiększając jednocześnie wskaźnik o 2 bajty. ry przedstawia zapis asemblerowy powyższej wprowadzeniu modyfikacji wynikowy kod
Instrukcja subs zmniejsza licznik pętli, a bne pętli. 80% instrukcji dotyczy odczytu/zapisu asemblerowy zmniejszył się o jedną instruk-
wykonuje skok (następną iterację pętli), jeżeli pamięci, a tylko 20% zajmuje się sprawdza- cję. Nie jest to może jakaś ogromna zmiana,
wynik odejmowania jest różny od zera. Widać niem warunku końca pętli! Jednocześnie wi- ale na początek wystarczy.
tu jasno, że tylko 50% wykonywanych przez dzimy, że w środku pętli obecne są punkty Czym by się można teraz zająć? Może spró-
procesor instrukcji odnosi się do kopiowania wejścia dla różnych wartości części ułamko- bujmy popatrzeć na matematykę, w końcu
pamięci, a więc tego, co nas najbardziej inte- wej szerokości. sześć mnożeń musi nieźle spowalniać nasz
resuje. Oczywiście, ocenić relatywnego czasu Nie należy się zbytnio przejmować tym, że kod. Spójrzmy na to, w jaki sposób wykony-
wykonywania poszczególnych instrukcji nie w przykładzie pętla została odwinięta cztery wana jest interpolacja koloru źródłowego z
sposób, przynajmniej bez posiadania symu- razy. W rzeczywistości może zostać wykorzy- docelowym (tutaj wartość alfa będzie w za-
latora procesora na poziomie bramek logicz- stana dowolna liczba, chociaż dobrze byłoby kresie 0 – 1, a nie 0 – 255):
nych. Mamy tu wszak instrukcje zapisu i od- się wpierw zastanowić, czy nie należałoby
czytu z pamięci (duże opóźnienie!), co praw- użyć którejś z potęg dwójki. Wszak żeby ob- d = s * a + d * ia
da dostęp jest sekwencyjny, więc cache znacz- liczyć wynik i resztę z dzielenia przez takie
nie przyspiesza działanie, ale konkretnie, o ile liczby, wystarczy wykonać proste operacje bi- Rozwińmy ia :
procent? Modyfikacje licznika pętli są na po- towe. Koniecznie należy za to przeprowadzić
ziomie rejestrów procesora, ale operacja sko- testy szybkości dla każdej sprawdzanej licz- d = s * a + d * ( 1 – a )
ku czeka, aż ALU obliczy wynik odejmowa- by odwinięć. Przykładowo, wykorzystanie
nia... Na szczęście kompilator sprawia się nad- mechanizmu Duffa w kodzie zmieniającym O, jakoś to teraz wygląda. Rozwijajmy dalej:
zwyczaj dobrze, przeplatając obsługę licznika format dźwięku, przy ośmiokrotnym odwi-
pętli z działaniami operującymi na pamięci, nięciu pętli, przyspieszyło wykonanie pętli z d = s * a + d – d * a
co minimalizuje czas oczekiwania na zakoń- 4,60 ms do 4,16 ms. Szesnastokrotne odwi-
czenie operacji zależnej. nięcie pętli zmieniającej głośność dźwięku Listing 4. Mechanizm Duffa
Dygresje na bok, chcemy zmaksymalizo- spowodowało spadek czasu potrzebnego na
wać liczbę operacji na pamięci, minimalizu- wykonanie pętli z 13,25 ms do 10,26 ms. UInt32 w = ( width + 3 ) / 4;
jąc jednocześnie liczbę operacji potrzebnych switch( width % 4 )
do obsługi pętli. Listing 3 przedstawia pętlę Blending {
odwiniętą 4 razy. Nie da się tu oczywiście nie Czyli innymi słowy mieszanie. Złożenie czę- case 0:
zauważyć poważnego problemu: pętla dzia- ści jednego koloru z proporcjonalnie odwrot- do
ła tylko dla szerokości będących wielokrot- ną częścią innego koloru. Występuje wszę- {
nościami czwórki. Aby kod działał popraw- dzie tam, gdzie wykorzystywana jest wartość *dst++ = *src++;
nie, należy wpierw obsłużyć ułamkową część alfa. Należy tu zwrócić uwagę, że podczas bli- case 3:
szerokości. Można też zintegrować odwinię- towania wartość alfa piksela pochodzi tak na- *dst++ = *src++;
cie pętli z obsługą części ułamkowej w całość. prawdę z dwóch źródeł. Pierwszym jest, o case 2:
Jak? Za pomocą mechanizmu Duffa (Duff's ile występuje, kanał alfa obrazu źródłowego. *dst++ = *src++;
device). Przykład wykorzystania tej techniki Drugim źródłem jest globalna wartość alfa, case 1:
przedstawiony został na Listingu 4. To dzi- opcjonalnie podawana do funkcji blitującej. *dst++ = *src++;
Dopiero połączenie globalnej wartości z war- }
tością z kanału alfa, inną dla każdego piksela, while( --w );
daje nam finalną wartość alfa, która powinna }
zostać użyta podczas rysowania.
Do rzeczy jednak. Listing 6 przedstawia Listing 5. Skompilowany program z
naiwną implementację blittera 8888 –> 565. Listingu 4
Kod, rzecz oczywista, działa zgodnie z ocze- .L7:
kiwaniami, jednak prędkość jest zdecydowa- ldrh r6, [r0], #2
nie niesatysfakcjonująca. Wystarczy spojrzeć strh r6, [lr], #2 @ movhi
na liczbę operacji wykonywanych dla każde- .L10:
go piksela, aby wiedzieć czemu (Listing 7). ldrh r6, [r0], #2
30 instrukcji asemblera, 6 mnożeń, na szczę- strh r6, [lr], #2 @ movhi
ście tylko 2 odczyty z pamięci i jeden zapis. .L11:
No, mogłoby być lepiej. Optymalizację mo- ldrh r6, [r0], #2
żemy zacząć od wyrzucenia z kodu niepo- strh r6, [lr], #2 @ movhi
trzebnych operacji, które co prawda mają ja- .L12:
kiś wpływ na czytelność, ale nas interesuje jak ldrh r6, [r0], #2
największa wydajność. Aby pobrać ze źródło- subs ip, ip, #1
wego piksela wartość alfa, nie ma sensu usu- strh r6, [lr], #2 @ movhi
Rysunek 3. Jedna z grafik wykorzystanych w wanie kanałów R, G i B, ponieważ przesunię- bne .L7
grze Boom Letters firmy Gamelion cie w prawo o 24 bity automatycznie pozba-

56 02/2010
Efektywny blitter

A teraz wyciągnijmy wartość alfa przed na- ko 16 bitów. Co by było, gdyby zostawić star- ka rzeczy. Kolory z obrazu źródłowego muszą
wias: sze 8 bitów w młodszym 16-bitowym słowie zostać stratnie przekształcone z formatu pik-
na wynik mnożenia, a w górnym 16-bitowym sela 888 na 565. Musimy również użyć 5-bi-
d = d + a * ( s – d ) słowie wstawić drugi kanał? Popatrzmy: tową alfę, żeby zmieścić się w buforach. Stra-
ta jakości, może się wydawać, dosyć znaczna,
Sukces! Udało nam się wyeliminować jedno 0606 * 5 / 10 = 3030 / 10 = 0303 jednak w rzeczywistości jest praktycznie nie-
mnożenie! A ponieważ przetwarzamy trzy zauważalna. Implementacja tej optymalizacji
kanały, rzeczywista liczba mnożeń spada z Działa! Na obsługę trzech kanałów zabrak- przedstawiona jest na Listingu 8. To, co się
sześciu do trzech. Liczba instrukcji asemble- nie nam jednak miejsca w rejestrze. Zauważ- dzieje w środku pętli, jest czarną magią w po-
ra pozostała niezmieniona, ale czy to ozna- my jednak, że docelowy format piksela to i równaniu z poprzednią wersją, ale spójrzmy
cza, że kod będzie się wykonywał tyle sa- tak 565. Rozpiszmy to sobie: na Listing 9. Liczbę mnożeń udało się zredu-
mo czasu? Należy wykonać pomiary i wy- kować do jednego, a liczba wykonywanych in-
ciągnąć wnioski, co niech zostanie zadaniem RRRRRGGGGGGBBBBB strukcji asemblera spadła do 21! Dobrze rów-
dla czytelnika. nież zauważyć, iż mimo wielu operacji odczy-
Trzy mnożenia na piksel to całkiem do- Hmm... A gdyby tak... tu z pamięci (z tego samego adresu) w kodzie
bry wynik, liczby kanałów zmienić się nie wysokopoziomowym, kompilator był w sta-
da, a mnożenia przez wartość alfa też raczej 00000GGGGGG00000RRRRR000000BBBBB nie wygenerować tylko jeden rzeczywisty do-
nie wyeliminujemy. Czy spoczniemy zatem stęp do pamięci.
na laurach? Nie, zmniejszymy liczbę mno- Udało nam się zmieścić trzy kanały w 32 bi- Może się wydawać, że tego to już się na pew-
żeń z trzech do jednego. Niemożliwe? Ha! W tach, zostawiając miejsce na wynik mnoże- no bardziej nie da zoptymalizować. Ale proszę
chwili obecnej przetwarzamy 8-bitowe war- nia, dzięki czemu możemy obliczyć wartości się zastanowić, czy 21 instrukcji asemblera to
tości na 32-bitowych rejestrach. Przy mnoże- wszystkich kanałów, wykonując tylko jedno nie jest troszkę za dużo, w przypadku gdy war-
niu przez 8-bitową alfę wykorzystane jest tyl- mnożenie. Oczywiście należy zauważyć kil- tość alfa jest równa 0, a więc piksel powinien

Rysunek 4. Animacja postaci w grze Tiger Woods PGA Tour

Listing 6. Naiwny blitter 8888 –> 565 Listing 7. Skompilowany program z Listingu 6

UInt32* src; .L5:


UInt16* dst; ldrh r4, [r8, #0]
ldr ip, [sl], #4
do and r2, r4, #2016
{ mov lr, ip, lsr #24
int w = width; rsb r0, lr, #255
do mov r1, r2, asr #3
{ and r3, r4, #63488
UInt32 a, ia, sr, sg, sb, dr, dg, db; mov r6, r3, asr #8
a = ( *src & 0xFF000000 ) >> 24; and r5, r4, #31
ia = 255 – a; mul r4, r0, r1
mov r2, r5, asl #3
sr = ( *src & 0x00FF0000 ) >> 16; mul r5, r0, r6
sg = ( *src & 0x0000FF00 ) >> 8; and r1, ip, #65280
sb = ( *src & 0x000000FF ); mul r6, r0, r2
dr = ( *dst & 0xF800 ) >> 8; mov r3, r1, lsr #8
dg = ( *dst & 0x07E0 ) >> 3; and r0, ip, #16711680
db = ( *dst & 0x001F ) << 3; mla r1, lr, r3, r4
mov r2, r0, lsr #16
dr = ( sr * a + dr * ia ) >> 8; mla r3, lr, r2, r5
dg = ( sg * a + dg * ia ) >> 8; and ip, ip, #255
db = ( sb * a + db * ia ) >> 8; mla r2, lr, ip, r6
mov r0, r1, lsr #5
*dst = ( ( dr & 0xF8 ) << 8 ) | ( ( dg & 0xFC ) << 3 ) | ( ( db & 0xF8 ) >> and ip, r3, #63488
3 ); and r1, r0, #2016
orr r0, ip, r1
src++; mov r2, r2, asl #16
dst++; orr r3, r0, r2, lsr #27
} subs r7, r7, #1
while( --w ); strh r3, [r8], #2 @ movhi
} bne .L5
while( --height );

www.sdjournal.org 57
Programowanie gier

być po prostu przeskoczony bez zmian? A je- ci musiały się jednocześnie znajdować jesz- dowania obrazów z dysku, ale dużo lepszym
żeli alfa jest równa 255 – nie ma potrzeby wy- cze 3 inne animacje o podobnych rozmia- rozwiązaniem jest wykonanie jej tylko raz
konywania blendingu, można po prostu sko- rach. Przy ograniczeniu możliwej do użycia – podczas tworzenia assetów programu. Wy-
piować (po zmianie formatu piksela) wartość pamięci do 10 MB (wymaganie platformy) nikowy rozmiar na dysku może być co praw-
z obrazu źródłowego do docelowego. Są to rze- stało się to znacznym problemem. Pewnym da większy – PNG z animacją zajmował 99,6
czy, wydaje się, oczywiste, ale kto o tym wcze- rozwiązaniem byłoby użycie obrazu z paletą, KB, a po kompresji RLE 121 KB, ale należy
śniej pomyślał? Koszt związany z obsługą róż- co zmniejszyłoby zużycie pamięci czterokrot- pamiętać, że obraz w formacie RLE lepiej
nych zachowań w zależności od alfy nie jest nie, jednak oznaczałoby to znaczną degrada- się kompresuje. Po spakowaniu obrazu PNG
oczywiście zerowy, ale spójrzmy na pomiary cję jakości obrazu, chociażby przez utratę an- programem 7zip rozmiar wynikowego archi-
szybkości wykonywania. Blitowanie obrazu, w tyaliasingu czy przezroczystości cieni. wum wyniósł 99,2 KB, a obraz RLE skompre-
którym wszystkie piksele mają wartość kanału Problem został usunięty przez zastosowanie sował się do 45 KB. Nie dość, że zmniejsza-
alfa równą 0, zajęło 4,34 ms. Dla wartości alfa kompresji RLE (Run Length Encoding). Polega ją się wymagania pamięciowe, zmniejsza się
równych 255 było to 7,43 ms. Dla innych war- ona na ustaleniu kodów operacji, które potem więc również zajętość dysku przez aplikację.
tości, czyli wtedy gdy musiał być wykonywany są odpowiednio interpretowane przez blitter.
blending, rysowanie trwało 15,57 ms. Różni- Przykładowo, kod 0 niech odpowiada ciągowi Co dalej?
ca dosyć znaczna! Szczególnie gdy w progra- pikseli przezroczystych (w ciągu danych zapisa- Przedstawione techniki w żadnym razie nie
mie wykorzystujemy grafiki takie jak przedsta- na jest długość ciągu obejmowanego przez kod), wyczerpują możliwych do zastosowania roz-
wiona na Rysunku 3. Aby uzyskać zadowalają- kod 1 może odpowiadać pikselom nieprzezro- wiązań. Z całą pewnością da się wymyślić
cą liczbę klatek na sekundę przed wprowadze- czystym (zapisujemy dodatkowo długość cią- jeszcze wiele innych sposobów na przyspie-
niem optymalizacji polegającej na zmianie za- gu i wartości pikseli, dla szybkości można użyć szenie programowego rysowania obrazów,
chowania w zależności od wartości alfa, grafi- formatu docelowego, e.g. 565), piksele półprze- czego czytelnikom życzę. Pewną pomocą mo-
ka musiała zostać pocięta na kilka mniejszych. zroczyste mogą być opisane kodem 2 (plus dłu- że być książka Graphics Programming Black
Zauważenie problemu umożliwiło użycie nie- gość i wartości pikseli razem z kanałem alfa). To Book autorstwa Michaela Abrasha, traktu-
pociętej grafiki bez spadku wydajności, równo- oczywiście tylko przykład. Analizę obrazów jąca co prawda o sprzęcie trochę przestarza-
cześnie zmniejszając nakład pracy grafików. podczas kompresji można rozszerzyć o wykry- łym, ale pełna wielu świetnych pomysłów i
O takich rzeczach, jak wczesne wyjście z wanie obszarów takiego samego koloru, obsza- wskazówek. Książkę można ściągnąć za dar-
funkcji, w przypadku gdy użytkownik podał rów ze stałą wartością alfa, gradientów itp. Blit- mo pod adresem http://nondot.org/~sabre/
globalną wartość alfa równą 0, chyba nie trze- ter interpretujący kod 0 może w tym momen- Mirrored/GraphicsProgrammingBlackBook/.
ba mówić. cie przeskoczyć o zapisaną liczbę pikseli, w ogó-
le ich nie przetwarzając. Interpretacja kodu 1 BARTOSZ TAUDUL
Problemy z pamięcią sprowadza się do wywołania funkcji memcpy Bartosz Taudul zajmuje się, pośród wielu innych
Podczas prac nad grą Tiger Woods PGA Tour – odpada konieczność konwersji pikseli z for- rzeczy, rozwojem i optymalizacją niskopoziomo-
dla firmy Electronic Arts pojawił się dość nie- matu 888 na 565 przy każdym rysowaniu. wych procedur graficznych w wieloplatformo-
oczekiwany problem. Blitter co prawda był Po zastosowaniu powyższej metody obszar wej bibliotece opracowywanej w firmie Gamelion
szybki, ale zostały zupełnie zaniedbane wy- pamięci zajmowany przez animację z Rysun- wchodzącej w skład Grupy BLStream.
magania pamięciowe. Przedstawiona na Ry- ku 4 został zmniejszony do 122 KB. Dziesię- Kontakt z autorem: wolf@pld-linux.org
sunku 4 animacja ma rozmiar 2987x103 ciokrotne zmniejszenie, chyba całkiem nie-
piksele i, przy 32-bitowym kolorze, zajmu- źle? Operacja kompresji może być na tyle Listing 9. Skompilowany program z
je w pamięci 1,17 MB. Co gorsza, w pamię- szybka, aby dało się ją wykonywać podczas ła- Listingu 8

Listing 8. Jednoczesne przetwarzanie wszystkich kanałów .L5:


ldr r0, [r5], #4
do ldrh r2, [r4, #0]
{ and r3, r0, #248
int w = width; and ip, r0, #16252928
do and r1, r2, #2016
{ mov r3, r3, lsr #3
UInt32 a, tmp; orr r2, r2, r1, asl #16
a = *src >> 24; orr r3, r3, ip, lsr #8
and r1, r0, #64512
tmp = ( ( *dst | ( ( *dst & 0x07E0 ) << 16 ) ) & 0xFFFFF81F ) + ( ( ( ( ( ( orr ip, r3, r1, asl #11
*src & 0xF80000 ) >> 8 ) | ( ( *src & 0x0000F8 ) >> 3 ) | ( bic r2, r2, #2016
( *src & 0x00FC00 ) << 11 ) ) - ( ( *dst | ( ( *dst & 0x07E0 rsb r3, r2, ip
) << 16 ) ) & 0xFFFFF81F ) ) * a ) >> 5 ); mov r0, r0, lsr #24
*dst = ( tmp & 0xF81F ) | ( ( tmp & 0x07E00000 ) >> 16 ); mul r1, r0, r3
add ip, r2, r1, lsr #5
src++; and r3, ip, #132120576
dst++; bic r0, ip, #2016
} orr r2, r0, r3, lsr #16
while( --w ); subs lr, lr, #1
} strh r2, [r4], #2 @ movhi
while( --height ); bne .L5

58 02/2010
Programowanie gier

Xcode
Xcode – oto czytelnik. Czytelniku – oto Xcode. Poznajcie się.
Wprowadzenie do programowania najpopularniejszego
urządzenia mobilnego na świecie.
iPhone i App Store to światowy fenomen. Firma Apple dokonała
niemożliwego i uwolniła wielką siłę niezależnych developerów mogących
od teraz spełniać swoje wizje i tworzyć gry jak dawniej, w pojedynkę lub
w małych zespołach, siedząc nad nimi po pracy, w garażach.
Krok drugi
Dowiesz się: Powinieneś wiedzieć: – ściągnięcie i zainstalowanie
• Co potrzebne jest do programowania gier • Podstawy obsługi Xcode; odpowiednich materiałów
na iPhone’a; • Znać podstawy C++ i Objective-C; Po pomyślnej rejestracji na portalu pracę czas
• Jak zacząć pracę nad grą i jakie są etapy jej • Przeczytać artykuł dotyczący programowa- zacząć! W zależności od zainstalowanego OS-u
produkcji; nia na iPhone; na Macu należy ściągnąć i zainstalować SDK
• Jak warto zorganizować sobie strukturę pro- • Podstawowe informacje na temat develop- w wersji Leopard bądź Snow Leopard. SDK
jektu. mentu gier. zawiera:

• Xcode – środowisko pozwalające


ga płatna w wysokości $99 (lub 299 dla du- na programowanie/kompilowanie/
żych firm) pozwala na uruchamianie aplikacji uruchamianie stworzonej aplikacji,
Poziom na sprzęcie i późniejszą dystrybucję aplikacji • iPhone simulator – symulator iPhone po-
trudności na App Store. Prócz tego płatna rejestracja da- zwalający na uruchomienie stworzonej
je większy dostęp do bazy wiedzy i przykładów aplikacji, jej testowanie i debugowanie,
przygotowanych przez Apple. Niezbędne będą • Tools – zestaw dodatkowych narzędzi
takie dane, jak numery konta, informacje o ban- pozwalających na łatwiejsze i sprawniej-

D
o napisania gry wymagany jest ku. Należy przy tym pamiętać, że wszelkie przy- sze programowanie i tworzenie aplika-
komputer Mac, co może wiązać chody z App Store należy rozliczyć z Urzędem cji. Jednym z ciekawszych narzędzi jest
się z wydatkiem zaczynającym się Skarbowym. Tak głosi prawo. Instruments pozwalający na dokładne i
w okolicach dwóch tysięcy złotych. Do testo-
wania dzieła na pewno też dobrze mieć do-
celowe urządzenie – iPhone’a lub iPoda To-
uch. Gdy już te absolutnie podstawowe wa-
runki zostają spełnione, nic (lub prawie nic)
nie stoi na przeszkodzie, by rozpocząć pracę
nad grą marzeń. Z tym, co stanąć może, po-
staramy się rozprawić w poniższym artykule.
Zapraszamy do lektury.

Krok pierwszy
– rejestracja na portalu
Czas zacząć. Zdecydowanie pierwszym kro-
kiem powinno być zarejestrowanie na oficjal-
nym portalu developerskim Apple dostęp-
nym pod adresem:
http://developer.apple.com/iphone/
Dzięki temu developer będzie mógł korzy-
stać ze wszystkich zasobów i informacji poma-
gających w programowaniu na iPhone OS. Sa-
ma rejestracja podzielona jest na dwie części.
Pierwsza darmowa umożliwia ściąganie SDK
i uruchamianie aplikacji na symulatorze. Dru- Rysunek 1. Ekran powitalny Xcode IDE

60 02/2010
Xcode

Stwórzmy grę! nie lada doświadczenia i wiedzy. Profesjonalne


Wiele gier powstaje, bazując na już istnieją- i zdroworozsądkowe podejście do sprawy wy-
cych produktach. Warto jednak sięgnąć po maga stworzenia planu produkcji gry. Dzieje się
własny produkt, którym zawojujemy rynek. to w pierwszym etapie zwanym zazwyczaj pre-
produkcją. Podczas tego etapu liderzy projektu
Pomysł – skąd go wziąć? wraz z producentem, bazując na GDD i TDD,
• burza mózgów. gry przygotowują zadania dla poszczególnych
członków zespołu.
Twórcze głowy zasiadają do stołu (na łące,
w pubie itd.) i snują pomysły, dzieląc się swo- Niezbędne narzędzia
imi przemyśleniami. Wyznaczona osoba no- w procesie developmentu gry
tuje. Zakaz krytykowania i wyśmiewania Do sprawnej organizacji całego przedsięwzię-
pod groźbą stawiania kolejki. cia przydadzą się różne narzędzia. Pozwolą
Rysunek 2. Ekran powitalny symulatora iPhone one na łatwiejszą, sprawniejszą i szybszą pra-
• analiza rynku (co na rynku robi konku- cę całego zespołu. W dzisiejszych dniach two-
szybkie namierzenie problemów związa- rencja, na co jest popyt, czego brakuje?); rzenie gry wymaga takich narzędzi jak:
nych z zarządzaniem pamięcią. • przypadkowe olśnienie. Czasami uderza
znienacka, czasami pod wpływem jakiejś • Managing tools – pozwalają na stworze-
Krok trzeci innej gry. App Store pełen jest takich gier, nie planu, przydzielenia zadań członkom
– odpalenie środowiska i stwo- wiele z nich odnosi sukces właśnie dzięki zespołu i koordynację całego procesu pro-
rzenie przykładowej aplikacji nieprzewidywalności i oryginalności. dukcji. Najbardziej znanym komercyjnym
Do tego celu służy środowisko Xcode. Jest to rozwązaniem jest Microsoft Project. Ist-
główne narzędzie SDK pozwalające na tworze- Strona organizacyjna produkcji gry nieją także alternatywne darmowe roz-
nie aplikacji, testowanie, uruchamianie i przy- Czasy, w których każda gra powstawała w zaci- wiązania takie jak np. dotProject.;
gotowywanie wersji na urządzenie. Sercem ze- szu domowym i była tworzona przez jedną lub • Bugtracking – dzięki niemu zarządzanie
stawu narzędzi Xcode jest Xcode IDE – graficz- dwie osoby, dawno odeszły do lamusa. Aktual- błędami, które mogą wystąpić w trakcie
ny kombajn zawierający profesjonalny text editor, nie w tworzenie gry bardzo często zaangażowa- trwania projektu staje się dużo prostsze,
system tworzenia aplikacji, debugger oraz kom- nych jest wiele osób. W zależności od wielkości przejrzystsze i szybsze. Do najpopular-
pilator. Więcej o Xcode można przeczytać pod projektu może to być 4 lub nawet 400 osób. niejszych bugtrackerów należą: Mantis,
adresem: http://developer.apple.com/tools/Xcode/. Aby poprawnie zarządzać taką ekipą, trzeba Bugzilla czy Track Studio;

����
����������
�����������������
�����������
����������������
�����������������

��������������
������������������������������
����������������������������
�������������������������
��������������������������������������������������������������������
������������������������������
���������������������������
����������������������������������

Rysunek 3. Boozle – gra firmy Vivid Games


inspirowana pomysłami z firmowej imprezy Rysunek 4. Przykładowy szkielet głównej klasy w grze zaprojektowany za pomocą UML

Na Skróty
• SDK (ang. Software Development Kit) – Zestaw narzędzi dla programistów niezbędny do stworzenia aplikacji korzystającej z określonych
funkcji pod określonym systemem operacyjnym.
• App Store – Sklep online firmy Apple pozwalający na zakup cyfrowych produktów, między innymi gier na iPhone’a.
• GDD (ang. Game Design Document) – Dokument zawierający wszystkie wymagane informacje pozwalające na stworzenie gry. Tworzony jest
przez “Game Designera”
• TDD (ang. Technical Design Document) – Techniczna wersja GDD opisująca wszelkie zagadnienia dotyczące gry od strony technicznej.
• API (ang. Application Programming Interface) – Interfejs programowania aplikacji umożliwiający komunikację z systemem operacyjnym, bi-
blioteką bądź innym zewnętrznym systemem.
• Cocoa – Jedno z pięciu głównych API systemu operacyjnego Mac OS X firmy Apple,
• Xcode – Zintegrowane środowisko programistyczne firmy Apple. Służy do tworzenia aplikacji i innego oprogramowania przeznaczonego
m. in. na system Mac OS X.
• UML (ang. Unified Modeling Language) – Zunifikowany Język Modelowania służący do opisu świata obiektów w analizie obiektowej oraz
programowaniu obiektowym.

www.sdjournal.org 61
Programowanie gier

• Time manager – zestaw narzędzi pozwa- dzo często zintegrowany jest on bezpo- Tworzenie gry krok po kroku
lający na organizację czasu pracowni- średnio z narzędziami służącymi do za- Etapy produkcji gry dzieli się na następujące
ków, ich czasu pracy przy projekcie. Bar- rządzania projektem. fazy produkcji:

• Preproduction – Etap planowania gry.


W trakcie jego trwania powstaje cały
plan produkcji i lista zadań do wyko-
nania przez poszczególnych członków
zespołu.
• First playable – wynikiem tego etapu
jest pierwsza wersja gry pozwalająca
na sprawdzenie, czy założenia dotyczą-
ce grywalności ustalone w czasie pre-
produkcji sprawdzają się w rzeczywi-
stości.
• Alpha – Na zakończenie tej części pro-
jektu powstaje pełna wersja gry, mo-
że jednak ona zawierać różnego rodzaju
błędy w funkcjonalności. Według najpo-
pularniejszych metod prowadzenia pro-
jektów, wersja Alpha powinna jednak
być już całkowicie wyposażona w tryby
gry, teksty, grafiki itd.
• Beta – Etap projektu, w którym głów-
ną uwagę spędza się na naprawianiu błę-
dów i szlifowaniu finalnego produktu.
• Release Candidate – Po zakończeniu te-
go etapu powstaje pierwsza wersja będąca
kandydatem do wydania gry. Jest to w peł-
ni stabilna, niezawierająca błędów gra.
Rysunek 5. Przykładowy szkielet głównej klasy w grze w języku Java • Gold Master – Powstający w tym czasie
produkt jest finalną wersją gry, która do-
stępna jest dla graczy.
Debugowanie i naprawianie błędów • Localization – Etap, w którym gra jest lo-
Pakiet Xcode zawiera w swoim zestawie bardzo ciekawą i pomocną aplikację o nazwie In-
struments. Dzięki niej jesteśmy w stanie podglądać wiele rzeczy podczas pracy aplikacji na kalizowana na różne języki. W tym cza-
symulatorze bądź na iPhonie. Program ten pozwala między innymi na: sie powstają alternatywne wersje języko-
we gry bądź jedna wersja z możliwością
• przeglądanie stanu pamięci wyboru języków.
Możesz śledzić zmiany alokacji pamięci dla wybranej aplikacji. Dzięki temu łatwo i przyjemnie
• Marketing – Po zakończonych etapach
można namierzyć największe „pochłaniacze” pamięci. Jest to dość istotne, gdyż należy pamię- ukończony produkt jest gotowy do wyda-
tać, że iPhone to tylko telefon i jego zasoby są ograniczone. Najbezpieczniejszą granicą, której nia, aby jednak osiągnął sukces, muszą po-
nie warto przekraczać, to zużycie 30MB realnej pamięci. wstać odpowiednie materiały marketin-
gowe służące do reklamowania i promocji
• znajdowanie wycieków pamięci
gry. Bardzo często zdarza się, że materia-
Opcja bardzo przydatna dla mniej wprawionych programistów. Bardzo często zapomina się o ły marketingowe powstają dużo wcześniej
tak ważnej rzeczy jak zwalnianie zaalokowanej pamięci. Szczególnie zarażeni są tym progra- lub równolegle z procesem produkcyjnym
miści Java przesiadający się na C++. W Javie menadżer pamięci czyści ją za nich, tutaj trzeba gry. Kontakt z mediami i fanami powinien
pamiętać o tym samemu. Skutkiem tego bardzo często zdarzają się wycieki pamięci, które w zostać zawiązany znacznie wcześniej, by
większych projektach jest bardzo ciężko namierzyć. Tutaj z pomocą przychodzi nam opcja Ac-
o grze było wiadomo cokolwiek, zanim po-
tivity Monitora. Dzięki niej dokładnie możemy zlokalizować wyciek cennych bajtów. Program
wskaże nam dokładną linijkę w kodzie, gdzie wyciek nastąpił. Co ciekawe, wycieki pamięci jawi się ona na rynku.
zdarzają się też w samym OS-ie.
Etapy tworzenia kodu gry
• analizę zużycia czasu procesora

Jest to narzędzie podobne do Task Managera znanego z Windowsa. Dzięki niemu może-
Podział prac pomiędzy programistami
my sprawdzić poziom zużycia pamięci realnej i wirtualnej, a także czas zużycia procesora dla Lider programistów wraz z project manage-
wszystkich aplikacji uruchomionych na iPhonie. rem w czasie planowania projektu rozdzie-
lają poszczególnym członkom zespołu za-
• obserwowanie file systemu i dostępu do plików dania. Dobry podział zadań to połowa suk-
Pozwala na przejrzenie wszystkich operacji dyskowych/plikowych, jakie występują od urucho-
cesu. Ważne jest to, aby każdy z programi-
mienia aplikacji na iPhonie. Jest to rzadziej używana opcja, jednakże pozwala ona programi- stów miał swoje pole działania, a współpra-
ście na obserwację zachodzących procesów związanych z plikami. ca pomiędzy kodem poszczególnych progra-
mistów odbywała się za pomocą określone-
go interfejsu.

62 02/2010
Xcode

Tworzenie szkieletu klas w UML let klas mu przydzielonych. Na końcu ca- Programowanie
bazując na TDD przez programistów łość zostaje złożona i dopracowania pod ką- poszczególnych metod i funkcji
Najwygodniejszym i najszybszym sposo- tem interfejsów i komunikacji. Bazując na do- Bazując na specyfikacji przygotowanej podczas
bem na sprawne zaplanowanie rozłożenia kumentacji programiści są w stanie szybko preprodukcji oraz na strukturze kodu zapro-
klas pomiędzy programistami jest stwo- wprowadzić zmiany w kodzie, tak aby speł- jektowanej w UML, dalsza praca to już „buł-
rzenie szkieletu całego projektu. Czy wy- niał on wymagania projektu. Na tym pozio- ka z masłem”. Niestety, jednak podczas two-
obrażacie sobie tworzenie go bezpośrednio mie projektowania powstają także komen- rzenia gry bardzo często zmieniają się części
w kodzie? Byłoby to bardzo czasochłonne i tarze do klas, metod i argumentów, które w projektu, wprowadzane są udoskonalenia i po-
trudne. W tym momencie z pomocą przy- późniejszej produkcji znacznie usprawnią prawiona zostaje grywalność. Dlatego właśnie
chodzi nam UML. Dzięki niemu tworzenie pracę z kodem. pierwszym ważnym etapem programowania
zarysu kodu staje się dużo wygodniejsze, a jest przygotowanie grywalnej wersji gry. To ona
dowolną zmianę można zrobić dosłownie Generowanie kodu pozwoli ocenić całemu zespołowi, czy gra jest
w chwilę. wraz z komentarzami z UML fajna, czy może coś będzie trzeba zmieniać i
Dodatkową zaletą UML-a jest możliwość wyge- dopracowywać. To w tym etapie programista
Recenzja, ewentualne zmiany nerowania kodu w prawie dowolnym języku pro- powinien jak najwięcej czasu poświęcić na gry-
i finalizowanie klas w UML przez lidera gramowania. Dzięki temu po fazie projektowej walność, a mniej przejmować się błędami.
W tworzeniu kodu uczestniczą wszyscy pro- programiści mają gotowy kod, który muszą tylko Gdy okaże się, że pierwsza wersja to praw-
gramiści. Po podzieleniu poszczególnych za- uzupełnić. Wszelkie hierarchie, interfejsy itp. są dziwy hit, pozostaje nic innego, jak zakasać
dań przez lidera każdy z nich tworzy szkie- już określone i praca jest dużo wygodniejsza. rękawy i przejść do programowania. Tutaj
praca jest już bardziej nudna. Bazując na spe-
cyfikacji, należy przygotować wszystkie me-
chanizmy pozwalające obsłużyć całą grę.
Warto pomyśleć także o nowinkach do gry,
które popularne są na iPhonie. Są to między
innymi:

• Facebook – obsługa konta facebook, ofi-


cjalna strona, zapisywanie wyników na
facebook itp.,
• iTunes library – funkcjonalność w aplikacji
pozwalająca na słuchanie plików muzycz-
nych zapisanych na swoim iPhone podczas
gry (zamiast oryginalnej muzyki z gry),
• More games – opcja pozwalająca graczowi
na zapoznanie się z ofertą gier producenta.

Zakończenie

• Testy i polishing gry.


• Stworzenie finalnej wersji gry.
• Wydanie gry na AppStore.
Rysunek 6. Ekran powitalny aplikacji Instruments
Bez wątpienia tworzenie gier na iPhone’a to do-
skonała zabawa, przygoda i szansa dla nieza-
leżnych developerów. Dziesiątki tysięcy (dane
wskazują, że już ponad 100!) aplikacji nie wzię-
ły się znikąd. Każdy szuka swojej niszy i prze-
błysku geniuszu. Powodzenia z projektami i do
zobaczenia na szczycie listy Top 10!

PATRYK BUKOWIECKI
Specjalista ds. PR i marketingu, manager, czujny
obserwator branży gier video, socjolog, redaktor
i wieloletni współpracownik Neo Plus, gracz, pił-
karz. W Vivid Games na stanowiskach producent
i PR and Marketing Manager.

JAROSŁAW WOJCZAKOWSKI
CTO w firmie Vivid Games, programista/project
manager z kilkunastoletnim doświadczeniem,
współwłaściciel firmy Vivid Games, wesoły i po-
Rysunek 7. Przykładowy wyciek pamięci w OS godny człowiek, otwarty na nowe rozwiązania.

www.sdjournal.org 63
Programowanie gier

Cyfrowa kreacja
Artystyczne projektowania gier

Niezależnie od tego, czy tworzymy film, spot reklamowy, efekty


specjalne, wizualizację czy grę, potrzebujemy narzędzi, które pozwolą
nam w produktywny i elastyczny sposób stworzyć to, co widzimy oczami
wyobraźni. Wtedy pojawia się konieczność wybrania oprogramowania
do tzw. cyfrowej kreacji.
w trybie DirectX z wyświetlaniem shaderów,
Dowiesz się: Powinieneś wiedzieć: a xView Mesh Analyzer pozwoli po wszyst-
• Jakie są trendy w aplikacjach trójwymiaro- • Jakie są podstawy terminologi 3D kim sprawdzić poprawność siatki wykona-
wych nego modelu.
• Co najnoweszego znajdziesz na rynku Okno renderingu zostało zmodyfikowa-
• Jak przyspieszyć proces tworzenia przy uży- ne tak, by można było dokonywać korekty
ciu nowoczesnych narzędzi 3D jakości i parametrów bezpośrednio w nim
bez każdorazowego otwierania dodatkowych
funkcji, pozwalając na szybkie podejrzenie
pełniających się rozwiązań, dlatego podział efektu wypalania tekstur przy różnych para-
ma znaczenie dopiero po określeniu swoich metrach wejściowych.
Poziom potrzeb. Narzędzia UV w 3ds Max zostały spe-
trudności cjalnie opracowane pod kątem tworzenia
Autodesk 3ds Max gier i zawierają szereg elementów wskaza-
Najpopularniejszy program służący do ge- nych przez użytkowników w trakcie wie-
nerowania i obróbki grafiki trójwymiaro- loletniego rozwoju aplikacji, wzbogacając

A
ktualnie największym producen- wej. Nie bez powodu nazywany kombaj- 3ds Max o Material Explorer, dzięki któ-
tem tego typu software'u jest fir- nem – modułowa budowa pozwala na do- remu skończyło się przebijanie przez kil-
ma Autodesk, dlatego skupię się wolne konfigurowanie oraz dodawanie i kanaście poziomów materiału, na które na-
na jej produktach i funkcjonalności jaką odejmowanie funkcji przez system wty- rzekali do tej pory użytkownicy. Wisien-
oferują w zakresie animacji oraz wspoma- czek. Rozbudowany język skryptowy czę- ką na torcie jest mental mill, zdobywają-
gania procesu tworzenia gier. Oczywiście sto wykorzystywany jest do automatyzacji cy popularność moduł pochodzący z men-
lwią część pracy wykonuje zespół progra- zadań, a całkowicie konfigurowalny inter- tal images, a pozwalający tworzyć skompli-
mistów, ale nie byłoby czego oprogramo- fejs ułatwia dostosowanie narzędzi do wła- kowane shadery z podglądem w czasie rze-
wać, gdyby nie treść dostarczona przez snych potrzeb. czywistym, co niesamowicie wpływa na
artystów tworzących animacje, postacie, Dla szefa studia graficznego na pewno szybkość generowania tekstur i materiałów
lokacje czy oprawę interfejsu. Autodesk ma to duże znaczenie. Łatwo znaleźć wy- obiektów w grach.
pokrywa wszystkie te dziedziny dzięki ca- kwalifikowanego człowieka, który z miej- Wprowadzone kontenery ułatwiają pra-
łej linii produktów ukierunkowanych na sca siada i zaczyna pracować. Ma to duże cę z dużymi scenami, gdzie na jednym kom-
wykorzystanie w danej dziedzinie kreacji. znaczenie przy projektach, w których za- puterze można tworzyć postacie, na drugim
Celowo nie wspominam tu o teksturach soby ludzkie wykorzystuje się w zależno- lokacje, na trzecim mapę, a na kolejnym łą-
i obróbce finalnej obrazu ruchomego, po- ści od potrzeb i obciążenia pracą na da- czyć to wszystko razem, nie obciążając ma-
nieważ z tego można byłoby napisać ko- nym etapie. szyn, a tym samym uprzyjemniając i przy-
lejny artykuł, a są to rzeczy, które są tylko Graphite modeling tool - nowe narzędzia spieszając pracę.
częścią procesu. Skupię się na krótkich do modelowania poligonowego zostały ukie-
opisach najważniejszych w dziedzinie gier runkowane na szybkie manipulowanie bryła- Maya
aplikacji z całego portfolio Autodesk. Nie- mi i siatką – zwiększono ich ilość do niemal Będący standardem w produkcji filmów pa-
które z poniższych produktów występują stu nowych funkcji służących tylko do ope- kiet coraz częściej jest zauważany przez twór-
jako samodzielne aplikacje, niektóre są czę- racji na obiekcie. Dodano długo oczekiwane ców gier. Powodem jest fakt zbliżenia się tych
ścią pakietów, bądź mają charakter uzupeł- rzeźbienie oraz malowanie tekstur. Pozwala dwóch dziedzin rozrywki do tego stopnia, że
niający, niemniej jednak całość produkcji to w krótkim czasie nanieść poprawki na mo- kino myśli o interaktywnych filmach, a prze-
gier jest procesem ciągłym i wymagającym del. Oczywiście aby szybko zobaczyć poten- mysł gier myśli o kinowej jakości obrazie i ani-
kompletnego systemu, a tym samym uzu- cjalny efekt końcowy okna podglądu, działają macji w grach.

64 02/2010
Cyfrowa kreacja

Maya ze względu na swoja przeszłość łą- chu. Możliwość pobrania danych z systemów je spore możliwości, jednak na pewnym eta-
czy doskonale oba te światy, zapewniając po Motion Capture i późniejsza ich obróbka da- pie precyzji zaczyna brakować dbałości o de-
jednej i drugiej stronie wszechstronne i do-
skonałe narzędzia i często jest wykorzysty-
wana jako środowisko systemowe do dal-
szego rozwoju projektu. Pozwala na to dzię-
ki obsłudze języków C++ i Python oraz wła-
snego MEL.
W Polsce ma to zapewne mniejsze znacze-
nie, ale może być istotne przy pracy w obrę-
bie jednego podmiotu na różnych platfor-
mach. O ile 3ds Max jest przeznaczony tyl-
ko dla MS Windows, o tyle Maya działa rów-
nież na MacOS X oraz Linux. Jest to jedyny
komercyjny produkt zapewniający taką ela-
styczność.
Tak samo jak w przypadku 3ds Max spo-
ro materiałów w Internecie pomaga rozwijać
umiejętności, chociaż w Polsce jest mniej lu-
dzi znających na poziomie zaawansowanym
tę linię produktów, ale z reguły jak już ktoś tą
wiedzę posiada, to jest profesjonalistą. Rysunek 1. Autodesk 3ds Max 2010, przygotowanie skóry postaci

Softimage
Znany głównie z nazwy, ale rzadko od stro-
ny użytkowej program, który ma najdłuższą
tradycję ze wszystkich produktów gamy Au-
todesk. Uznany za standard w dziedzinie fil-
mowej animacji postaci, a w grach coraz czę-
ściej z tego powodu wykorzystywany do two-
rzenia modeli.
Posiada zintegrowaną platformę ICE
(Interactive Creative Environment), będącą
zbiorem narzędzi pozwalającym składać z
klocków efekty wizualne. Nowej generacji
silnik GigaCore zapobiega zawieszaniu się
programu przy obiektach składających się
z wielu milionów punktów, a przy okazji
znacznie przyspiesza obróbkę dużych scen
i plików.
Jedno z najciekawszych narzędzi to Face
Robot, będący do tej pory osobnym produk-
Rysunek 2. Autodesk Maya 2010, malowanie trójwymiarowej trawy bez modelowania
tem, teraz zintegrowany z Softimage, służą-
cy tworzeniu w pełni animowalnych siatek,
mimiki i realistycznie wyglądających twa-
rzy – szczególnie użyteczna funkcja, gdy w
grze trzeba stworzyć wielu różnych bohate-
rów, a na modelowanie każdego osobno nie
ma czasu.
Całość w pełni współpracuje z pozostałymi
produktami Autodesk – w Polsce jeden z naj-
większych producentów gier wykorzystuje
właśnie równolegle Softimage i 3ds Max.

MotionBuilder
Zaawansowana animacja postaci (nie tylko
humanoidów) wymaga często wielu godzin
spędzonych przed komputerem. Naprzeciw
oczekiwaniom animatorów wychodzą mo-
duły (Character Animation Toolkit i Character
Studio) do wspomagania tego procesu od two-
rzenia szkieletów, przez łączenie ich z siatka-
mi, aż po końcową sekwencję animacji ru- Rysunek 3. Autodesk Softimage 2010, miksowanie animacji ruchu

www.sdjournal.org 65
Programowanie gier

tale animacyjne w dopasowaniu do konkret- Dlaczego warto zainwestować w dodat- macji ruchu? Jak zwykle odpowiedzią bę-
nej sytuacji. kowy program tylko do generowania ani- dzie to, czego oczekujemy od produktu fi-
nalnego i czasu (a tym samym kosztów), ja-
kie możemy poświęcić na proces produk-
cyjny.
Jeżeli wierzyć twórcom MotionBuilde-
ra – pozwala on skrócić czas przygotowa-
nia animacji o przeszło 250%! To wszyst-
ko dzięki prewizualizacji, automatycznym
modyfikacjom skali, układu kończyn, nie-
destrukcyjnej edycji kluczy i dopasowaniu
do modelu. Większość dużych game deve-
loperów na świecie używa właśnie Motion-
Buildera do animacji postaci – można by
rzec, że jest to industry standard.

Mudbox
W wirtualnym rzeźbieniu konkurencja jest
silna, a Autodesk nieśmiało od kilku lat sta-
wia w tej dziedzinie pierwsze kroki. Nie-
mniej jednak ma jedną niesamowitą zaletę
Rysunek 4. Autodesk MotionBuilder 2010, przygotowanie kinematyki człowieka – pełna integracja z pozostałymi produkta-
mi tej marki. Oczywiście kwestią gustu jest
przyzwyczajenie do interfejsu, ale funk-
cjonalność podstawowa narzędzi wszyst-
kich niezależnych producentów pozostaje
zbliżona. Narzędzia rzeźbiarskie, warstwy,
wypalanie tekstur – to cecha wspólna, ale
jednak jest coś ciekawego w Mudbox, co,
poza wspomnianą integracją, podnosi je-
go użyteczność (i to wysoko) ponad stan-
dard. Niespotykana gdzie indziej precyzja
podglądu czasu rzeczywistego tego, co two-
rzymy, dzięki której efekty naszej pracy wi-
dać od razu. Teraz już nie trzeba poprawio-
nego modelu, materiałów czy shaderów im-
portować do aplikacji 3D, żeby zobaczyć fi-
nalny efekt swojej pracy – wszystko widać
w MudBox i to bez renderingu!

Maya Composite i MatchMover


Rysunek 5. Autodesk Mudbox 2010, rzeźbienie trójwymiarowe Jak już stworzymy wspaniałą grę o nietu-
zinkowej fabule, zaczynamy się zastanawiać
nad opakowaniem jej w przepiękną anima-
cję intro. Wtedy zaczynają się schody. Są fir-
my, które zlecają takie rzeczy na zewnątrz,
ale są też takie, które mają tak dobry zespół
ludzi, że grzechem byłoby pominąć ich ta-
lent w tej części produkcji. Autodesk włą-
czył te dwie aplikacje w skład pakietu Maya
i dzięki temu stworzył kompleksowe rozwią-
zanie filmowe.
MatchMover jako narzędzie śledzące
ruch pikseli obrazu wideo potrafi stwo-
rzyć pełny ruch kamer i matrycę punktów
referencyjnych pozwalających skompono-
wać obraz wideo z animacją. Pomimo oczy-
wistych zalet w tworzeniu efektów filmo-
wych należy pamiętać, że coraz częściej w
grach kamery prowadzi się jak w hollywo-
odzkiej krainie snów, a MatchMover jest
najprostszym sposobem na uzyskanie efek-
Rysunek 6. Autodesk Maya 2010, MatchMover, śledzenie ruchu kamery w przestrzeni trójwymiarowej tu ujęcia kinowego.

66 02/2010
Rysunek 7. Autodesk Maya 2010, Composite, kompozycja obrazu

Maya Composite (znany wcześniej jako • FBX – międzyplatformowy format wy-


Toxik) jako system kompozycyjny pozwoli miany danych, pozwala w jednym stu-
wykończyć animację i finalnie połączyć jej diu wykorzystywać całą gamę aplikacji
elementy w jedną całość jak Photoshop – tyl- (nie tylko Autodesk!) i wymieniać mię-
ko w ruchu. Włączenie Maya Composite do dzy nimi (w zakresie funkcjonalności)
pakietu pozwoli nam zaoszczędzić kilka ty- bezstratnie dane.
sięcy na dodatkowym oprogramowaniu przy
zachowaniu zgodności formatu. Całą ani- Oczywiście o każdym z programów moż-
mację można podzielić na „pasy” renderingu na napisać osobny artykuł, a nawet książ-
i po złożeniu w Maya Composite uzyskać wy- kę, ale zebranie wszystkiego w jednym
sokiej jakości końcowy efekt bez mozolnych miejscu z krótkim opisem pozwoli zo-
prerenderingów. Efekty specjalne, korekty rientować się w sytuacji i wybrać wła-
kolorystyczne, głębia ostrości i inne procesy ściwy zestaw dla siebie. Nie bez znacze-
zajmujące wiele godzin obliczeń w tej aplika- nia jest również fakt popularności Auto-
cji robione są niemal natychmiast. desk w branży kreatywnej ze względu na
Poza powyższymi, znanymi produktami, to, że nawet brak wiedzy na danym etapie
należy zwrócić uwagę na kilka mniejszych projektu pozwala na szybkie rozwiązanie
elementów układanki (co nie znaczy mniej po- problemu dzięki tysiącom informacji za-
trzebnych), które w procesie tworzenia mogą wartych na forach internetowych, stro-
zapewnić zwiększenie wydajności, a z których nach pasjonatów 3D czy w tutorialach.
istnienia niewiele osób zdaje sobie sprawę. Popularność świadczy o sile oprogramo-
wania, ponieważ pozwala szybko rozwią-
• ImageModeler – na podstawie już kilku zać skomplikowane problemy i nigdy nie
zdjęć pozwala na wymodelowanie rze- pozostaniemy bez pomocy, a to chyba jed-
czywistych obiektów trójwymiarowych. na z najistotniejszych funkcji, jakiej po-
Im więcej zdjęć, tym dokładniej zostanie trzebujemy!
wykonane modelowanie (w procesie au-
tomatycznym lub manualnym), a do ca-
łości zostanie dołączona tekstura z koor- ARKADIUSZ WYCHADAŃCZUK
dynatami mapowania. Pasjonat filmowych efektów specjalnych oraz
• Stitcher – skleja dowolną ilość zdjęć w animacji 3D. Zajmuje się obrabianiem oraz two-
panoramy, sfery i hemisfery. rzeniem grafiki i obrazu ruchomego od niemal
• Human IK – zaawansowane rozwiąza- piętnastu lat. Zdobył doświadczenie zawodowe
nie do tworzenia w czasie rzeczywistym współpracując ze większością polskich (i niektó-
animacji humanoidów na potrzeby gier rych europejskich) studiów postprodukcyjnych
z uwzględnieniem interakcji z otoczeniem. oraz stacji telewizyjnych, zarówno jako twórca
• Kynapse – sztuczna inteligencja środo- wizualny jak i doradca oraz specjalista technicz-
wiskowa pozwalająca między innymi na ny. Pozwoliło mu to uzyskać wszechstronną wie-
generowanie zachowań postaci i tłumu dzę w każdej gałęzi twórczej związanej z nowy-
w zastanych warunkach lokacji gry. mi mediami.

www.sdjournal.org
Programowanie gier

Programowanie
wizualne
Co to takiego?
Niniejszy tekst to informacje, przykłady i tutorial przybliżające
technologię Quest3D. Artykułem tym chcę pokazać, że można tworzyć
aplikacje 3D i gry szybko oraz bez znajomości języka programowania,
bibliotek DirectX czy OpenGL. Jeszcze raz – można. Jest do tego gotowe
narzędzie. Resztę znajdziecie poniżej.
Kiedy prezentuję obraz znajomym firmom czy
Dowiesz się: Powinieneś wiedzieć: też na targach, bardzo często słyszę ...acha, czyli
• Co to jest programowanie wizualne; • Co to jest aplikacja 3D. nie mogę programować tradycyjnie? I poprawiam
• Czym Jest Quest3D; ich Nie w tym rzecz, że nie możesz, ale że nie musisz,
• Czym nie jest :); bo nie ma takiej potrzeby.
• Jak szybko tworzyć aplikacje 3D bez znajo- Mamy do dyspozycji channnele, które może-
mości języka programowania. my wypełnić za pomocą LUA Script i tam stwo-
rzyć swój mały kawałek kodu. Ponadto kiedy
ktoś się bardzo uprze, zawsze ma do dyspozycji
łączyć ze sobą, po prostu przeciągając linię od darmowe biblioteki SDK i może pisać w C++
jednego do drugiego. Na liniach łączących widać swoje własne autorskie channele, a następnie
Poziom czarną strzałkę informującą, w którym kierun- używać ich w środowisku Quest3D na takich sa-
trudności ku danego połączenia przekazywane są informa- mych zasadach jak wszystkie inne.
cje. Większe fragmenty grafu możesz zwinąć do Dzięki temu możliwości nigdy się nie koń-
postaci folderu (patrz Rysunek 1), aby struktura czą, a program rozwija się zarówno w pracowni
twojego programu była przejrzysta i czytelna dla producenta, jak i w domach i firmach jego użyt-

Z
apewne wiele razy spotkałeś się z listin- innych pracujących nad tym samym projektem. kowników.
gami programów pisanych w takich ję- W ten sposób programujesz wizualnie.
zykach jak C++, Java, C# czy innych. Metoda tworzenia w pełni funkcjonalnych Programowanie wizualne
Pojedyncze linie tworzą funkcje lub procedury, aplikacji Quest3D sprawia, że jest on narzę- 3D na przykładzie Quest3D
z których składa się program. Jeżeli poznałeś je- dziem dla wszystkich. Pracują w nim graficy- Wydajność wewnętrznego silnika 3D nie ugina
den z takich języków, na pewno wiesz, że dużo 3D, projektanci, inżynierowie i ludzie ze świata się pod sceną zawierającą wiele milionów trójką-
pracy kosztuje poznanie nazw funkcji, składni , rozrywki, bo każdy może po prostu usiąść i za- tów (face'ów). Najwiekszą jednak zaletą progra-
a potem pilnowanie, aby podczas pisania progra- cząć prace – bez wielomiesięcznych kursów na- mowania wizualnego w Quest3D jest szybkość
mu nie pojawiła się literówka czy też czeski błąd uki języka. To jest właśnie serce Quest3D. budowania aplikacji. Ja nazywam to wydajnością
albo parametry funkcji podane w odwrotnej ko- programowania, która zestawiona z mocnym sil-
lejności, co może spowodować, że programu nie Aplikacje 3D nikiem renderującym pozwala na naprawdę wie-
uda sie skompilować. programowane wizualnie
Z drugiej strony może niekoniecznie chcesz Quest3D jest jednocześnie wizualnym środo-
być programistą. Ja np. nigdy nie chciałem nim wiskiem programistycznym oraz wydajnym sil-
Tutorial na płycie
Aby ułatwić początkującym i tym po prostu
być. Chciałem po prostu móc wprowadzić inte- nikiem renderującym 3D. Służy do tworzenia ciekawym zaznajomienie się z podstawa-
rakcję do wykonywanych przez siebie scen i mo- aplikacji 3D. Zarówno tych małych wirtual- mi Quest3D, przygotowałem videotutorial,
deli 3D. Z pomocą przyszło właśnie programo- nych spacerów, prostych gier 3D, jak i większych który przekazuję wraz z niniejszym nume-
wanie wizualne. i sieciowych produkcji widzianych z różnych ka- rem SDJ. Jest to krótka lekcja ukazująca krok
po kroku stworzenie nieskomplikowanej
Charakteryzuje się ono tym, że twój program mer. Jednocześnie tworzymy w nim duże sy-
gry dla jednego gracza. Gatunek: western.
w wersji źródłowej nie jest już wieloma liniami mulatory obliczane przez kilkanaście maszyn. Każdy jest w stanie wykonać taką aplikację
kodu. W programowaniu wizualnym źródło Jest zatem środowiskiem bardzo skalowalnym. , postępując za tutorialem w przeciągu kilku
twojego programu stanowią bloki (channels) i Wszystkie wymienione rodzaje aplikacji stwo- godzin. Później pozostaje kwestia wymiany
połączenia między nimi, wizualizowane jako rzysz bez wpisania choćby jednej linii kodu. obiektów na swoje. Zapraszam serdecznie
graf. Głównym narzędziem nie jest klawiatura, Wyobrażam sobie, że wielu rdzennych progra- do zapoznania się z tutorialem.
tylko myszka. Poszczególne klocki grafu możesz mistów może poczytać to jako minus aplikacji.

68 02/2010
Programowanie wizualne

le. Dla przykładu dość statyczna scena ukazana


na pierwszych dwóch obrazkach powstała po-
przez jedno przeciągnięcie zbioru Quest'owych
klocków zapisanych na liście Templates. Są to go-
towe do użycia większe i mniejsze grafy fragmen-
tów aplikacji. Wystarczy je przeciągnąć do grafu i
po prostu połączyć z resztą naszych klocków. To
jest ogromnie przyspieszenie i uproszczenie dla
programistów. Aby dodać do naszej sceny kame-
rę orbitującą wokół obiektu, wystarczy usunąć z
grafu nasze Basic Camera i zamiast tego przecią-

Rysunek 2. Efekt grafu powyżej – scena 3D w


czasie rzeczywistym

Rysunek 3. Fragment zbioru szablonów


Rysunek 1. Przykład grafu - prosta aplikacja 3D gotowych do użycia – Templates

R E K L A M A
Programowanie gier

gnąć z listy Templates nowy zestaw klocków zapi- Directional Light, oraz kamera, która ową scenę rów gry. Do najważniejszych należy zaliczyć Sil-
sany pod nazwą Object Inspection Camera. obserwuje z zadanego punktu widzenia – u nas niki fizyczne: ODE, Newton, jest też płatny do-
W Quest3D w bardzo prosty sposób możesz Basic Camera. Wszystko to podłączamy do kloc- datek: PhysX. Możemy wybrać ten, który będzie
oprogramować urządzenia do sterowania takie ka Render odpowiedzialnego za wyświetlenie na- spełniał nasze oczekiwania. Są zintegrowane i go-
jak klawiatura, mysz, joystick i inne, włączając w szego grafu jako obraz 3D w aplikacji. Na Rysun- towe do użycia. Czeka na nas także mechanizm
to wirtualne rękawice czy chełmy. Co więcej, to ku 2 widać efekt tej najprostszej aplikacji 3D. oświetlenia słonecznego ustawianego za pomo-
środowisko integruje w sobie elementy niezbęd- cą godziny, pory roku i położenia geograficznego.
ne w wielu grach (silnik fizyczny, generowanie Przykłady aplikacji Mamy do dyspozycji również takie parametry jak
tłumu, szukanie drogi). Pisząc grę metodą tra- wykonanych w Quest3D wiatr, deszcz czy zamglenie - słowem, kompletny
dycyjną, sam musiałbyś je zintegrować. Modele Jak pisałem wcześniej , środowisko to jest bardzo system pogodowy (Weather System).
używane w tym środowisku można wykonać za skalowalne. Na kilku przykladach postaram się W Quest3D można również tworzyć aplika-
pomoćą dowolnego pakietu graficznego 3D, jak przybliżyć najbardziej znanych albo zasługują- cje sieciowe, i to na dwa sposoby. Pierwszy to ne-
chociażby 3ds max, maya, blender, cinema, a na- cych na uznanie aplikacje wykonane przez róż- tworking budowany na bibliotekach DirectPlay
stępnie zaimportować do Quest3D poprzez je- ne firmy z bardzo rozbieżnych branż. Wiele firm wchodzących w skład DirectX. Drugi to tzw. soc-
den z uniwersalnych formatów: COLLADA, X, używa tego środowiska do celów promocyjno-re- kety. Z kolei do optymalizacji większych map te-
a wkrótce również FBX. klamowych. Przykładowo, w branży dewelope- renów służy moduł Nature Painting, który po-
Na Rysunku 1 widać graf przedstawiający pro- rów mieszkań, domów i innych nieruchomości trafi doskonale zoptymalizować tereny miejskie
stą scenę 3D. Każdy, kto spotkał się już z grafiką jest to idealne rozwiązanie. Firma nie musi na- oraz wielkie zalesione połacie. Producent w ko-
3D i zasadami tworzenia takich obrazów, wie, wet zatrudniać programisty. lejnej wersji Quest3D zapowiada także rewolu-
ze każda taka scena składa się z 3 grup elemen- cyjny edytor terenu. Wewnątrz programu Qu-
tów: obiekty 3D – w tym przypadku napis trój- Możliwości silnika Quest3D est3D mamy możliwość tworzenia własnych
wymiarowy oraz podłoże, światło, które owe Środowisko Quest3D jest silnikiem komplet- shaderów w jęz. HLSL lub wczytywania plików
obiekty oświetla abyśmy mogli je zobaczyć – w nym. Znaczy to, że zawarte w nim moduły i pod- .fx. Dostępny jest również global shader.
tym przypadku zamknięte w folderze o nazwie silniki wystarczają do zrobienia sporych rozmia- Z działki animacji warto wspomnieć o ani-
macji szkieletowej, mikserze sekwencji aminacji
(tzw. motion blending), potrzebny może okazać
się wbudowany system tkanin (cloth rendering).
Jeżeli postaci będzie więcej, z łatwością będziesz
mógł skorzystać z generowania tłumu za pomo-
cą crowd rendering.
Do wyliczonego zbioru należy doliczyć jeszcze
gotową realistyczną wodę, zaawansowany system
cząsteczek, płynną zmianę ruchu (np. ze space-
ru w bieg), ekspozycję światła HDR, obsługę baz
Rysunek 4. Agencje PR tworzą za pomoca Quest3D małe i sympatyczne gry reklamowe oraz prezentacje, danych (mySQL i ODBC), obsługę wielu forma-
które całkowicie mieszczą się w jednym pliku EXE i można je łatwo przesyłać Internetem, a uruchomienie tów dźwiękowych, oczywiście z dźwiękiem 3D,
aplikacji nie wiąże się z instalacją czegokolwiek. Po prostu jeden plik exe działający na zasadzie Click&Run
renderowanie na wielu komputerach tej samej
sceny. Na koniec to wszystko możemy wyren-
derować jako aplikację 3D (stereorendering lub
anaglif). Pełne porównanie z opisem modułów
znaleźć można na stronie www.quest3D.pl.
Jak widzisz, jest w czym wybierać. To wszyst-
ko jest już w środku i nie wymaga dogrywania ja-
kichkolwiek pluginów czy innego rodzaju roz-
szerzeń. Zainstaluj i używaj.

Rysunek 5. Pełnowymiarowe gry 3D tworzą zarówno duże studia, jak i małe grupy. W tych drugich W Sieci
często nawet nie ma programisty, tylko kilku grafików 3D i animatorów
• quest3d.pl – strona główna i podstawowe
informacje o technologii i zastosowaniu;
• forum.quest3d.pl – podstawowe źró-
dło pomocy, jeżeli zaczniesz używać
Quest3D, również linki do tutoriali;
• support.quest3d.com – aktualna doku-
mentacja online w j. Angielskim.

ARKADIUSZ BRZEGOWY
Ekspert i certyfikowany trener Quest3D. Partner
holenderskiej firmy Act3D, producenta technolo-
gii. Właściciel firmy oferującej oprogramowanie
Rysunek 6. Ponadto jednymi z najczęściej wykonywanych aplikacji w Quest3D są konfiguratory, Quest3D oraz wsparcie techniczne dla twórców.
aplikacje szkoleniowe 3D (tzw. trenażery), symulatory i różnej maści aplikacje do wirtualnej Założyciel i opiekun Quest3d.pl.
rzeczywistości (m.in. projekcja na 4 ściany, obsługa rękawic i hełmów wirtualnych) Kontakt z autorem: arek.brzegowy@quest3d.pl

70 02/2010
Programowanie gier

Producent
A kto to jest?
Rola producenta w procesie budowania gry komputerowej bywa,
szczególnie dla osób postronnych, dość niejasna. Czytając poniższy
artykuł, przekonasz się, kim jest producent i jaka jest jego rola we
wspomnianym procesie.
ne’u o połowę. Na to wszystko trzeba mieć
Dowiesz się: Powinieneś wiedzieć: odpowiedź, im pełniejszą, tym lepiej.
• Jakie są codzienne obowiązki producenta; • Co to jest gra komputerowa. • Grafik – Graficy dostają od designera gene-
• Z jakimi problemami producent boryka się ralne wytyczne co do tego, co mają wyko-
na co dzień; nać, a reszta jest tak naprawdę przejawem
• Jak wiele ról pełni producent; ich własnej inwencji twórczej. Tutaj właśnie
• Jak producent postrzegany jest przez resztę wkracza producent, bo taka inwencja musi
zespołu. podlegać kontroli. Często trzeba kontrolo-
wać, czy inwencje dwóch grafików, pracu-
jących równolegle nad projektem są zbież-
rownika Projektu) w biznesie gier komputero- ne, bo nie chcemy skończyć z budowlami
wych. Kim zatem jest w szczególe? W swoim rodem z Art Deco w środku wioski elfów.
Poziom biznesie producent jest Project Managerem, pro- Należy też zwracać uwagę na sposób wyko-
trudności gramistą, jasnowidzem, grafikiem, designerem, nania poszczególnych elementów, bo kulka
testerem, głosem rozsądku, planistą, strażakiem, złożona z 10 tysięcy wielokątów nie poto-
facetem od pizzy, salesmanem, najlepszym kole- czy się zbyt płynnie na urządzeniu, które-
gą i bezlitosnym szefem. go wydajność można w skrócie ocenić jako

G
ry komputerowe, czyli przemysł fil- Przedstawmy pokrótce każdą z tych ról, co by dwa kalkulatory sklejone taśmą klejącą.
mowy XXI wieku. Coraz więcej z nas słów na wiatr nie rzucać. • Designer – producent, zwłaszcza przy ma-
gra w gry, coraz więcej z nas uczestni- łych projektach, pełni też rolę designera,
czy w ich tworzeniu. Gry przedostają się powo- • Project manager – zdawało by się, że głów- aby oszczędzić na kosztach, nigdy nie jest
li do środków masowego przekazu, otrzymują na rola producenta. Pilnowanie harmo- to dobry pomysł. Przy większych projek-
nagrody i oklaski za całokształt, doświadczenia nogramu, regulacja zasobów, rozmowa z tach zawsze deleguje się osobnego designe-
gracza oraz dziesiątki innych kategorii. Przemysł klientem, czytanie poczty i dokumentacji. ra, ale jako że jest to etat posiadający licen-
filmowy ma swoje gwiazdy, są nimi aktorzy, re- Pozycje takie jak rozmowa z klientem po- cję na inwencję twórczą, należy go kontro-
żyserowie, scenarzyści, okazjonalny operator. trafią urosnąć do rozmiarów, gdzie wyma- lować. Designer, jak każdy artysta, chce być
Wszyscy znają ich nazwiska i prace. gałyby osobnego etatu. unikalny i jedyny w swoim rodzaju. Dzięki
Tak jak i w filmach, przemysł gier kompute- • Programista – nie każdy producent ma przypływowi takiej weny jest w stanie wy-
rowych ma swoje gwiazdy. Tymi gwiazdami są wiedzę techniczną, w większości wypad- myślić takie elementy gry, o jakich nie bę-
designerzy, artyści, programiści – ludzie, któ- ków nawet nie powinien, bo zarządzanie dzie się śniło naszym dzieciom ani nasze-
rzy tworzą rzeczy widoczne, rzeczy, do których projektem to nie jest dobre miejsce dla do- mu budżetowi. Trzeba więc filtrować ta-
można się odnieść, tworzą elementy w pew- brego programisty. Wiedza programistycz- kie pomysły, aby na następnym spotkaniu
nym stopniu namacalne. Tu przechodzimy do na jednak się przydaje, po pierwsze, poma- projektowym nie zorientować się, że zespół
pozycji producenta, która jest zazwyczaj moc- ga producentowi zrozumieć, o czym pro- przez ostatnie 2 tygodnie pracował nad
no w cieniu. gramiści do niego mówią. Po drugie, po- czymś, co zupełnie nie nadaje się do naszej
Obiegowa opinia wśród zespołów projekto- zwala łatwiej ocenić, czy rzeczywiście na- gry.
wych jest taka, że producent tak naprawdę nic pisanie Hello World w OpenGL zajmie do- • Tester – mimo tego iż każdy projekt ma
nie robi. Producent, wbrew nazwie, sam ni- świadczonemu programiście trzy dni ro- swój zespół QA, świeże spojrzenie produ-
czego tak naprawdę nie produkuje, nie tworzy bocze. Po trzecie, daje możliwość dialogu centa, nie tylko na błędy w grze, ale także
grafiki, nie tworzy kodu, czasem przyjdzie po- z programistami w momentach impasu i na grę jako całość ma zbawienny wpływ na
przeszkadzać designerowi, ale zazwyczaj się go nieurodzaju intelektualnego. jakość końcowego produktu. Poszczególne
nie widzi. Siedzi przy arkuszu i tworzy jakieś ta- • Jasnowidz – drugi, pełny etat producen- zespoły są tak zajęte swoimi zadaniami, że
belki, więc czemu miałby być pretendentem do ta. Trzeba umieć przewidzieć wszystko, co nie są w stanie zauważyć faktu, iż niektóre
gwiazdy przemysłu gier? może się stać w najbliższej przyszłości, i za- elementy, nawet sąsiadujące, nie współgrają
Zastanówmy się więc: kim właściwie jest pro- cząć się do tego przygotowywać. Problemy ze sobą.
ducent? W dużym uogólnieniu, producent jest z oprogramowaniem, narzędziami, ciąża, • Planista i głos rozsądku – często zespół
odpowiednikiem Project Managera (czyli Kie- grypa, kreatywny klient, skrócenie deadli- chciałby coś dodać, odjąć czy zmienić, i za-

72 02/2010
Producent

daniem producenta jest ocena, czy dana Mimo tego, że pozornie obowiązków tych wy- programiści oraz inne zespoły wykonają, i jeśli
funkcjonalność wpłynie rzeczywiście do- daje się być dużo, wśród developerów panuje jego zespół nie wyrabia się w czasie, to musi on
datnio na jakość produktu i czy trzy-tygo- obiegowa opinia, że producent to taki człowiek, znaleźć kreatywne rozwiązania, skróty i sztucz-
dniowy poślizg związany z implementacją który nic tak naprawdę nie robi. Widzi się go z ki, aby jednak osiągnąć cel w zamierzonym cza-
tej funkcjonalności jest dopuszczalny. Nie rana na spotkaniu, pogada coś, a potem przy- sie. Często przypomina to żonglerkę płonącymi
mówiąc o tym, że na trzech tygodniach chodzi, tylko jeśli coś idzie nie tak. Podobnie jak kotami podczas jazdy na monocyklu, ale za to w
może się to nie skończyć. Czasem trzeba z administratorami sieci, praca producenta jest końcu mu płacą.
podjąć kilka niepopularnych decyzji, aby najbardziej widoczna, kiedy on sam nie ma co Reasumując, życie producenta to nieustan-
projekt jednak miał szanse sukcesu. robić. Jeśli wszystko jest dopięte na ostatni gu- na walka ze światem. Ekwilibrium przenosze-
• Strażak – jak sama nazwa wskazuje, stra- zik i współgra ze sobą jak trybiki w zegarku, to nia zasobami, tak aby jednak wszystko się uda-
żak gasi pożary. Pożarami nazywamy producent nie ma już czego poprawiać. Oczy- ło, mimo iż na papierze jasno widać, że czasu
wszystkie nagłe wypadki w projekcie, któ- wiście do czasu, kiedy wybuchnie następny po- jest o kilka tygodni za mało. To także, jak u każ-
re w pośredni lub bezpośredni sposób żar. Wtedy nasz bohater musi założyć swój ska- dego managera, kompromisy między byciem
wpływają na wykonalność projektu w za- fander, wziąć gaśnicę pod pachę i ratować swój efektywnym kierownikiem a byciem przyjacie-
mierzonym czasie, lub w ogóle. Dobrymi (a także nasz i wasz) projekt przed totalną ka- lem swoich ludzi i motywowanie ich w delikat-
przykładami jest odejście głównego deve- tastrofą. ny sposób. Bycie producentem to także posiada-
lopera, zmiana terminu oddania projektu Katastrof jest co nie miara, uwierzcie mi. Na nie wiedzy na każdy temat oraz części umiejęt-
lub odnalezienie krytycznej luki w zaku- każdym kroku w projekcie czyhają tylko, aby za- ności każdego z członków zespołu, tak aby móc
pionej technologii. W takich wypadkach atakować zespół i puścić projekt z dymem. Wte- wpasować się między nich, a także podejmować
producent zaczyna robić wszystko, co tyl- dy właśnie producent wkracza do akcji, aby wy- decyzje poparte konkretną wiedzą. Najważniej-
ko możliwe, aby załagodzić następstwa ta- konać swoją niewdzięczną akcję ratunkową, o szą jednak częścią jest posiadanie wizji projek-
kich wydarzeń. Ekspresowa rekrutacja, której mało kto tak naprawdę się dowie. O pro- tu i motywacji do jego ukończenia. Pracowni-
długie negocjacje z klientem lub telefony co blemach nie mówi się w zespole, problemy dzia- cy często bywają zagubieni, wiele rzeczy w pro-
godzinę do dostawcy technologii, aby do- łają bardzo demotywująco. Programiści, graficy jekcie bywa dla nich nie jasnych, i w takich wła-
wiedzieć się, czy błąd już został naprawio- i cała reszta ferajny nie musi wiedzieć o tym, że śnie momentach oczekują od producenta ja-
ny. Wszystko to zazwyczaj poza zasięgiem klient miał kolejny genialny pomysł i chciał z na- snej wizji i odpowiedzi w 10 sekund. Taką od-
wzroku całego zespołu. szej gry akcji zrobić puzzle. Takie informacje wy- powiedź zawsze trzeba mieć, i mieć ją na każdy
• Facet od pizzy – najłatwiejszy z obowiąz- wołują nieprzyjemne pomruki dezaprobaty na możliwy temat.
ków. Jeśli już cały zespół musi siedzieć w sali, a niektórym developerom podnoszą w bar- Mam nadzieję, że dzięki temu artykułowi
nocy, tak aby wyrobić się na określony ter- dzo widoczny sposób ciśnienie. Takie skoki ci- część z Was spojrzy inaczej na swojego produ-
min, to trzeba go nakarmić. Zamówić piz- śnienia i pomruki są wrogiem najlepszej przy- centa. Jeśli w Waszym projekcie pojawi się na-
ze, podać, opłacić i uśmiechać się ładnie. Im jaciółki producenta – produktywności, a bez gle dodatkowy kolega, przesunie się termin al-
mniej developerzy muszą nad tym myśleć, niej problemy zaczynają się mnożyć jak gremli- bo stanie coś równie ciekawego, co ułatwi wam
tym lepiej. ny karmione po północy. pracę, to wiedzcie, że nie jest to do końca przy-
• Sprzedawca – tutaj producent współpracu- Głównym problemem, wynikającym z braku padkowe zrządzenie losu. Jeśli na kolejnym
je z innymi sprzedawcami w czasie wstęp- produktywności, są oczywiście opóźnienia. Jed- spotkaniu producent będzie się opierał przed
nych negocjacji z klientem, aby ustalić listę nak zakres tych opóźnień często przybiera for- wprowadzeniem kolejnej funkcjonalności do
funkcjonalności, która jest wykonalna w mę wykładniczą. Z podstaw informatyki wie- gry, która jest akurat Waszym oczkiem w gło-
zamierzonym czasie i budżecie. Sprzedaw- my, iż cały system działa tak szybko jak najwol- wie, to wiedzcie, że nie robi tego z czystej zło-
cy często mają problemy z oceną możliwo- niejsza jego część. Opóźnienie jednego zespo- śliwości, ale ma plan, w który nie da się wpi-
ści wykonania projektu, co najczęściej koń- łu często oznacza opóźnienie innych zespołów, sać wszystkiego. Mimo że pozornie czasu jesz-
czy się ujemnymi budżetami oraz setkami przestoje i puste przebiegi. Dla przykładu, jeśli cze zostało całkiem dużo, to często nie bierzecie
nadgodzin w projekcie, dlatego też należy zespół grafików nie dostarczy na czas potrzeb- lub nie zauważacie pewnych czynników ryzyka,
przypilnować tego, aby sprzedać klientowi nych elementów, programiści nie będą w stanie które stoją na drodze projektu. Producent je wi-
coś, co rzeczywiście jest wykonalne przez ich poprawnie zaimplementować, a zespół testo- dzi, w końcu jest także jasnowidzem...
nasz zespół. Koniec końców, jeśli coś nie wy nie będzie w stanie zweryfikować poprawno-
wyjdzie, to oczywiście jest to wina produ- ści tej implementacji. Cały moduł, a wraz z nim
centa. Naturalnie. cała gra zaczyna się obsuwać, a zespół generuje
• Najlepszy kolega – to właśnie producent. puste godziny, na których cierpi budżet gry. Jeśli ŁUKASZ SZCZEPAŃSKI
Zawsze wysłucha swoich ludzi, poradzi im, taki okres się przeciągnie, to możemy znaleźć się Pracuje na stanowisku Producenta w firmie Game-
co mogą robić w krytycznych sytuacjach, i w sytuacji, gdzie nie będziemy mieć już budżetu lion, wchodzącej w skład Grupy BLStream. Łukasz
da urlop przy nagłych wypadkach. Zrozu- na ukończenie gry jako takiej. specjalizuje się w technologiach związanych z pro-
mie, jeśli ktoś przyjdzie później po bardzo Zadaniem producenta jest więc pilnowa- dukcją oprogramowania na platformy mobilne,
wesołej nocy. nie wydajności i monitorowanie jakości całego ze szczególnym naciskiem na tworzenie gier. Gru-
• Bezlitosny szef – to także producent. Taki projektu. Producent jest swego rodzaju firewal- pa BLStream powstała, by efektywniej wykorzy-
tryb włącza się zazwyczaj pod koniec pro- l’em między zespołem projektowym a wszyst- stywać potencjał dwóch szybko rozwijających się
jektu. Godziny pracy są stałe i często bar- kimi czynnikami zewnętrznymi. Dba o to, aby producentów oprogramowania – BLStream i Ga-
barzyńsko wczesne. Urlopy zostały prze- jedynym zmartwieniem programistów był ro- melion. Firmy wchodzące w skład grupy specja-
łożone na następny rok, a każde spóźnie- dzaj algorytmu sortowania,jaki mają zastoso- lizują się w wytwarzaniu oprogramowania dla
nie kończy się wizytą na dywaniku i poga- wać, a wszystkie problemy takie jak zmiany za- klientów korporacyjnych, w rozwiązaniach mobil-
danką o tym, jak ważny jest projekt i jak za- kresu projektu, zmiany w terminach, zmiany w nych oraz produkcji i testowaniu gier.
wiedliśmy wszystkich swoim nieodpowie- zasobach, etc. były ponad ich głowami. Z drugiej Kontakt z autorem: lukasz.szczepanski@game-
dzialnym zachowaniem. strony, producent jest odpowiedzialny za to, co lion.com

www.sdjournal.org 73
Efektywność pracy

Wspinaczka
do profesjonalizmu
Modelowa ścieżka rozwoju kompetencji – podejście
pragmatyczne
Model kompetencji Braci Dreyfus, który odnosi się nie tylko do umiejętności
technicznych, ale również do ogólnej aktywności każdego z nas. Model
pozwoli Ci uświadomić sobie swój aktualny poziom kompetencji w dowolnej
dziedzinie oraz zaplanować dalszą drogę ich rozwoju. Spojrzenie przez
pryzmat modelu na kolegów z zespołu pomoże Ci lepiej komunikować się.
moświadomości, a co za tym idzie na racjo-
Dowiesz się: Powinieneś wiedzieć: nalne działanie.
• Jak zmieniasz się wraz z rozwojem kompe- • „Co lubię w życiu robić?” Model jako taki z założenia odnosi się do
tencji; niemal każdej aktywności człowieka, któ-
• Jak zdiagnozować na jakim poziomie jesteś ra podlega rozwojowi. Jego główna koncep-
Ty i Twoi współpracownicy; cja opiera się na istnieniu 5 poziomów, wg
• Na co zwracać uwagę w komunikacji ze ko- których zmienia się nasza percepcja danego
legami z zespołu; problemu oraz sposób, w jaki budujemy jego
• Jak racjonalnie dobrać strategię swojego mentalną reprezentację.
rozwoju
1. Novice
Spotykasz się z daną sytuacją po raz pierw-
chy lub pilotowania samolotu. Mam nadzie- szy. Jesteś zorientowany na konkretne zada-
ję, że z uwagi na jego bliskość z naszą branżą nia, kroki i potrzebujesz kogoś, kto je Tobie
Poziom okaże się ciekawy i zachęcający do spojrzenia wskaże. Jeszcze nie masz pełnej świadomości
trudności we własne wnętrze. Mam również nadzieję, szerszego celu. Nie masz żadnej intuicji, za-
że zainspiruje on wszystkich czytelników do tem potrzebujesz jasnych, bezkontekstowych
refleksji nad własną drogą do osiągnięcia pro- reguł postępowania, aby nie pogubić się w no-
fesjonalizmu. wym środowisku.

C
zy potrafisz przypomnieć sobie Profesja i Rzemiosło (Craftsmanship) są
naukę jazdy na rowerze? To sku- wartościami nabierającymi coraz większego 2. Advanced begginer
pienie, aby przejechać 10 metrów znaczenia w branży programistycznej – póki Radzisz sobie coraz lepiej, zaczynasz for-
prosto? Albo pierwszą jazdę samochodem co, niestety, szczególnie zachodniej. Zwykle mułować proste zasady. Jednak są to zasady
i skupienie na sprzęgle? I jego zgrzyt? A jednak postrzega się je jako metodyki, podej- ograniczone do wąskiego kontekstu, ponie-
czy teraz, po latach, potrafisz powiedzieć, ścia i warsztat. W niniejszym artykule przyj- waż nie masz jeszcze zdolności spojrzenia na
co należy zrobić, aby jechać bez trzyma- rzymy się tym wartościom pod kątem świa- swą pracę z boku. Póki co, masz problem z
nia kierownicy, rozmawiając jednocześnie domej i racjonalnej drogi rozwoju w kierun- radzeniem sobie z pojawiającymi się trud-
przez telefon i podziwiając inne uczest- ku profesjonalizmu. nościami, dlatego potrzebujesz kogoś, kto
niczki ruchu (mam tu na myśli oczywiście będzie podpowiadał Ci rozwiązania – naj-
jazdę na rowerze)? Model zdobywania kompetencji lepiej szybko!
Tę właśnie drogę od nowicjusza z fioleto- Każdy, kto nie jest totalnym cyborgiem, za- Co ważne, wciąż potrzebujesz kogoś, kto
wymi kolanami do pewnego siebie eksperta pewne ma świadomość, że kompetencje w powie Ci, co i jak powinieneś zrobić.
opisuje model rozwoju kompetencji opraco- danej dziedzinie oraz sam ich charakter nie
wany w latach '70 ubiegłego wieku przez bra- są statyczne. Podlegają zmianom w czasie Boję się iść dalej
ci Dreyfus. – zwykle w długiej perspektywie czasu, przez Dwa pierwsze poziomy kompetencji w
Nie jest to bynajmniej czysto teoretycz- co mogą być trudne do zaobserwowania. Mo- przedstawianym modelu charakteryzują
ny model akademicki. Model powstał pod- del Braci Dreyfus opisuje taką właśnie dro- się tym, że ktoś mówi nam CO – i najważ-
czas badań nad zastosowaniem sztucznej in- gę owych zmian, nazywając i charakteryzu- niejsze JAK musimy zrobić. Potrzebujemy
teligencji (i jej ograniczeniami) do gry w sza- jąc jej etapy. Pozwala to na zwiększenie sa- zadań, których jesteśmy jedynie wykonaw-

74 02/2010
Wspinaczka do profesjonalizmu

cą. Towarzyszy temu oczywiście przyjem- nych kontekstach. Ujrzałeś tak zwany big- tyczy zdobywania konkretnej, mniej lub bar-
ne uczucie zwolnienia z odpowiedzialno- ger picture i masz problem... Do tej pory by- dziej ogólnej kompetencji. Czyli w pewnych
ści – ja tylko wykonywałem rozkazy. Pamię- łeś kompetentny w swoim malutkim świe- nielicznych aspektach możemy być eksperta-
tajmy jednak, że dla niektórych z nas strach cie, jednak gdy zobaczyłeś, o co tak napraw- mi, a w innych np. nowicjuszami.
przed podjęciem odpowiedzialności za wła- dę chodzi i zrozumiałeś, że jest to jednak Warto zwrócić uwagę na kilka kwestii
sne poczynania może być blokadą przed dal- bardziej skomplikowane niż się wydawało. związanych z naszą postawą w zależności od
szym rozwojem. Wiem, że nic nie wiem – chichocze za Twymi poziomu kompetencji w danej dziedzinie.
plecami sam wielki Sokrates. Jesteś po pro-
3. Competent stu skazany na dalsze samodoskonalenie w Najpierw ogólnie
Przestałeś borykać się ze szczegółami tech- tej dziedzinie. Niektórzy z nas, poznając nowe zagadnie-
nicznymi problemu, wszystko to, co na po- Frustrują Cię zbytnie uproszczenia, które nia z ogólnie znanego już zakresu, prefe-
czątku zgrzytało, teraz działa dosyć gładko. widzisz dookoła. Stałeś się zapewne dener- rują rozpoczęcie od trzeciego poziomu –
Pozbycie się tych problemów spowodowa- wującym typkiem w zespole, który wciąż za- Competent. Dzieje się tak, gdy nasze nawy-
ło, że jesteś już nastawiony na cel i sam decy- daje pytania. Pytania, których nikt nie lubi ki kognitywne kierują nami, aby najpierw
dujesz, jak do niego dotrzeć. Dzięki świado- – zaczynające się od A dlaczego...?. poznać ogólnie problem i zrozumieć, o co
mości celu sam planujesz kroki i zadania pro- chodzi. Dopiero później będziemy szukać
wadzące Cię do niego. Robisz to, ponieważ je- 5. Expert przykładów, tutoriali itp. Najpierw musi-
steś już w stanie tworzyć modele koncepcyj- Wiedziony wrodzoną ciekawością zgroma- my poznać całość oraz metodyki obowiązu-
ne problemu, co z kolei pozwala na myśle- dziłeś na poprzednim etapie niemal całą wie- jące w danej dziedzinie, aby zdecydować w
nie bardziej długofalowe – planowanie. Two- dzę z danej dziedziny. Cały czas poszerzasz ją ogóle, czy to nas interesuje i czy chcemy za-
je rozwiązania nie są może jeszcze najlepszy- - szukasz jednak w innych miejscach niż po- głębiać się dalej.
mi z możliwych, ale działają. Wypracowujesz przednio. Szukasz analogii i skojarzeń z zu-
swoje własne zasady, ale starasz się jednocze- pełnie odrębnymi domenami. Być może in- Błędna samoocena
śnie je weryfikować. spiruje Cię biologia, mechanika, architektura Będąc na niższych poziomach, mamy tenden-
Ponieważ przewidujesz, że mogą istnieć budowli? Syntezujesz pojęcia na wyższym po- cję do zawyżania swej samooceny. Nawiasem
lepsze rozwiązania, że ktoś opracował dobre ziomie abstrakcji. mówiąc, niektórzy mają chyba do tego wro-
praktyki i sprawdzone rozwiązania, to szu- Zrozumiałeś, że wszystko zależy od kon- dzone skłonności.
kasz informacji u Ekspertów. Prawdopodob- tekstu, dlatego posługujesz się głównie me- Natomiast będąc na wyższych pozio-
nie nie dowiesz się od nich niczego, ale o tym taforami, mówiąc o swej dziedzinie. Paradok- mach, przychodzi pokora i zaniżamy swe
za chwilę... salnie to właśnie metafory są najbardziej traf- kompetencje. Najbardziej niebezpieczni dla
ne, ponieważ można je interpretować na róż- siebie samych, tudzież otoczenia jesteśmy na
Już się zmęczyłem ne sposoby w zależności od kontekstu. Nie- poziomie Advanced Begginer. Wydaje nam
Wszyscy mamy tendencję do niewysilania się ustannie poszukujesz lepszych metod. się, że osiągnęliśmy wówczas mistrzostwo,
ponadto, co konieczne. Jest to jak gdyby we- Co gorsza – zapytany o argumentację ponieważ nie mamy jeszcze wyrobionego
wnętrzny mechanizm mózgu chroniący go swych decyzji, często nie potrafisz jej podać, szerszego poglądu. Przypomnijcie sobie, kie-
przed śmiertlenym przegrzaniem. Dlatego ponieważ myślisz intuicyjnie. Rozwiązania dy zaliczyliście najwięcej upadków z rower-
chętnie zatrzymujemy się na poziomie Com- same pojawiają się w głowie, po prostu wiesz. ka; a z drugiej strony, kiedy ostatnio do te-
petent. Radzimy sobie już całkiem dobrze i je- go doszło?
steśmy generalnie zadowoleni z rezultatów. Warto zwrócić uwagę
Inni są również z nich zadowoleni. Czego Ogólnie rzecz ujmując, model zakłada zmia- Test na eksperta
chcieć więcej? Czy nie zrobiłem już wszyst- nę nastawienia. Z początkowej orientacji na Dave Thomas – autor klasycznej już książ-
kiego, co można, i nie mogę wreszcie oddać procedury i konieczność na późniejsze na- ki Pragmatyczny programista przedstawia w
się czynnościom wegetatywnym typu oglą- stawienie w kierunku poszerzenia wachla- swych prezentacjach oparty o model Mo-
danie TV? rza możliwości. Czyli z tego, co musi być na del Braci Dreyfus humorystyczny, ale da-
to, co może być. jący do myślenia test na Eksperta. Jeżeli
4. Proficient Należy jasno podkreślić, że model nie opi- weźmiesz dwóch ekspertów mających od-
Wejście na ten poziom i osiągnięcie pozio- suje naszego rozwoju jako całości. Model do- mienne zdanie na dany temat, to zaczną
mu biegłości w danej dziedzinie wymaga
wysiłku intelektualnego. Przede wszystkim
musisz chcieć. O ile poprzednie poziomy
Poziomy kompetencji wg Modelu Braci Dreyfus
osiągamy liniowo – po prostu powtarzając • Novice – robisz coś po raz pierwszy, nie do końca wiesz, o co chodzi. Jesteś nastawiony
pewne czynności wielokrotnie – to w przy- na szybką realizację prostego zadania, czegoś, co działa;
padku Proficient samo powtarzanie nie wy- • Advanced Begginer – powoli zaczynasz rozumieć, o co mniej więcej chodzi. Twój mózg
starczy. Mamy tutaj do czynienia z ogrom- zaczyna zauważać powtarzalne wzorce i nie da się tego w żaden sposób wyłączyć. Jed-
nak w dalszym ciągu potrzebujesz kogoś, kto powie Ci, co trzeba zrobić;
nym skokiem jakościowym. Skokiem, który • Competent – całkiem dobrze orientujesz się w wyuczonej domenie, a samodzielne my-
polega na całkowitym zaangażowaniu w da- ślenie pozwala Ci na planowanie działań na przyszłość. Dzięki temu możesz przejść z wy-
ny temat i zgłębianiu jego natury poprzez konywania zleconych zadań na samodzielną realizację celów;
szersze poszukiwania. Poszukiwania te po- • Proficient – odkryłeś, że jest jeszcze coś więcej i zrozumiałeś, że tak naprawdę nic nie
legają na kojarzeniu analogii do innych za- wiesz. Zaczynasz syntezować wiedzę z innych dziedzin, aby rozumieć więcej i lepiej. Za-
dajesz trudne pytania;
gadnień, pogłębianiu zasobów tychże sko-
• Expert – w większości podejmujesz decyzje intuicyjnie, po prostu wiesz, co trzeba zrobić.
jarzeń. Posługujesz się metaforami. Nieustannie szukasz lepszych metod, czerpiąc jednak inspi-
Na tym poziomie nie jesteś już nastawio- rację z innych dziedzin.
ny na sam cel, ale na zrozumienie celu w róż-

www.sdjournal.org 75
Efektywność pracy

się spierać. Właściwie to dyskutować, uży- Model w kontekście IT bujesz malutkich sukcesów, które zmotywu-
wając merytorycznych argumentów w ce- Zakładam, że skoro sięgnąłeś po ten artykuł, ją Cię do dalszego rozwoju. Chcesz po prostu
lu przekonania adwersarza. Z czasem po- to interesujesz się własnym rozwojem. Zakła- zrobić coś, co działa. Jesteś teraz zbyt obcią-
winni się nawzajem przekonać do swych ra- dam też, że skoro doszedłeś do tego rozdziału, żony, aby dodatkowo jeszcze pogłębiać wie-
cji – czyli niejako wymienić poglądami. Po to Model Braci Dreyfus wydaje Ci się w miarę dzę na temat specyfikacji – po prostu nie w
tym wciąż będą się spierać, aby nawzajem sensowny. Przyjrzyjmy mu się zatem pod ką- tym momencie. Jeżeli Twój przełożony tego
się przekonać do tego, o czym wcześniej by- tem strategii rozwoju kompetencji technicz- nie wie, to najprawdopodobniej w swoim fa-
li przekonani. nych w kontekście naszej branży. Zrobimy to chu jest na takim samym poziomie jak Ty w
zarówno z perspektywy osobistej, jak i zespo- swoim.
Intuicja – czy jest dozwolona? łu – jako systemu ludzkiego. Rozsądny manager nie powinien wrzucać
W modelu Braci Dreyfus istnieją dwa nie- Zacznijmy od oczywistych oczywistości: nowicjusza na głęboką wodę – a przynajm-
jawne atrybuty: potrzeba_reguł oraz opar- oprogramowanie piszą ludzie, nie platfor- niej nie każdego. Taki ktoś zacznie paniko-
cie_na_intuicji. Na pierwszych szczeblach my korporacyjne, języki, narzędzia, meto- wać, co jest zaraźliwe.
potrzebujmy jasnych reguł, które z cza- dyki czy frameworki (najlepiej webowe i
sem stają się mniej istotne, a wręcz zaczy- najlepiej z zaokrąglonymi rogami każdej, Pistolet
nają przeszkadzać. Ich miejsce zajmuje tak nawet z natury kanciastej formy). Owszem Okiełznałeś już nieco chaos techniczny wo-
zwana intuicja. Oczywiście nie mamy tu są to bardzo ważne elementy całości, ale nie kół siebie – jesteś Zaawansowanym Początku-
na myśli jakiejś magicznej formy objawie- wystarczające. Głównym elementem proce- jącym. W dalszym ciągu potrzebujesz zadań
nia prawdy. su produkcji czy zespołu w ujęciu systemo- zamiast celów, ale radzisz sobie z nimi cał-
Chodzi o naturalne procesy kognitywne wym są ludzie. kiem dobrze. Zbyt dobrze, nie masz jeszcze
zachodzące w mózgu każdego z nas. Mózg Zimna metodyka zorientowana na staty- pokory. Wystarczy nieco piachu na zakręcie,
optymalizuje wydatek energii, ucząc się wy- stycznie optymalne wykorzystanie zasobów a rowerek pojedzie w swoją stroną, podczas
bierania istotnych danych do przetwarzania. ludzkich (piękne sformułowanie, niepraw- gdy Ty przyciągany efemeryczną siłą grawita-
Z czasem pobudzenia neuronów sięgają co- daż?) będzie, owszem, działać. Przyjrzenie cji z mniejszą lub większa gracją spotkasz się
raz to niższych warstw kory nowej. W rezul- się każdemu człowiekowi jako jednostce i ele- z ziemią. Niestety w naszej branży efekt prze-
tacie ekspert wcale nie myśli szybciej czy w ja- mentowi większego systemu ludzkiego mo- cenienia swych kompetencji nie jest widocz-
kiś sposób lepiej. Myśli po prostu mniej, a co że zwiększyć produktywność tegoż systemu i ny natychmiastowo.
za tym idzie bardziej wydajnie. Po prostu sku- przede wszystkim zwiększyć jakość pracy (w Błędy wynikające z braku postrzegania
pia się na istotnych danych, różnica polega na sensie spędzania czasu) – a co za tym idzie, szerszego kontekstu problemu wychodzą na-
tym, że jego mózg dokładnie wie, które dane jakość życia. wet dopiero po miesiącach. Zły projekt, krót-
są istotne. kowzroczna architektura, bałagan w kodzie,
Normalni ludzie nazywają to zjawisko w I co ja robię tu brak testów – to boli, ale nie od razu.
skrócie: intuicja. Jesteś Nowicjuszem – zwykle jest to Twoja Kuszą Cię różnego rodzaju obietnice efek-
Czy w branży technicznej jest w ogó- pierwsza praca i wszystko wygląda zupełnie tywnych narzędzi, generujących gotowe roz-
le miejsce na coś takiego jak intuicja? Coś, inaczej niż na studiach. Aż palisz się, aby za- wiązania, bez zbędnych konstrukcji, które po-
czego nie da się ująć w ścisłe ramy, zmie- kodować w jakimś niskopoziomowym języku zwalają na uniknięcie przykrej czynności za-
rzyć i opisać, może wydawać się wręcz nie- Transformatę Cosinusową, ale zamiast tego stanowienia się nad konsekwencjami ich za-
pożądane. Oczywiście decyzji intuicyjnych zostajesz wrzucony w sam środek katastrofy stosowania.
nie można uzasadnić i nie można zweryfi- Titanica, który na jutro ma zostać wydobyty Jeżeli jest taka możliwość, to Zaawanso-
kować formalnie. Nie da się również opisać z dna i do tego ma lśnić na prezentacji przed wany Początkujący powinien rozwijać się pod
jej w formie powtarzalnej procedury w celu zarządem lub klientem. okiem doświadczonego mentora, aby jak naj-
wdrożenia przez innych. Wady podejścia in- Nie wiesz, od czego zacząć ani po czym po- szybciej opuścić ten poziom, zanim narobi bi-
tuicyjnego są bezdyskusyjne, ale musimy się znać, że już skończyłeś. gosu. Jeżeli natomiast nie masz takiej możli-
z nimi pogodzić, ponieważ (o ile model Bra- Znając Model Kompetencji Braci Dreyfus, wości, to najlepszą radą będzie uświadomie-
ci Dreyfus jej poprawny) jesteśmy na nie po wiesz co robić: domagaj się małych, krótkich, nie sobie beznadziejności swego aktualnego
prostu skazani. dobrze określonych zadań, ponieważ potrze- położenia, aby jak najszybciej wskoczyć na
następny poziom kompetencji.

Strategie dla managerów Rzetelny rzemieślnik


• Zlecając zadania Nowicjuszowi, pamiętaj, aby były małe i jasno sformułowane. Powin-
Odważyłeś się samemu podejmować decy-
ny też pozwalać mu na osiągnięcie szybkiego sukcesu, dzięki czemu zwiększa się mo- zje i brać za nie odpowiedzialność. Jesteś na-
tywacja; stawiony na cele i samodzielnie dobierasz
• Podchodź krytycznie do rozwiązań Zaawansowanego Początkującego. Nie ma on jeszcze sposób ich rozwiązania. Definiujesz własne
dostatecznego obrazu, aby uświadomić sobie słabe strony swoich pomysłów. Ważne jest standardy, jednocześnie szukając potwier-
dla niego, że w końcu działa;
dzenia poprawności u bardziej doświadczo-
• Przed Kompetentnym stawiaj cele i pozwól mu na samodzielną ich realizację. Zachęcaj go
również do poszerzania zakresu kompetencji; nych. Jesteś po prostu osobą, na której moż-
• Bądź cierpliwy dla Biegłego i uszanuj jego pęd do samodoskonalenia. Rozwój i ambitne na polegać.
problemy są dla niego teraz ważniejsze niż np. podwyżka; Oczekujesz problemów postawionych ja-
• Wybacz Ekspertowi jego różne dziwactwa. Jeżeli któryś raz z kolei miał rację, to warto mu ko cele oraz autonomii w ich osiąganiu.
zaufać i dać większą autonomię; Konkretne zadania wykopania dołka w da-
• Zachęcaj Ekspertów, aby przeszli do poziomu Guru. Tak, nie każdy będzie miał odpowied-
nie cechy osobowości, ale warto spróbować – to zawsze się opłaca w skali zespołu lub
nym miejscu o zadanych wymiarach są już
firmy. dla Ciebie deprymujące. Jeżeli przełożony
wciąż traktuje Cię jakbyś był Advanced Beggi-

76 02/2010
Wspinaczka do profesjonalizmu

ner, to musisz zakomunikować swe aspiracje. podwładnego, bo oto na Twoich oczach po- Częstym przykładem jest np. sugerowanie sil-
Komunikacja to podstawa, a brak komunika- woli rodzi się Ekspert, który po pewnym cza- nika bazodanowego jako kompleksowej plat-
cji to źródło większości problemów, więc nie sie wniesie ogromną wartość dodaną do fir- formy developmentu całego systemu – pomi-
trać czasu ani swego potencjału. my. jając problemy oraz ignorując rozwiązania le-
Masz własny styl, ale niestety tylko jeden i piej nadające się do niektórych zastosowań.
do tego na każdą okazję. Szukaj najlepszych Po prostu Ekspert Tak więc strzeżmy się ekspertów o ograni-
praktyk i sprawdzonych wzorców, aby nie Swoje decyzje podejmujesz intuicyjnie czonym zasobie skojarzeń oraz tych nieprak-
utknąć w grząskim gruncie własnych wydaje – gdzieś w pokładach nieświadomości. Jest tykujących – samozwańczych. Łatwo też wy-
mi się, że wiem najlepiej. to jedyny sposób Twojego mózgu na radze- obrazić sobie, ile może być warta jedna słusz-
Zastanów się dobrze, czy to, co robisz, jest nie sobie z ogromem informacji zdobytych na strategiczna decyzja prawdziwego Eks-
twoją pasją. Jeżeli tak, to będziesz miał moty- podczas wieloletniego doświadczenia. Zro- perta.
wację i znajdziesz czas, aby się doskonalić i zumiałeś, że wszystko zależy od kontekstu,
przejść na kolejny poziom. Jeżeli jednak nie, dlatego chętnie posługujesz się metafora- Guru
to nie ma potrzeby, aby zbytnio się frustro- mi, które wg Ciebie najbardziej trafnie od- Co prawda nie opisany w standardowym mo-
wać, nie wszyscy przecież muszą zajmować dają sytuację. Możesz mieć problemy z po- delu braci Dreyfus, ale niektórzy wyróżniają
się zawodowo tym, czym się pasjonują. daniem merytorycznych powodów, dla któ- tę specjalną klasę Ekspertów. Guru to taki eks-
rych powinno postępować się zgodnie z pert, który ma dobry interfejs ludzki (sprzęg,
Pan „dlaczego” Twoimi pomysłami. jak mawiano w erze krzemu łupanego). Dzię-
Na poprzednim poziomie byłeś dobry w swo- Z tego powodu koledzy będący na pierw- ki wysokiej empatii potrafi dostosować swój
im fachu – dosyć dobrze udało Ci się go zgłę- szych szczeblach kompetencji w Twojej do- przekaz do aktualnego poziomu odbiorcy. Po-
bić i wypracować dobre metody. Teraz za- menie mogą mieć problem ze zrozumieniem, trafi również operować sugestywnymi przy-
miast w głąb, szukasz wszerz. Kwestionu- o czym do nich mówisz. Zwróć uwagę, czy kładami oraz prowokować do zadawania wła-
jesz najlepsze praktyki, gdy widzisz, że Cię gdy wydajesz im polecenie, nie kiwają jedynie ściwych pytań. Dzięki temu każdy, kto uda
ograniczają. głowami – poproś o opisanie zadań w mailu. się do Guru po radę, wraca z jakąś odpowie-
Rozglądaj się w poszukiwaniu szerszych Bądź miły i uważaj, aby nie sprawiać, że Twoi dzią – a przynajmniej z natchnieniem. Ema-
problemów i ucz się dobierać do nich rozwią- współpracownicy będą kończyć rozmowę ze nuje on aurą, dzięki której wszyscy wokół roz-
zanie. Szukaj skojarzeń i paraleli do innych łzami w oczach – nic w ten sposób nie osią- wijają się szybciej i w dobrym kierunku.
dziedzin. To poszerzy Twój wachlarz możli- gniecie jako zespół. Jeżeli jesteś ekspertem, to warto popraco-
wości i nauczy Cię zaliczać problemy do pew- Jeżeli jesteś przełożonym eksperta, to masz wać nad przepoczwarzeniem się do formy
nych klas problemów. Okaże się, że nie każda pewien problem – musisz postępować z nim Guru, ponieważ tylko wówczas zyskasz sza-
aplikacja musi być być np. webowa, dany fra- niczym ze świętą krową. Ekspert bardzo do- cunek i staniesz się bohaterem opowieści snu-
mework nie jest uniwersalnym młotkiem do brze zdaje sobie sprawę ze swej wartości na tym wnukom przez twych uczniów.
wszystkiego, a pewien styl architektoniczny rynku, bywa zarozumiały, więc nie będzie
nie nadaje się do każdego projektu. Wszystko się zbyt długo zastanawiał nad zmianą barw Liczy się doświadczenie
zależy od klasy problemu. Jeżeli jesteś progra- klubowych. Przedstawiony model kompetencji zakłada
mistą, to uświadomisz sobie, że języki progra- Przede wszystkim musisz zapewnić mu liniowy rozwój do trzeciego poziomu – od
mowania, o których palmę zwycięstwa spie- tak zwany bigger picture. Zdawkowe po prostu Novice, poprzez Advanced Begginer po Com-
rałeś się na studiach, należą tak naprawdę do zrób to jest dla Eksperta obraźliwe. Nie zmu- petent. Liniowy, czyli odbywający się propor-
pewnej wspólnej klasy – różnią się jedynie lu- szaj go do podążania wg standardowych pro- cjonalnie do czasu powtarzania (trenowania).
krem składniowym i detalami technicznymi. cedur – to go spowalnia i irytuje. Nie zawra- Natomiast dalszy rozwój – poprzez Proficient
Tu chodzi o coś innego, większego. caj mu głowy formalnościami typu raporty z do Expert – nie jest już liniowy, ponieważ wy-
Możesz mieć problem z irytacją wynikają- wykonanej pracy. Ekspert wie, że to, co robi, maga skoku jakościowego naszej aktywności.
cy z otaczających Cię uproszczeń i błędnych, robi dobrze, więc okaż mu zaufanie i pozwól Skoku polegającego na poszerzeniu zakre-
niepodważalnych założeń. Zaczynasz zada- na autonomię. su zainteresowań w celu rozwinięcia ogólne-
wać pytania podważające firmowe dogmaty. Jeszcze jedna dobra rada, której udziela go obrazu.
Dlaczego używamy tego podejścia czy roz- Dave Thomas na temat ekspertów: Nie zlecaj Dlatego warto zastanowić się nad naszym
wiązania do tego problemu? Dlaczego robi- mu opracowania architektury nowego syste- x lat doświadczenia w branży. Czy jest to x lat
my to akurat tak? Uważaj... jesteś pierwszy mu. Znudzony Ekspert wykreuje monstrum różnych doświadczeń, czy tak naprawdę je-
do zwolnienia. integrujące różne rozwiązania i technologie den rok, powtórzony x razy?
Jeżeli jesteś przełożonym kogoś, kto za- tyko po to, aby się zabawić i sprawdzić, jak to
czyna być biegły, to wykorzystaj jego poten- wszystko będzie ze sobą działać.
cjał. Przydziel mu ambitną misję wymaga- Należy również uważać na tak zwanych eks- SŁAWOMIR SOBÓTKA
jącą przekrojowego wysiłku i raczej syntezy pertów. Czyli ludzi na poziomie Competent w Konsultant w firmie BNS IT. Interesuje się szeroko
niż analizy. pewnej materii, którzy nie mają jeszcze szer- pojętą inżynierią oprogramowania: architekturą
Ale przede wszystkim wybaczaj jego nad- szej perspektywy. Nie przeszkadza im to jed- systemów JEE, Domain Driven Design, wzorcami,
mierne zastanawianie się na błahymi (z Two- nak w lansowaniu swoich rozwiązań (jedy- procesem wytwórczym. Hobbystycznie interesuje
jej perspektywy) sprawami. Szanuj biegłego nych, jakie znają) w każdej możliwej sytuacji. się psychologią i kognitywistyką. Oprócz dosko-
nalenia rzemiosła stara się odnaleźć w progra-
mowaniu również pierwiastek sztuki.
W Sieci Autor bloga poświęconego całościowemu ujęciu
inżynierii oprogramowania: http://art-of-softwa-
• strona http://www.infoq.com/presentations/Developing-Expertise-Dave-Thomas;
• strona http://www.infoq.com/articles/better-best-practices. re.blogspot.com
Kontakt z autorem: ssobot@gmail.com

www.sdjournal.org 77
Roczna prenumerata

tylko
256,-
Software Developer’s Journal (poprzednio Software 2.0)
jest miesięcznikiem głównie dla programistów, którzy li-
czą, że dostarczymy im gotowe rozwiązania, oszczędza-
jąc im czasu i pracy. Jesteśmy czytani przez tych, któ- UWAGA!
rzy chcą być na bieżąco informowani o najnowszych osią-
gnięciach w dziedzinie IT i nie chcą, żeby jakiekolwiek
istotne wydarzenia umknęły ich uwadze. Aby zadowolić Zmiana danych
kontaktowych
naszych czytelników, prezentujemy zarówno najnowsze
rozwiązania, jaki starsze, sprawdzone technologie.

Obsługa prenumeraty
Software Press Sp. z o.o. Spółka Komandytowa
1. Telefon
(022) 427 37 59
2. Fax
(022) 244 24 59
3. Online
pren@software.com.pl
4. Adres
Software Press Sp. z o.o. Spółka Komandytowa
ul. Bokserska 1
02-682 Warszawa
Prenumerujesz
– zyskujesz
l oszczędność
pieniędzy
l szybka dostawa
l prezenty
l bezpieczna płatność
on–line

Zadzwoń
lub
zamów
mailowo!

Ilość Od
Ilość zama- numeru
Tytuł nume-
rów
wianych pisma
prenu- lub mie-
Cena

merat siąca
Software Developer’s
Journal (1 płyta DVD) 12 256
– dawniej Software 2.0 PLN
KLUB PRO
Oferta skierowana dla firm
Jeżeli Twoja firma jest prenumeratorem Software Developer’s Journal za comiesięczną
dopłatą 50 PLN +VAT możesz dodatkowo otrzymać reklamę.
Wystarczy tylko, aby profil Twojej firmy pokrywał się z naszym magazynem.
Wyślij do nas: logo firmy, dane kontaktowe i informację o firmie
Reklama przez 12 kolejnych numerów tylko za 600 PLN +VAT.
Jeżeli nie posiadasz jeszcze prenumeraty możesz ją zamówić w atrakcyjnej cenie.
Dla nowych prenumeratorów specjalna oferta – 690 PLN.

Skontaktuj się z nami:


tel. +48 22 877 20 80
fax: +48 22 877 20 70
software@europress.pl

Opera Software Architektury systemów IT


Opera Software’s vision is to deliver the best In- Twórca frameworków JUVE i serwera aplikacji
ternet experience on any device. We are offering AVAX oferuje usługi, doradztwo, rozwiązania do
browser for PC/desktops and embedded pro- tworzenia nowoczesnych, dużych systemów i roz-
ducts that operates across devices, platforms wiązań informatycznych/internetowych, integrujące
and operating systems. Our browser can deliver architektury ery post-J2EE/.NET, wykorzystujące
a faster, more stable and flexible Internet expe- MDD/MDA dla dziedzin – bankowość, telekomuni-
rience than its competitors. kacja, handel, e-commerce, ERP/Workflow/CRM,
rozwiązania internetowe, portalowe.
http://www.opera.com www.mpsystem.com mpsystem@mpsystem.com

Kei.pl Future Processing


Kei.pl działa na rynku usług hostingowych od 2000 Future Processing to dynamiczna firma technolo-
roku. Do naszych zadowolonych Klientów z du- giczna działająca na globalnym rynku oprogramo-
mą możemy zaliczyć wiele przedsiębiorstw sekto- wania. Jesteśmy zespołem wysokiej klasy specja-
ra MSP, instytucji oraz osób prywatnych. W ofer- listów posiadających wiedzę i doświadczenie nie-
cie Kei.pl znajdują się pakiety hostingowe, a także zbędne do realizacji ambitnych projektów informa-
usługi dla wymagających Użytkowników – platfor- tycznych. Jeśli programowanie to Twoja pasja do-
my e-Biznes oraz serwery fizyczne. łącz do nas! (możliwość pracy zdalnej).

http://www.kei.pl http://www.future-processing.pl

Playsoft WSISiZ w Warszawie


Playsoft jako lider portowania aplikacji na plat- INFORMATYKA ZARZĄDZANIE
formy mobilne wciąż powiększa bazę swo- studia stopnia I i II (stacjonarne i niestacjonar-
ich klientów: EA Mobile, Sega, THQ, Kona- ne) specjalności: inżynierskie, magisterskie
mi. W ramach rozszerzania swojej działalno- i licencjackie. Szczegółowe plany studiów, opi-
ści, poszukujemy doświadczonego programi- sy poszczególnych specjalności – zapraszamy
sty, który byłby odpowiedzialny za tworzenie na stronę uczelni.
aplikacji na platformy Iphone, Windows Mobi-
le, Android.
http://www.playsoft.fr http://www.wit.edu.pl
KLUB PRO

INFOTEX SP.J TTS Company Sp. z o.o.


Śmietanowski i Wsp. Sprzedaż i dystrybucja oprogramowania komputero-
Dystrybutor XP Unlimited – Serwer Terminali dla wego. Import programów na zamówienie. Ponad 200
Windows XP i VISTA. Program umożliwia łącze- producentów w standardowej ofercie. Chcesz kupić
nie się z dowolnego klienta Windows, Linux z wy- oprogramowanie i nie możesz znaleźć polskiego do-
korzystaniem protokołu RDP. Cena wersji Classic stawcy? Skontaktuj się z nami – sprowadzimy nawet
dla 5 użytkowników - 165€, dla nieograniczonej
liczby - 235€. Ponadto oferujemy opiekę serwiso- pojedyncze licencje.
wą i aplikacje internetowe na zamówienie.

http://www.infotex.com.pl http://www.OprogramowanieKomputerowe.pl

IT SOLUTIONS Softline rozwiązania mobilne


Wdrożenia i szkolenia z zakresu: Wiodący producent systemów mobilnych, do-
• SQL Server stawca aplikacji użytkowych dla biznesu (Sym-
• SharePoint Services bian OS, Windows Mobile, J2ME ) zaprasza do
IT SOLUTIONS • MS Project / Server
• Tworzenie aplikacji w technologii .NET
współpracy. Zostań naszym partnerem. Dołącz
do zespołu.

http://www.itsolutions.biz.pl
marcin.pytlik@itsolutions.biz.pl http://www.softline.com.pl

Proximetry Poland Sp. z o.o. Systemy bankowe, ISOF


Proximetry Poland Sp. z o.o. jest polskim od- HEUTHES istnieje na rynku od 1989 r. Obok
działem amerykańskiej firmy Proximetry Inc. – systemów informatycznych dla banków, ofe-
dostawcy systemów zarządzania sieciami bez- ruje nowoczesne oprogramowanie do obsługi
przewodowymi opartymi na technologiach WiFi
i WiMAX. Naszą misją jest dostarczenie klien- firm. System ISOF jest udostępniany klientom
tom rozwiązań poprawiających jakość usług w trybie SaaS lub licencji. Pracuje na platfor-
(QoS) dostarczanych drogą radiową. Dołącz do mie Linux i zawiera m.in. takie moduły jak
najlepszych i zostań członkiem naszej ekipy! CRM, DMS, Magazyn, Sprzedaż, Logistyka
oraz Rachunkowość.
http://www.proximetry.com http://www.isof.pl
Felieton

GeeCON 2010

M
iło nam poinformować, iż Software Developer's Journal przed właściwą konferencją, w ramach GeeCON University Day,
został patronem medialnym drugiej edycji międzynaro- we współpracy z firmą Sun Microsystems, udało się zorganizo-
dowej konferencji GeeCON, która odbędzie w dniach 13- wać serię dedykowanych szkoleń. Nie zabraknie ich również w
14 maja 2010 r. w Poznaniu. tym roku (12 maja).
GeeCON to konferencja poświęcona technologiom, u podstaw Kolejnym miastem, do którego zapraszają nas organizatorzy,
których znajduje się język Java wraz z platformą, jaką jest Wirtual- jest Poznań – miasto tętniące życiem, miejsce, gdzie tysiąclet-
na Maszyna Java. Organizatorami konferencji są Poznańska i Pol- nia historia spotyka się z nowoczesnością. Tu co roku organizo-
ska Grupa Użytkowników Języka Java oraz stowarzyszenie Gru- wanych jest wiele imprez kulturalnych i targowych, które od-
pa Informatyczno-Kulturalna. Organizatorzy chcą promować roz- wiedzają goście z całego świata. Poznań oferuje przyjazną at-
wiązania zwiększające produktywność programistów takie jak ję- mosferę dla biznesu, ale również przestrzenie, w których ro-
zyki dynamicznie typowane (m.in. Groovy, Ruby) czy nowocze- dzą się innowacyjne pomysły. Wystarczy wspomnieć tylko o
sne szkielety aplikacyjne (m.in. Grails, Apache Wicket). W tym roku obecności ośrodków badawczo-rozwojowych wielkich kon-
chcą położyć nacisk również na technologie mobilne (wśród nich cernów takich jak Microsoft, Carlsberg, Dalkia, GlaxoSmithKli-
Android oraz JME) i rozwiązania do tworzenia Rich Internet Appli- ne czy Roche.
cation (Flex i JavaFX). GeeCON w Poznaniu to nie tylko dwa dni konferencji i możli-
Poprzednia edycja konferencji GeeCON odbyła się w ma- wość uczestnictwa w szkoleniach, to również spotkania towarzy-
ju 2009 w krakowskim Multikinie. Odwiedziło ją wielu specjali- szące, podczas których uczestnicy mają okazję do nawiązywania
stów z kraju i świata, m.in. Austrii, Czech, Niemiec, Wielkiej Bryta- licznych kontaktów. To wyjątkowa okazja, aby porozmawiać ze
nii, Francji, Stanów Zjednoczonych. Wśród prelegentów znaleź- światowej klasy specjalistami, których nie zabraknie podczas te-
li się m.in.: Adam Bien, Alef Arendsen, Antonio Goncalves, Bru- gorocznej edycji. To również szansa podzielania się swoją wiedzą
no Bossola, Corneliu Creanga, Giorgio Natili, Jacek Laskowski, lub prezentacji własnych rozwiązań – do grona prelegentów mo-
Luc Duponcheel, Miško Hevery, Paweł Wrzeszcz, Piotr Walczy- że bowiem dołączyć każdy, kto zgłosi temat prezentacji w języku
szyn, Simon Ritter, Stephan Janssen, Szczepan Faber, Thomas angielskim i zostanie przyjęty przez komitet organizacyjny konfe-
Enebo, Václav Pech, Waldemar Kot. W konferencji uczestniczyło rencji.
prawie 400 gości, którzy ocenili wysiłki organizacyjne i poziom Rejestracja na GeeCON właśnie się rozpoczęła! Do końca marca
merytoryczny bardzo wysoko – interesujące prezentacje, świa- obowiązują promocyjne ceny. Po więcej szczegółów zapraszamy
towej sławy prelegenci i niepowtarzalna atmosfera, a wszystko na strony konferencji – www.geecon.org. Organizatorzy gwarantu-
to przy zachowaniu bardzo niskiej opłaty za uczestnictwo. Dzień ją, że będzie to niezapomniane wydarzenie!

82 02/2010

You might also like