
         Ŀ
          Programatorska dokumentacia k hre GRAVITOID 
         

                     Jaroslav Semancik 1998



  ABSTRAKT
 
    Gravitoid je 3D logicko-akcna hra. Ulohou hraca je pomocou
lopticky znicit vsetky tehly v miestnosti. Lopticka podlieha
gravitacii; zmenou smeru posobenia gravitacie je teda mozne
ovladat pohyb lopticky.
    Ak sa ti hra nepaci, nic si z toho nerob, ani ja si nemyslim,
ze by bola extra zabavna.
    Tu najdes nieco o tom, ako je Gravitoid genialne
naprogramovany.



  ! WARNING !
 
    Kedze su prilozene aj zdrojove texty a komentare nie je tazke
si hru upravit. Tuto upravenu verziu vsak uz dalej nerozsiruj
medzi ludi. Okrem ineho by stratila hodnotu tabulka High Scores.



  INCLUDE
 
    Podrobnejsi popis hry je v subore citaj.ma, odporucam ti
precitat si ho pred tym, ako budes citat dalej. Najdes tam
odpovede na otazky, ktore ta uz dlho trapia.

    {$I citaj.ma}, vhodne je aj
    {$I geditman.txt}



  SOURCES
 
    Zdrojove texty hry by mali byt v adresari SOURCES. Su to:

      graph13h.pas
      grav.pas
      gravedit.pas
      int1c.inc
      int1c2.inc
      krysa.pas
      music.inc
      palette.inc
      proc32.asm
      proc32.obj
      scoretab.inc
      smallfnt.inc
      sprites.inc
      vector.pas


            Subory potrebne pre kompilaciu
         HRY                              EDITORA

      graph13h.pas                      graph13.inc
      grav.pas                          gravedit.pas
      int1c.inc                         int1c2.inc
      krysa.pas                         krysa.pas
      music.inc                         palette.inc
      palette.inc                       proc32.obj
      proc32.obj                        smallfnt.inc
      scoretab.inc                      sprites.inc
      smallfnt.inc                      vector.pas
      sprites.inc
      vector.pas
                    primarny subor je
      grav.pas                          gravedit.pas

    Kompilovane boli v Borland Pascal 7.0. Vsetky subory su pri
kompilacii v aktualnom adresari. Nastavenie Options by nemalo
robit problemy, je na zaciatku zdrojoveho textu vo forme direktiv
pre prekladac. Datove subory nutne pre beh programu a ich
umiestnenie su popisane v subore citaj.ma.



  CO JE, KDE JE, O COM JE
 

  graph13h.pas
 
    Subor graph13h.pas je klasicka pascalovska kniznica (unit)
pre grafiku vo VGA mode 13h (rozlisenie 320x200, 256 farieb). Je
to kniznica nahradzujuca unit Graph.
    Zvlada zakladne graficke objekty potrebne v hre (bod, ciara,
vyplneny obdlznik a 4-uholnik), nastavenie a zistenie farby a
palety. Okrem toho umoznuje pracu viacerymi strankami. Aktivna
stranka (do ktorej sa bude kreslit a ktora sa bude zobrazovat) sa
nastavi procedurou SetActivePage13h. Argumentom je segment
stranky (64000 bytov pamate, ktoru vyhradi programator). Stranka
sa bude zobrazovat automaticky, len ak sa nachadza vo viditelnej
casti VRAM pre mod VGA13h (adresy A000h:0000h az A000h:F999h).
Inak treba pouzit proceduru ShowScreen13h, ktora obsah aktivnej
stranky skopiruje do VRAM. Graficky mod VGA13h treba pred
pouzivanim kresliacich procedur nastavit pomocou InitGraph13h,
po ukonceni prace CloseGraph13h obnovuje povodny graficky mod a
paletu.
    Pri spusteni programu kniznica Graph13h zisti ci je v
pocitaci aspon 386 procesor, a ak ano pouziva 32-bitovy prenos
(ShowScreen13h, ClearScreen13h). K tomu je potrebny (aj ked 386
nie je, pretoze obsahuje testovaciu proceduru ChckProcessor)
subor proc32.obj (jeho zdrojak je v proc32.asm), ktory sa
prilinkuje ku kniznici.


  grav.pas
 
    Subor grav.pas je hlavnym a primarnym suborom, ktory sa
kompiluje. Obsahuje jadro hry - datove struktury a klucove
procedury pre 3D grafiku a organizaciu hry. Pretoze je pomerne
rozsiahly, jeho obsah bude popisany neskor a rozdeleny na datove
struktury, algoritmy, formaty suborov, ...
    Snad este moze byt zaujimavy strom kompilacie:

      grav.pas <u> graph13h.pas <l> proc32.obj
                         krysa.pas
                         vector.pas
                 
                 <i> palette.inc
                          smallfnt.inc
      <u> - uses          sprites.inc
      <i> - include       int1c.inc <i> music.inc
      <l> - link          scoretab.inc


  gravedit.pas
 
    Subor gravedit.pas, je len mierne upraveny grav.pas
(neobsahuje menu, ani obsluhu tabulky High Scores; navyse je
vstup miestnosti v textovom formate (vid. geditman.txt) a jej
kompresiu). Je hlavnym a primarnym suborom pre kompilaciu
editora. Viac o nom asi nie je o com (nieco je v geditman.txt a
komentaroch v programe, komprimacia bude popisana neskor), este
strom:

      gravedit.pas <u> graph13h.pas <l> proc32.obj
                             krysa.pas
                             vector.pas
                     
                     <i> palette.inc
      <u> - uses              smallfnt.inc
      <i> - include           sprites.inc
      <l> - link              int1c2.inc


  int1c.inc
 
    V subore int1c.inc su vsetky veci suvisiace s prerusenim
int 1Ch - casovacom. Toto prerusenie sa automaticky vyvolava
18.2-krat za sekundu a nim su casovane vsetky udalosti, ktore
nemaju byt zavisle od rychlosti procesora.
    Pri spusteni programu sa procedurou HookIntr1Ch na obsluhu
prerusenia int 1Ch zavesi procedura Intr1ChHandler, ktora pred
navratom vola povodnu obsluhu, cim sa zachova funkcnost vsetkeho
co uz na casovaci bolo. Pred skoncenim programu sa procedurou
ReleaseIntr1Ch vrati povodna obsluha prerusenia int 1Ch.
    Casovacom riadene (a teda nezavisle od rychlosti procesora)
su: hudba, ovladac mysi, animacie (skakajuce pismenka, oko a
ufo), specialne tehly (blikanie, pohyb, ...) a docasne trvajuce
bonusy.
    Premenne merajuce cas zacinaju znakom _, jednotka casu je
jedna 18.2-tina sekundy. Pri bonusoch znamena nenulovy obsah
casovacej premennej, ze je bonus aktivny. Konkretne ak treba, aby
nieco trvalo napr. 10 sekund, nastavi sa _nieco:=182 a pri kazdom
vyvolani obsluhy casovaca sa _nieco dekrementuje, kym nie je 0.
Sucasne kym je _nieco>0 vykona sa prislusna cinnost.
    Ak sa ma nieco periodicky vykonavat napr. 2-krat za sekundu,
zabezpeci to jeho vykonanie len ak _nieco mod 9 = 0, pricom sa
_nieco pri kazdom volani obsluhy casovaca inkrementuje.
    Vypisovany cas hry, ako aj pohyb lopticky je riadeny s
pomocou funkcie GetTime mimo prerusenia.


  int1c2.inc
 
    Je osekana verzia int1c.inc pre ucely editora. Neobsahuje
riadenie hudby, ufa, ani skakajucich pismeniek.


  krysa.pas
 
    Subor krysa.pas je pascalovska kniznica (unit), pre obsluhu
mysi. Vyuziva prerusenie int 33h, kde by mal byt nainstalovany
driver pre mys.
    Okrem niektorych preddefinovanych tvarov kurzora vo forme
konstant, spristupnuje standardne funkcie pre mys poskytovane
driverom.
    Za pozornost stoji moznost pouzivat 256-farebny kurzor. Toto
vyuziva aj hra Gravitoid. Kurzor sa vtedy nekresli sluzbou
drivera (procedura ShowMouseCursor), ale procedurou
DrawMouseCursor2, ktora vykresli graficky kurzor tvaru gcurtype2
ako klasicky sprite (farba 1, je transparentna) do prave aktivnej
stranky.


  music.inc
 
    V subore music.inc je len procedura PlayMusic, zabezpecujuca
hudbu.
    Ziadana melodia je zapisana ako retazec v premennej mel
(syntax je v komentaroch music.inc). Premenna mel_ ukazuje do
retazca na znak, ktory je zaciatkom zapisu noty nasledujucej po
prave hranej. Hudba sa obsluhuje, ak je music=true, nota sa
fyzicky ozve, ak je navyse soundswitch=true. Na casovanie sa
pouziva premenna _music, ktora obsahuje pocet jednotiek casu,
kolko sa este bude hrat aktualna nota. V kazdom preruseni sa
dekrementuje, ak je 0, zacne sa hrat nasledujuca nota.
Nastavovanie _music, ako aj posuvanie mel_ zabezpecuje
PlayMusic. Po skonceni melodie v mel, zacne hrat od zaciatku.


  palette.inc
 
    V subore palette.inc je 256 farebna paleta zakompilovana
priamo do exe-suboru.
    Prvych 8 farieb je vyhradenych na specialne pouzitie
0 - cierna, 1 - transparent, 2..7 - nevyuzite). Dalsich 24 farieb
je na hviezdy v pozadi (prekvapenie?), a zvysnych 224 je
rozdelenych do 28 osmic - vzdy 8 odtienov jednej farby. Tieto
farby su farbami tehal; odtiene su na tienovanie. Farby 240..255
su okrem toho 16 odtienmi sivej - farby lopticky. Zvysna grafika
v hre (pozadie, ikony a ciary), moze vyuzivat vsetky farby.


  proc32.asm
 
    Subor proc32.asm obsahuje 3 procedury: test typu procesora -
- ChckProcessor a 32-bitove verzie procedur ShowScreen13h,
ClearScreen13h - ShowScreen13h32, ClearScreen13h32. Pouzivaju sa
ak je procesor aspon 386 a su trochu rychlejsie. Prelozeny subor
proc32.obj sa potom prilinkuje k unitu graph13h.pas.


  proc32.obj
 
    Obsahuje rychlejsie 32-bitove verzie procedur ShowScreen13h a
ClearScreen13h z unitu Graph13h a test typu procesora. Prilinkuje
sa k unitu graph13h.pas. Jeho zdrojak je v proc32.asm.


  scoretab.inc
 
    V subore scoretab.inc su procedury pre citanie a zapis do
tabulky High Scores. Tabulka je samozrejme sifrovana a chranena
pred poskodenim a je v (no... bohuzial tam vidno kde je).
    Detailny popis sifrovania nie je z programatorskeho hladiska
zaujimavy a je lahko zneuzitelny, preto si na to musis prist zo
zdrojaku sam. Potom si mozes urobit www-stranku "Gravitoid -
- utajene skutocnosti" alebo "Undocumented features of game
Gravitoid".


  smallfnt.inc
 
    Subor smallfnt.inc obsahuje maly font pouzivany v nazve
miestnosti zakompilovay do exe-suboru. Znaky maju velkost 8x10,
diakritika je v kodovani Kamenickych. Nestandardne znaky (kody
mensie ako 32, ramceky, grecke, ...) nemusia odpovedat
standardnemu kodovaniu Kamenickych.
    Pre nekludne duse: Nepisal som to rucne.


  sprites.inc
 
    V subore sprites.inc su procedury, pre nahratie, kopresiu,
dekompresiu a vykreslovanie spritov. Spritom je lopticka, bonusy,
ikony aj velky font - vsetka bitmapova grafika. Kompresia sa
vyuziva len pri editore a podrobnejsie bude popisana dalej.
Sprity sa vykresluju do aktivnej stranky, teda do segmentu
vramseg. Na vykreslenie spritu je viac procedur, lisiacich sa
orezavanim, pridavanim, relativnej farby, atd. Farba 1 je pouzita
ako transparentna.


  vector.pas
 
    Subor vector.pas, je pascalovska kniznica (unit) pre pracu s
vektormi a maticami. Pre zrychlenie vypoctov nepouziva typ real,
ale single na co potrebuje matematicky koprocesor, alebo jeho
emulaciu.



  VYBRANE DATOVE STRUKTURY A VECI SUVISIACE S
 

    Suradnicove osi maju smer:   Vrcholy miestnosti su cislovane:
                 
               /                            z 
             / z                            /
           /                              32
       (0,0,0)>               /             / 
                   x                01>
                                                       x
                                                    
           y                               
                  obrazovka             7ĳ6
          v                            /             /
                                      45
  Premieta sa do roviny xy.
                                       y
                                      v

    V miestnosti je miesto pre 6*6*6=216 tehal. Ich typ je v poli
bricks[i,j,k] a farby v brickscolors[i,j,k]. Pripustne hodnoty a
ich vyznam je popisany v manuale k editoru (geditman.txt).
Indexovanie je i  z (rastie spredu dozadu), j  y (rastie zhora
nadol) a k  x (rastie zlava doprava).

    V byte bricks[i,j,k] oznacuje najvyssi 7. bit, ci v nej nieco
je (1) alebo je prazdna (0). Ak nie je prazdna ma zmysel aj
6.bit, ktory urcuje, ci je to tehla (1) alebo bonus (0). Ak je to
tehla, 5. bit urcuje, ci po nej zostane bonus (1) alebo nie (0).
4. bit sa pouziva pri posuvani a mnozeni tehal (ktore uz boli
spracovane). Dolne 4 bity urcuju typ tehly 0h..Fh (vid.
geditman.txt).
    V byte brickscolors[i,j,k] je vyuzitych len dolnych 5 bitov,
ktore urcuju farbu tehly a tym sucasne aj bonus, ktory po nej
ostane (ak ostane) (vid geditman.txt).

    V poli transfroomverices[n] su suradnice vrcholov tehal podla
momentalneho natocenia miestnosti. Na toto pole suradnic sa potom
aplikuju transformacne matice. Cislovanie vrcholov je:

                        z 
                        /

                   294295   .  .  .   300
                   /   /                   / 
                 .   .      .  .  .      . 307
               .   .      .  .  .      .   / 
             /   /                   /   .
          4950   .  .  .   55   .     .
         /   /                   /  /       .
       01   .  .  .   6  62     .   .   >
                              /    . .        x
       78   .  .  .   13       . .   
                                .   .   342
                                   .       /
       .   .      .  .  .      .   .     .
       .   .      .  .  .      .       .
       .   .      .  .  .      .    /
                                  97
                              /
      4243   .  .  .   48

        y
       v

    V cykloch pouzivane premenne su i  z, j  y, k  x.
    Suradnice premietnutych vrcholov na obrazovku su v poli
projroomvertices[n]. Normaly a osvetlenie stien je pri kazdej
tehle rovnake, preto sa nepamata pre kazdu osobitne, ale
centralne v planesnormals[plane] a planesshades[plane].
    Diery v stenach su v holes[plane,i,j], cislovane takto:

                     z 
                     /
                   32
                 /  0,0 >      < 0,0   / 
               /0,0 /i  j         j  i  /   
             / j/i                    /    
           01  / j    >
           0,0 >                  0,0       x
                j                          
            i                      i     
            v                       v      
                                           
                                           
                                           
                  7ĳ6
                /                        /
              / /i j                    /
            /0,0  >                 /          i = 0..5
           45            j = 0..5

            y
           v

nieco o tom je aj v geditman.txt.




  VYBRANE A OBDIVUHODNE ALGORITMY
 

  Viditelnost tehal v miestnosti
 
    Pretoze miestnost je velmi specialnym pripadom 3D sceny, bolo
by zbytocnym prepychom pouzivat vseobecne algoritmy. Okrem toho
by bolo treba rozlozit tehly na jednotlive ich steny a zobrazit
miestnost ako velku kopu polygonov v priestore. To by bolo
vyrazne narocnejsie na cas aj na pamat.
    Prva vec, ktoru mozme vyuzit, je ze pri kresleni jednej tehly
problemy s viditelnostou (vzajomnym prekryvanim stien) nie su.
Staci v lubovolnom poradi vykreslit privratene steny a odvratene
nie.
    Kedze tehlu vieme vykreslit bez problemov, staci uz len
vykreslit jednotlive tehly v spravnom poradi. To urobime takto
(budeme pouzivat oznacenie Tehla pre miesto pre tehlu, bez ohladu
na to ci tam tehla skutocne je alebo nie):

  - vyberieme si lubovolnu Tehlu v miestnosti (v programe je to
    konkretne Tehla, v ktorej je lopticka)

  - zistime, ktore steny su viditelne (privratene) a ktore nie

  - Tehly, ktore su v polpriestore ZA niektorou odvratenou stenou
    urcite nemozu prekryvat tuto Tehlu, preto ich mozme (a tie,
    ktore su prekryte touto Tehlou musime) vykreslit skor. Aby
    sa aj tieto tehly vykreslili v spravnom poradi pouzijeme
    rovnaky algoritmus. Rekurzivne sa zavolame pricom vybrana
    Tehla bude ta, ktora je hned za odvratenou stenou tejto
    Tehly, a miestnost, v ktorej je vybrana Tehla bude len ta
    cast terajsej, ktora je v polpriestore za odvratenou stenou
    (zmensia sa teda rozmery miestnosti). Rekurzivne sa vola
    samozrejme len vtedy, ak nie sme na okraji povodnej
    miestnosti.

  - niektore Tehly su vo viacerych polpriestoroch za odvratenou
    stenou Tehly, preto si budeme znacit, ktore Tehly uz su
    vykreslene (konkretne v poli bricksdone[i,j,k])

  - potom ako boli vykreslene vsetky Tehly v odvratenych
    polpriestoroch, mozme vykreslit samotnu vybranu Tehlu (ak tam
    je)

  - tato Tehla urcite nemoze prekryvat tie, ktore su v
    polpriestoroch PRED jej privratenymi stenami. Tieto Tehly
    vykreslime opat tym istym algoritmom, rekurzivnym volanim.
    Rozmery miestnosti sa uz ale zmensovat nebudu, pretoze
    Tehly v privratenych polpriestoroch sa tiez navzajom
    prekryvaju a nemozme si dovolit vykreslit naraz cely jeden
    polpriestor, lebo jeho Tehly mozu prekryvat ine, ktore v nom
    nie su a este sa nevykreslili. Aby sa nezabehlo niekde dozadu
    je zabezpecene tym, ze si pamatame, ktore Tehly uz vykreslene
    su a nekreslime ich dvakrat.

    Este nejake poznamky. Pocas kreslenia miestnosti, treba
vykreslit aj lopticku. Nie je to take jednoduche ako sa zda bude
to popisane v nasledujucej casti.
    Pri kresleni jednej tehly sa nekreslia vsetky jej privratene
steny, ale len tie, ktore nie su zakryte stenou susednej tehly
(ktore teda musi byt odvratena), pretoze ich nebude vidno. Je to
hlavne kvoli problemom s pixelmi na hranici polygonu (steny
susednych tehal na seba celkom nenavazuju a presvita pozadie) a
mozno sa usetri aj trochu casu.
    Kreslenie miestnosti zabezpecuje rekurzivna procedura
DrawBricks, samotne vykreslenie jednej tehly DrawBrick.


  Kreslenie lopticky
 
    Lopticka je kreslena ako sprite. Je to velmi rychle, ale
spaja sa s tym jeden problem - KEDY ju vykreslit. Vhodnym
riesenim vyzera byt, ked ju vykreslime namiesto Tehly, v ktorej
je stred lopticky. Toto riesenie vsak nedava dobre vysledky.
Lopticka sa kresli priblizne vtedy ked sa ma, ale napriklad pri
pohlade spredu a trochu zhora, ak je pod lopticku tehla a
lopticka je posunuta tak, ze jej stred je tesne v Tehle o jedna
vzdialenejsej, sa vykresli lopticka skor (pretoze jej stred je
v polpriestore za tehlou), a pritom ma tehlu prekryvat.
    Pri popise kreslenia tehal je, ze lopticka sa kresli namiesto
Tehly, v ktorej je. Je to trochu nepresna formulacia - lopticka
zasahuje do viacerych Tehal. Dobrym riesenim je vybrat z tych
Tehal najvzdialenejsiu a vykreslit lopticku namiesto tejto Tehly.
Tiez to nekresli 100% spravne ale chyby takmer nevidno. (Tazko
povedat, ci pri takejto kombinacii spritu a 3D, vobec uplne
spravny algoritmus existuje.)
    Zostava este problem, ako urcit najvzdialenejsiu Tehlu, do
ktorej lopticka zasahuje. Bude hladat medzi vsetkymi, do ktorych
zasahuje (v procedure DrawRooom) a hladat najvzdialenejsiu.
Porovnavanie sa robi v procedure FindFarestCube. Spocita sa pocet
viditelych a neviditelnych stien Tehly, v ktorej je stred
lopticky, za ktorymi lezi testovana Tehla a ak je viac
neviditelnych alebo (rovnako neviditelnych a menej viditelnych
stien) ako pre doteraz najdenu najvzdialenejsiu (na zaciatku
0,0), je testovana najvzdialnejsia (jej indexy budu v premennej
bb).


  Odrazanie lopticky
 
    Algoritmus na odrazanie lopticky nie je
fyzikalne podlozeny, ale sprava sa velmi           
realisticky, tak mozno to tak naozaj je               tehla
(ak neuvazujeme rotaciu lopticky).            ^    
    Odrazanie od stien je velmi                 
jednoduche - staci zmenit zlozku            v  / 
vektora kolmu na narazenu stenu                /  ___
na opacnu a mame novy vektor            ___~~~ 
rychlosti. Pri odraze od hran        ~~~ v'
a rohov je to zlozitejsie.                         
    Na obrazku je zjednoduseny                 
model pre odrazanie kruhu v rovine od
pravouhlych rohov. Predpokladajme, ze kruh
sa pohybuje v smere vektora v. Uhol medzi vektorom v a spojnicou
stredu kruhu s narazenenym rohom oznacme . Potom vektor pohybu
po odraze v' najdeme tak, ze v osovo sumerne zobrazime podla
spojnice (resp. od uhla v (v polarnych suradniciach) dvarkrat
odpocitame uhol  (0 je v smere osi x >, rastie v kladnom
smere)) a vezmeme k nemu opacny vektor.
    Preverme niektore hranicne pripady. Ak je uhol  velmi maly
odrazi sa kruh skoro naspat. Ak je 45 odrazi sa v pravom uhle,
ak sa len suchne -  je blizke 90, kruh zmeni svoj smer len
nepatrne. Zda sa to celkom rozumne.
    V priestore sa vektor rozklada na polarne suradnice
(procedurou VSplitToAngles) na uhol VO vodorovnej rovine - fi,
uhol S tou istou rovinou - sigma a dlzku - p. Pri naraze do
zvislej hrany sa pouzije uvedeny algoritmus na vodorovnu rovinu
a zmeni sa fi. Pri naraze do vodorovnej hrany takto zmeni aj fi
aj sigma (staci si to predstavit).
    Moze sa stat, ze lopticka vrazi do dvoch vodorovny hran naraz
potom by sa uhol sigma menil dvakrat a teda by zostal taky ako
bol. Aby sa zmenil len raz je osetrene priznakom crashsigma.
Podobne moze narazit do vodorovnej a zvislej hrany naraz, vtedy
treba zmenit len raz uhol fi. To osetruje priznak crashfihor.
    Vzdy pri pohybe lopticky sa vektor jej rychlosti rozlozi na
uhly, tie sa pripadne zmenia a z nich sa opat vypocitaju
suradnice (p VComputeFromAngles). Pre spravny priebeh je potrebne
aby lopticka skakala po dost malych krokoch (zrejme sa nemoze
pohybovat spojite ako v reale), aby sa spojnica stredu lopticky a
hrany velmi nelisila od idealnej pri spojitom pohybe. Poloha
lopticky sa odlozi vzdy pred jej pohybom a ked sa zisti, ze
narazila (vtedy uz zasahuje DO tehly) obnovi sa ako terajsia
poloha (so zmenenym smerom pohybu).
    Pri naraze do rohu tehly sa tiez tymto postupom zmenia obidva
uhly - fi aj sigma.
    To ci lopticka narazila do nejakej hrany sa zisti najprv z
ktorych stien Tehly, v ktorej ma stred 'vycnieva' (premenna
crashedplanes) a ak su tam spravne dve pre tuto hranu, porovna sa
vzdialenost stredu lopticky s hranou a polomer. Pre rohy tehal
analogicky.
    Okrem tehal sa este testuju hrany stien v stenach a cele je
to skomplikovane kontrolovanim indexov do rozsahu 0..5. Odrazanie
a pohyb lopticky zabezpecuje procedura MoveBall.


  Odrazanie + kreslenie
 
    Odrazanie lopticky by si v lubovolne natocenej miestnosti
vyziadalo velmi narocne vypocty, preto sa pouziva jeden trik.
Lopticky su vlastne dve - jedna sa pohybuje v stojacej miestnosti
a odraza sa (premenna ball). Pred zobrazenim sa jej suradnice
transformuju do priestoru natoceneho tak ako miestnost (do
premennej tranfball) a tieto suradnice sa potom premietaju. Tu sa
mozno hodi jedno vyjasnenie:
    Filozofia hry je taka, ze ak je lopticka v miestnosti, aj ked
sa nicoho nedotyka otaca sa spolu s nou, akoby bol dnu iny
priestor ako von. Ak sa dostane mimo miestnosti (konkretne stred
lopticky) prestane sa s nou otacat a prestane na nu posobit
gravitacia.
    Natocenie priestoru v miestnosti je urcene natocenim troch
bazovych (jednotkovych suradnicovych) vektorov tohoto priestoru
v1x,v1y,v1z. Otacaju sa spolu s miestnostou. Pre zobrazenie
lopticky treba previest suradnice z tohoto natoceneho priestoru
do okoliteho, teda z bazy v1x,v1y,v1z do (1,0,0),(0,1,0),(0,0,1).
Na to sluzi procedura TranformFromBase.


  Najdenie kliknutej steny
 
    Najprv si treba uvedomit, ze pri kliknuti na otacajucu sa
miestnost je na mieste kliknutia prave jedna privratena a prave
jedna odvratena stena, nic viac (ak neuvazujeme nejake pofiderne
klikanie na hrany).
    Testuju sa vsetky steny, ci bolo kliknute vnutri ich priemetu
tymto postupom: Predstavme si vodorovnu ciaru v mieste kliknutia
a sledujme jej priesecniky s hranami premietnutej steny. Dnu bolo
kliknute, len ak je pocet priesecnikov vlavo od kliknutia 1 (pre
vseobecne pre nekonvexny polygon neparne cislo).
    Teda ak lezi jeden vrchol hrany nad a druhy pod touto ciarou
vypocitame suradnice priesecnika a zistime ci vlavo alebo vpravo
od kliknutia. To zopakujeme pre vsetky hrany tejto steny a
spocitame kolko priesecnikov je vlavo.
    Takto spomedzi vsetkych stien vyberieme vyberieme spravne dve
a privratenost/odvratenost zistime podla ich normal.
    Testovanie jednej steny prevadza funkcia InPlane (v int1c.inc)
a jej podfunkcie.


  Generovanie hviezd na pozadi
 
    Hoci sa zda, ze nie je o com, predsa len tu cosi je.
Konkretne urcovanie jasnosti hviezd. Bolo by mozne urobit to
uplne nahodne ale realistickejsi je postup pouzivany pri
generovani kraterov na fraktalnych planetach. Je to pravidlo, ze
pocet n-krat jasnejsich hviezd ako nejaka s jasom j, je n-krat
mensi ako pocet hviezd s jasom j. Teda ak hviezd s jasom 1 je 400
pocet najjasnejsich hviezd s jasom 16 je len 400/16=25 (vsetkych
spolu (jas 1..16) je priblizne 1350).
    Okrem toho sa pre hviezdy s jasom 15 a 16 vybera farba
spomedzi 8 az 31, co su odtiene medzi bielou-zltou, bielou-modrou
a bielou-cervenou.
    Nakoniec sa niekedy niekde umiestnia niektore zo spritov
galaxia, kometa a planeta (v tomto poradi). Vytvorene pozadie
je ako bitamapa na adrese background^.


  Skakajuce pismenka
 
    Su oproti pohybu lopticky fyzikalne velmi jednoduche. Vlavo
(vpravo) sa pohybuju konstantnou rychlostou (introdx), okrem toho
si kazde pismenko pamata svoju vysku (y) a rychlost (dy). Ide o
rovnomerne zrychleny pohyb, rychlost sa vzdy zvysuje o 1, ak
dosiahne maximalnu dovolenu velkost (maxdy), zmeni znamienko -
- pismenko sa odrazi (dalej sa rychlost stale zvysuje o 1, teda
pismenko spomaluje az zastavi a zacne padat). Bolo by logickejsie
zistovat maximalnu vysku a nie rychlost, ale vznikaju pri tom
nepresnosti a vyzera to kostrbatejsie.
    O vsetko sa staraju procedury InitIntro, InitOutro (grav.pas)
a IntroControler, OutroControler (int1c.inc).


  Ufo
 
    Ufo sa zjavuje priemerne raz za 110 sekund. Nahodne sa
vygeneruju 2 miesta tesne za okrajom obrazovky - start a ciel,
spoja sa pomyslenou ciarou a podla nej sa urci vertikalny a
horizontalny krok ufa. O tieto kroky sa potom pohybuje v kazdom
preruseni casovaca (p UfoControler), kym neprileti do ciela.


  Kompresia
 
    Komprimovane su vsetky sprity a miestnosti, pri miestnostiach
kompresia sucasne zabezpecuje necitatelnost suboru.
    Pouzivaju sa dva druhy kompresie - RLE (Run-Length-Encoding)
a LZW (Limpel-Ziv-Welch). Vzdy sa vyskusaju styri moznosti: nic,
RLE, LZW a RLE+LZW (v tomto poradi) a vyberie sa najucinnejsi.
Dosiahnuty kompresny pomer je bezne asi 1/4 (zo 100 bytov na 25).
    Komprimovat je potrebne iba ked sa vytvori nova miestnost.
Dekompresia prebieha vzdy pri nacitani miestnosti z disku a na
zaciatku pri nahrati spritov. Sprity su v pamati ulozene
nekomprimovane, pocas kreslenia by sa dekompresia nestihala.
    Komprimovat sa daju len bloky velke najviac 64KB z pamati do
pamati, ale format suboru (vid. dalej) umoznuje az 4GB bloky.



  FORMATY SUBOROV
 

  Sprite
 
    Jeden sprite ma v pamati tvar:

  dx:word                      - sirka spritu
  dy:word                      - vyska spritu
  bitmap:array[dx*dy] of byte  - bitmapa spritu, po riadkoch
                                 zhora dole, v riadkoch zlava
                                 doprava, kazdy pixel je v jednom
                                 byte

  Komprimovany blok dat
 
    Skomprimovany blok dat o velkosti size sa zapise ako:

  size:doubleword            - pocet bytov neskomprimovaneho
                               bloku dat
  csize:doubleword;          - pocet bytov skomprimovaneho bloku
                               dat
  status:word;               - info o puzitej kompresii
  data:array[csize] of byte  - samotny skomprimovany blok dat

                        status: x x x x x x x x  x x x x x x x x
                                                            
                                                           
                 nevyuzite . . .                             
                                
0/1 ne/pouzita LZW kompresia   
0/1 ne/pouzita RLE kompresia  

    Pretoze kazdy blok ma 10 bytovu hlavicku, bolo by neefektivne
komprimovat kazdy sprite osobitne. Sprity su preto zdruzene do
niekolkych vacsich blokov (lopticka, bonusy, ikony, font).
Subor *.csp (Compressed SPrites) moze pozostavat z lubovolneho
poctu takychto blokov.


  Subor rooms.dat
 
    V subore rooms.dat su ulozene miestnosti. Ich pocet obsahuje
prvy byte suboru, ale aby nebol taky napadny je prexorovany 145.
Kazda miestnost je skomprimovana osobitne, vyssieuvedenym
sposobom. Po dekomprimacii dostaneme blok dat, ktory ma takyto
vyznam:

  title:string[40]                 - nazov miestnosti, ak je
                                     kratsi je doplneny medzerami

  color:byte                       - farba nazvu miestnosti

  x,y,z:integer                    - x,y,z miesta pre tehlu, v
                                     ktorom sa nachadza lopticka
                                     na zaciatku

  r:byte                           - polomer lopticky

  ro:single                        - pruznost lopticky

  g:single                         - gravitacne zrychlenie v
                                     tejto miestnosti

  bricks:array[216] of byte        - info kazdej tehle
                                     (tehla [i,j,k] je na
                                     pozicii i*36+j*6+k)

  brickscolors:array[216] of byte  - farba kazdej tehly

  holes:array[216] of byte         - info o dierach poradi
                                     leftp..farp

    Spolu 704 bytov. Po dekomprimacii sa udaje rozhadzu do
prislusnych premennych.



  FINAL
 
    Tu konci dokumentacia ku Gravitoidu. Vsetko dalej su uz len
dohady co vznikli pocas vekov a ani Mudri nevedia kde je pravda...

    Boli tu popisane niektore zakladne veci o tom ako je hra
naprogramovana a zopar zaujimavych a neobvyklych algoritmov.
Bezne principy 3D grafiky a kompresie sa daju najst v spravnych
knihach alebo na WWW. Ak mas stale nejake otazky, komentare,
nebezpecne nazory alebo nieco podobne mozes napisat na:

  6semancik@st.fmph.uniba.sk, pripadne na
  6semancik@nw.fmph.uniba.sk

    Ale pozor! Aj tu sa uskutocni zrebovanie, tentoraz o nevkusne
ceny, avsak len z tych mailov ktore NEPRIDU. Jedinou otazkou sa
mozes pripravit o moznost vyhry.



 pohov
