h3. Predhovor Jednou zo silných čŕt jazyka Ruby je jeho univerzálnosť. Môžete ho použiť pri tvorbe počítačovej hry, zložitej webovej aplikácie, programu pre robota alebo textového procesora. Nech programujeme čokoľvek, stále používame základné štruktúry Ruby ako napríklad if, while, loop alebo each. Je ale zrejmé, že na písanie rôznych druhov programov treba mať k dispozícii rôzne prostriedky. Keď programujete internetový server, budete používať úplne iné funkcie, než keď programujete hru. A práve na to slúžia pri programovaní knižnice. Knižnice obsahujú funkcie z jednotlivých oblastí a programátor môže použiť tie, ktoré potrebuje. Čo sa programovania grafických aplikácii a hier, z knižníc, ktoré sú open-source, sa najväčšej popularite teší knižnica *SDL*. Je veľmi multiplatformová, takže programy, čo sú v nej vytvorené, fungujú aj na počítačoch, o akých ste v živote nepočuli. Väčšina knižníc, vrátane SDL, sa normálne dá použiť iba v C, C++ a podobných jazykoch. Našťastie existujú tzv. "bindingy", ktoré dokážu funkcie z SDL preniesť do iného jazyka. Tu budeme používať binding, ktorý sa volá *RUDL*. Ten nie len prenáša tie funkcie, ale dáva ich aj do dobre navrhnutých tried a skrášľuje ich použitie. p(advanced). Väčšina programov v SDL používa aj rôzne dodatkové knižnice, ako SDL_image alebo SDL_mixer. Napríklad SDL_mixer pracuje s hudbou a zvukmi. Keď nejaký program hudbu vôbec nevyužíva, jednoducho tú knižnicu nepoužije. V SDL samotnej je len to najnutnejšie minimum, nech programy nie sú zbytočne veľké. Funkcie v RUDL pochádzajú z rôznych dodatkových knižníc, ale RUDL ich spája dohromady tak, nech na to programátor nemusí myslieť. Než prejdeme ku prvému „Hello World“ programu, ešte zostáva jedna drobnosť. Programy v Ruby, ktoré nič nevypisujú, ale miesto toho povedzme zobrazujú grafické okno, sa dávajú do súborov s príponou .rbw, nie .rb. A odporúčam dávať si programy a úlohy z každej lekcie do samostatného adresára, inak v tom čoskoro nastáva chaos. h3. "Hello, World!" Tu je samotný zdrojový kód: require "RUDL" include RUDL include Constant def keypress loop do event = EventQueue.wait exit if event.is_a? QuitEvent break if event.is_a? KeyDownEvent end end $screen = DisplaySurface.new([640,480], DOUBLEBUF|FULLSCREEN, 16) $screen.set_caption "Hello, world!" $screen.fill [255,255,255] $screen.print([100,100], "Hello, world!", [0,0,0]) $screen.flip keypress Tento Ruby program spustíte ako každý iný (v Linuxe príkazom ruby môjprogram.rbw, vo Windowse dvojkliknutím na ikonu súboru). Netreba zadávať žiadne parametre o tom, že sa RUDL používa. Poďme sa na jednotlivé riadky teraz pozrieť trochu podrobnejšie. require "RUDL" Tento riadok načíta celú RUDL, pripraví ju na použitie a obstará všetko okolo toho. include RUDL include Constant Toto zariadi, nech netreba vždy pred každým menom triedy písať RUDL:: (napríklad miesto RUDL::DisplaySurface stačí DisplaySurface) a pred každou konštantou Constant:: (resp. RUDL::Constant::). p(advanced). Princíp je podobný ako 'using namespace' v C++. Namespace (teda v Ruby je to modul) Constant je vnútri modulu RUDL. def keypress loop do event = EventQueue.wait exit if event.is_a? QuitEvent break if event.is_a? KeyDownEvent end end Táto funkcia počká na stlačenie nejakého klávesu. Jej vysvetlenie bude musieť počkať, lebo treba vedieť nejaké veci o tzv. udalostiach v SDL. $screen = DisplaySurface.new([640,480], DOUBLEBUF|FULLSCREEN, 16) A ideme otvoriť nové okno. Funkcia DisplaySurface.new chce tri parametre: veľkosť, nastavenia a farebnú hĺbku. Výsledné nové okno uložím do globálnej premennej $screen. p(advanced). Farebná hĺbka určuje, koľko farieb naraz môže program nakresliť. Keď je to 8, v jednom okamihu môže byť nakreslených 256 rôznych farieb. Keď je to 16, bude ich až 65536. Farebná hĺbka 24 je tá, ktorú používa operačný systém a normálne aplikácie -- vo svojich čo i len trochu serióznych programoch by ste mali používať tú. Ešte existuje farebná hĺbka 32, ktorá podporuje ešte aj priesvitnosť. p(advanced). Nastavenia sa zadávajú ako bitmask, čo znamená, že ich spája |, a že 0 znamená žiadne nastavenia. Zoznam užitočných nastavení je v dodatkoch. Ak nezadáte žiadnu farebnú hĺbku (tretí parameter úplne vynecháte), automaticky sa zvolí nejaká dobrá. DisplaySurface by sa dalo doslova preložiť ako "zobrazovacia plocha". Je to vlastne plocha, na ktorú keď niečo nakreslím, tak sa to zobrazí. (Slovo "plocha" v SDL v podstate znamená "bitmapa" alebo "obrázok".) $screen.set_caption "Hello, world!" Tento riadok nastaví, čo sa zobrazuje v titulku okna. Pri oknách na celej obrazovke to nie je také užitočné, ale môže sa to hodiť pri Alt+Tab apod. $screen.fill [255,255,255] fill vyfarbí celú plochu jednou farbou. V RUDL sa farby zadávajú ako normálne trojprvkové polia [r,g,b]. Dá sa použiť aj hexadecimálny zápis (0xFFFFFF). $screen.print([100,100], "Hello, world!", [0,0,0]) print na dané miesto napíše daný nápis danou farbou. Miesta sa píšu ako dvojprvkové polia [x,y]. Obdĺžniky sa píšu podobne - [x,y,šírka,výška]. (V zadanom mieste bude ľavý horný roh textu.) p(advanced). print je veľmi jednoduchá a základná funkcia určená pre jednoduché aplikácie. Keď napríklad treba použiť iné písmo, ako to štandardné systémové, už treba použiť pokročilejšie metódy, ktorým sa budeme venovať neskôr. $screen.flip Kým na ploche pracujem a kreslím jednotlivé veci, RUDL čaká a neukazuje to v okne. To preto, že by omylom mohla ukázať nedokončenú scénu, kde ešte nie sú všetky veci, a potom to vyzerá, ako keby blikali. Tento riadok hovorí, že už som hotový a môže to, čo som dal do $screen, zobraziť na monitore. Táto finta sa volá double-buffering. keypress Zavolám tú funkciu, čo som si definoval vyššie, nech sa program hneď nezavrie, ale užívateľ si môže pozrieť výsledok. *Úloha č. 1:* Napíšte, pochopte, spustite. *Úloha č. 2:* Skúste miesto DOUBLEBUF|FULLSCREEN dať iba DOUBLEBUF. Čo sa zmenilo? Vyskúšajte farebné hĺbky 8, 24 a 32, a rozlíšenia 320x200, 800x600 a 1024x768. Kedy to funguje a kedy nie? *Úloha č. 3:* Čo sa stane, ak (na celej obrazovke) použijete netradičné rozlíšenie, napr. 500x500? Skúste si najprv tipnúť. *Úloha č. 4:* Skúste zmeniť farby v programe. Upravte program tak, aby vypisoval červený text na žltom pozadí. h3. Presúvanie Keď pochopíte prvú verziu, skúsme teraz urobiť jednu významnú zmenu. Keďže "Hello, World!" je veľmi významná správa celému svetu, chcel by som, aby bola v strede obrazovky, kde ju najlepšie vidno. Najjednoduchšie by bolo urobiť v programe túto úpravu: $screen.print([$screen.w/2,$screen.h/2], "Hello, world!", [0,0,0]) (w a h sú šírka a výška.) Problém s touto verziou je ten, že text sa neumiestni celkom do stredu - print totiž do zadaného miesta dá ľavý horný roh textu, takže ľavý horný roh bude v strede obrazovky. Hlavne je problematická x-ová os, pri tej y-ovej to až tak nevidno. Vyrieši sa to tým, že si vyrátam polovicu šírky textu, a odčítam ju od $screen.w/2, takže polka textu bude v ľavej polovici okna a druhá polka bude vpravo. Písmo, ktoré používa print, je také, že každý znak je veľký 8x8 pixelov, a správa "Hello, world!" má 13 znakov, takže jej šírka na obrazovke bude 104 pixelov. $screen.print([($screen.w/2)-52,$screen.h/2], "Hello, world!", [0,0,0]) p(advanced). Keby bolo treba text často meniť, takéto počítanie dopredu nemusí byť vždy ono. Dá sa to elegantnejšie vyriešiť pomocou funkcie String#length: message = "Hello, world!" $screen.print([($screen.w/2)-(message.length*8/2),$screen.h/2], message, [0,0,0]) *Úloha č. 5:* Napíšte, pochopte, spustite. *Úloha č. 6:* Napíste upravenú verziu, kde sa bude správa vypisovať úplne hore. Napíšte upravenú verziu, kde sa bude správa vypisovať úplne dole. *Špeciálna úloha:* Upravte program tak, aby na čiernom pozadí vypísal žltý text v modrom rámčeku. h3. Dodatky h4. Zoznam nastavení pre DisplaySurface.new SWSURFACE a HWSURFACE určujú, či sa má táto plocha vytvoriť v normálnej (softvérovej) pamäti, alebo v pamäti grafickej karty (hardvérovej). Kreslenie z hardvérovej do hardvérovej pamäti by malo byť rýchlejšie ako zo softvérovej do softvérovej, ale prenos medzi hardvérovou a softvérovou je dosť pomalý. Vo väčšine prípadov sa s takýmito vecami netreba babrať. RESIZABLE vytvorí okno, ktorého veľkosť sa dá meniť. Tomu, ako to rozumne používať, sa budeme venovať neskôr. SDL má vstavaný double-buffering, DOUBLEBUF ho zapne. FULLSCREEN vyrobí okno na celú obrazovku. NOFRAME zariadi, nech to okno nemá rámček. OPENGL zapne v SDL podporu OpenGL.